Dialogs.js 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755
  1. /**
  2. * Copyright (c) 2006-2012, JGraph Ltd
  3. */
  4. /**
  5. * Constructs a new open dialog.
  6. */
  7. var OpenDialog = function()
  8. {
  9. var iframe = document.createElement('iframe');
  10. iframe.style.backgroundColor = 'transparent';
  11. iframe.allowTransparency = 'true';
  12. iframe.style.borderStyle = 'none';
  13. iframe.style.borderWidth = '0px';
  14. iframe.style.overflow = 'hidden';
  15. iframe.style.maxWidth = '100%';
  16. iframe.frameBorder = '0';
  17. var dx = 0;
  18. iframe.setAttribute('width', (((Editor.useLocalStorage) ? 640 : 320) + dx) + 'px');
  19. iframe.setAttribute('height', (((Editor.useLocalStorage) ? 480 : 220) + dx) + 'px');
  20. iframe.setAttribute('src', OPEN_FORM);
  21. this.container = iframe;
  22. };
  23. /**
  24. * Constructs a new color dialog.
  25. */
  26. var ColorDialog = function(editorUi, color, apply, cancelFn)
  27. {
  28. this.editorUi = editorUi;
  29. var input = document.createElement('input');
  30. input.style.marginBottom = '10px';
  31. // Required for picker to render in IE
  32. if (mxClient.IS_IE)
  33. {
  34. input.style.marginTop = '10px';
  35. document.body.appendChild(input);
  36. }
  37. var applyFunction = (apply != null) ? apply : this.createApplyFunction();
  38. function doApply()
  39. {
  40. var color = input.value;
  41. // Blocks any non-alphabetic chars in colors
  42. if (/(^#?[a-zA-Z0-9]*$)/.test(color))
  43. {
  44. if (color != 'none' && color.charAt(0) != '#')
  45. {
  46. color = '#' + color;
  47. }
  48. ColorDialog.addRecentColor((color != 'none') ? color.substring(1) : color, 12);
  49. applyFunction(color);
  50. editorUi.hideDialog();
  51. }
  52. else
  53. {
  54. editorUi.handleError({message: mxResources.get('invalidInput')});
  55. }
  56. };
  57. this.init = function()
  58. {
  59. if (!mxClient.IS_TOUCH)
  60. {
  61. input.focus();
  62. }
  63. };
  64. var picker = new mxJSColor.color(input);
  65. picker.pickerOnfocus = false;
  66. picker.showPicker();
  67. var div = document.createElement('div');
  68. mxJSColor.picker.box.style.position = 'relative';
  69. mxJSColor.picker.box.style.width = '230px';
  70. mxJSColor.picker.box.style.height = '100px';
  71. mxJSColor.picker.box.style.paddingBottom = '10px';
  72. div.appendChild(mxJSColor.picker.box);
  73. var center = document.createElement('center');
  74. function createRecentColorTable()
  75. {
  76. var table = addPresets((ColorDialog.recentColors.length == 0) ? ['FFFFFF'] :
  77. ColorDialog.recentColors, 11, 'FFFFFF', true);
  78. table.style.marginBottom = '8px';
  79. return table;
  80. };
  81. var addPresets = mxUtils.bind(this, function(presets, rowLength, defaultColor, addResetOption)
  82. {
  83. rowLength = (rowLength != null) ? rowLength : 12;
  84. var table = document.createElement('table');
  85. table.style.borderCollapse = 'collapse';
  86. table.setAttribute('cellspacing', '0');
  87. table.style.marginBottom = '20px';
  88. table.style.cellSpacing = '0px';
  89. table.style.marginLeft = '1px';
  90. var tbody = document.createElement('tbody');
  91. table.appendChild(tbody);
  92. var rows = presets.length / rowLength;
  93. for (var row = 0; row < rows; row++)
  94. {
  95. var tr = document.createElement('tr');
  96. for (var i = 0; i < rowLength; i++)
  97. {
  98. (mxUtils.bind(this, function(clr)
  99. {
  100. var td = document.createElement('td');
  101. td.style.border = '0px solid black';
  102. td.style.padding = '0px';
  103. td.style.width = '16px';
  104. td.style.height = '16px';
  105. if (clr == null)
  106. {
  107. clr = defaultColor;
  108. }
  109. if (clr != null)
  110. {
  111. td.style.borderWidth = '1px';
  112. if (clr == 'none')
  113. {
  114. td.style.background = 'url(\'' + Dialog.prototype.noColorImage + '\')';
  115. }
  116. else
  117. {
  118. td.style.backgroundColor = '#' + clr;
  119. }
  120. var name = this.colorNames[clr.toUpperCase()];
  121. if (name != null)
  122. {
  123. td.setAttribute('title', name);
  124. }
  125. }
  126. tr.appendChild(td);
  127. if (clr != null)
  128. {
  129. td.style.cursor = 'pointer';
  130. mxEvent.addListener(td, 'click', function()
  131. {
  132. if (clr == 'none')
  133. {
  134. picker.fromString('ffffff');
  135. input.value = 'none';
  136. }
  137. else
  138. {
  139. picker.fromString(clr);
  140. }
  141. });
  142. mxEvent.addListener(td, 'dblclick', doApply);
  143. }
  144. }))(presets[row * rowLength + i]);
  145. }
  146. tbody.appendChild(tr);
  147. }
  148. if (addResetOption)
  149. {
  150. var td = document.createElement('td');
  151. td.setAttribute('title', mxResources.get('reset'));
  152. td.style.border = '1px solid black';
  153. td.style.padding = '0px';
  154. td.style.width = '16px';
  155. td.style.height = '16px';
  156. td.style.backgroundImage = 'url(\'' + Dialog.prototype.closeImage + '\')';
  157. td.style.backgroundPosition = 'center center';
  158. td.style.backgroundRepeat = 'no-repeat';
  159. td.style.cursor = 'pointer';
  160. tr.appendChild(td);
  161. mxEvent.addListener(td, 'click', function()
  162. {
  163. ColorDialog.resetRecentColors();
  164. table.parentNode.replaceChild(createRecentColorTable(), table);
  165. });
  166. }
  167. center.appendChild(table);
  168. return table;
  169. });
  170. div.appendChild(input);
  171. if (!mxClient.IS_IE && !mxClient.IS_IE11)
  172. {
  173. input.style.width = '182px';
  174. var clrInput = document.createElement('input');
  175. clrInput.setAttribute('type', 'color');
  176. clrInput.style.position = 'relative';
  177. clrInput.style.visibility = 'hidden';
  178. clrInput.style.top = '10px';
  179. clrInput.style.width = '0px';
  180. clrInput.style.height = '0px';
  181. clrInput.style.border = 'none';
  182. div.style.whiteSpace = 'nowrap';
  183. div.appendChild(clrInput);
  184. var dropperBtn = mxUtils.button('', function()
  185. {
  186. // LATER: Check if clrInput is expanded
  187. if (document.activeElement == clrInput)
  188. {
  189. input.focus();
  190. }
  191. else
  192. {
  193. clrInput.value = '#' + input.value;
  194. clrInput.click();
  195. }
  196. });
  197. var dropper = document.createElement('img');
  198. dropper.src = Editor.colorDropperImage;
  199. dropper.className = 'geAdaptiveAsset';
  200. dropper.style.position = 'relative';
  201. dropper.style.verticalAlign = 'middle';
  202. dropper.style.width = 'auto';
  203. dropper.style.height = '14px';
  204. dropperBtn.appendChild(dropper);
  205. div.appendChild(dropperBtn);
  206. mxEvent.addListener(clrInput, 'change', function()
  207. {
  208. picker.fromString(clrInput.value.substring(1));
  209. });
  210. }
  211. else
  212. {
  213. input.style.width = '216px';
  214. }
  215. mxUtils.br(div);
  216. // Adds recent colors
  217. createRecentColorTable();
  218. // Adds presets
  219. var table = addPresets(this.presetColors);
  220. table.style.marginBottom = '8px';
  221. table = addPresets(this.defaultColors);
  222. table.style.marginBottom = '16px';
  223. div.appendChild(center);
  224. var buttons = document.createElement('div');
  225. buttons.style.textAlign = 'right';
  226. buttons.style.whiteSpace = 'nowrap';
  227. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  228. {
  229. editorUi.hideDialog();
  230. if (cancelFn != null)
  231. {
  232. cancelFn();
  233. }
  234. });
  235. cancelBtn.className = 'geBtn';
  236. if (editorUi.editor.cancelFirst)
  237. {
  238. buttons.appendChild(cancelBtn);
  239. }
  240. var applyBtn = mxUtils.button(mxResources.get('apply'), doApply);
  241. applyBtn.className = 'geBtn gePrimaryBtn';
  242. buttons.appendChild(applyBtn);
  243. if (!editorUi.editor.cancelFirst)
  244. {
  245. buttons.appendChild(cancelBtn);
  246. }
  247. if (color != null)
  248. {
  249. if (color == 'none')
  250. {
  251. picker.fromString('ffffff');
  252. input.value = 'none';
  253. }
  254. else
  255. {
  256. picker.fromString(color);
  257. }
  258. }
  259. div.appendChild(buttons);
  260. this.picker = picker;
  261. this.colorInput = input;
  262. // LATER: Only fires if input if focused, should always
  263. // fire if this dialog is showing.
  264. mxEvent.addListener(div, 'keydown', function(e)
  265. {
  266. if (e.keyCode == 27)
  267. {
  268. editorUi.hideDialog();
  269. if (cancelFn != null)
  270. {
  271. cancelFn();
  272. }
  273. mxEvent.consume(e);
  274. }
  275. });
  276. this.container = div;
  277. };
  278. /**
  279. * Creates function to apply value
  280. */
  281. ColorDialog.prototype.presetColors = ['E6D0DE', 'CDA2BE', 'B5739D', 'E1D5E7', 'C3ABD0', 'A680B8', 'D4E1F5', 'A9C4EB', '7EA6E0', 'D5E8D4', '9AC7BF', '67AB9F', 'D5E8D4', 'B9E0A5', '97D077', 'FFF2CC', 'FFE599', 'FFD966', 'FFF4C3', 'FFCE9F', 'FFB570', 'F8CECC', 'F19C99', 'EA6B66'];
  282. /**
  283. * Creates function to apply value
  284. */
  285. ColorDialog.prototype.colorNames = {};
  286. /**
  287. * Creates function to apply value
  288. */
  289. ColorDialog.prototype.defaultColors = ['none', 'FFFFFF', 'E6E6E6', 'CCCCCC', 'B3B3B3', '999999', '808080', '666666', '4D4D4D', '333333', '1A1A1A', '000000', 'FFCCCC', 'FFE6CC', 'FFFFCC', 'E6FFCC', 'CCFFCC', 'CCFFE6', 'CCFFFF', 'CCE5FF', 'CCCCFF', 'E5CCFF', 'FFCCFF', 'FFCCE6',
  290. 'FF9999', 'FFCC99', 'FFFF99', 'CCFF99', '99FF99', '99FFCC', '99FFFF', '99CCFF', '9999FF', 'CC99FF', 'FF99FF', 'FF99CC', 'FF6666', 'FFB366', 'FFFF66', 'B3FF66', '66FF66', '66FFB3', '66FFFF', '66B2FF', '6666FF', 'B266FF', 'FF66FF', 'FF66B3', 'FF3333', 'FF9933', 'FFFF33',
  291. '99FF33', '33FF33', '33FF99', '33FFFF', '3399FF', '3333FF', '9933FF', 'FF33FF', 'FF3399', 'FF0000', 'FF8000', 'FFFF00', '80FF00', '00FF00', '00FF80', '00FFFF', '007FFF', '0000FF', '7F00FF', 'FF00FF', 'FF0080', 'CC0000', 'CC6600', 'CCCC00', '66CC00', '00CC00', '00CC66',
  292. '00CCCC', '0066CC', '0000CC', '6600CC', 'CC00CC', 'CC0066', '990000', '994C00', '999900', '4D9900', '009900', '00994D', '009999', '004C99', '000099', '4C0099', '990099', '99004D', '660000', '663300', '666600', '336600', '006600', '006633', '006666', '003366', '000066',
  293. '330066', '660066', '660033', '330000', '331A00', '333300', '1A3300', '003300', '00331A', '003333', '001933', '000033', '190033', '330033', '33001A'];
  294. /**
  295. * Creates function to apply value
  296. */
  297. ColorDialog.prototype.createApplyFunction = function()
  298. {
  299. return mxUtils.bind(this, function(color)
  300. {
  301. var graph = this.editorUi.editor.graph;
  302. graph.getModel().beginUpdate();
  303. try
  304. {
  305. graph.setCellStyles(this.currentColorKey, color);
  306. this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [this.currentColorKey],
  307. 'values', [color], 'cells', graph.getSelectionCells()));
  308. }
  309. finally
  310. {
  311. graph.getModel().endUpdate();
  312. }
  313. });
  314. };
  315. /**
  316. *
  317. */
  318. ColorDialog.recentColors = [];
  319. /**
  320. * Adds recent color for later use.
  321. */
  322. ColorDialog.addRecentColor = function(color, max)
  323. {
  324. if (color != null)
  325. {
  326. mxUtils.remove(color, ColorDialog.recentColors);
  327. ColorDialog.recentColors.splice(0, 0, color);
  328. if (ColorDialog.recentColors.length >= max)
  329. {
  330. ColorDialog.recentColors.pop();
  331. }
  332. }
  333. };
  334. /**
  335. * Adds recent color for later use.
  336. */
  337. ColorDialog.resetRecentColors = function()
  338. {
  339. ColorDialog.recentColors = [];
  340. };
  341. /**
  342. * Constructs a new about dialog.
  343. */
  344. var AboutDialog = function(editorUi)
  345. {
  346. var div = document.createElement('div');
  347. div.setAttribute('align', 'center');
  348. var h3 = document.createElement('h3');
  349. mxUtils.write(h3, mxResources.get('about') + ' GraphEditor');
  350. div.appendChild(h3);
  351. var img = document.createElement('img');
  352. img.style.border = '0px';
  353. img.setAttribute('width', '176');
  354. img.setAttribute('width', '151');
  355. img.setAttribute('src', IMAGE_PATH + '/logo.png');
  356. div.appendChild(img);
  357. mxUtils.br(div);
  358. mxUtils.write(div, 'Powered by mxGraph ' + mxClient.VERSION);
  359. mxUtils.br(div);
  360. var link = document.createElement('a');
  361. link.setAttribute('href', 'http://www.jgraph.com/');
  362. link.setAttribute('target', '_blank');
  363. mxUtils.write(link, 'www.jgraph.com');
  364. div.appendChild(link);
  365. mxUtils.br(div);
  366. mxUtils.br(div);
  367. var closeBtn = mxUtils.button(mxResources.get('close'), function()
  368. {
  369. editorUi.hideDialog();
  370. });
  371. closeBtn.className = 'geBtn gePrimaryBtn';
  372. div.appendChild(closeBtn);
  373. this.container = div;
  374. };
  375. /**
  376. * Constructs a new textarea dialog.
  377. */
  378. var TextareaDialog = function(editorUi, title, url, fn, cancelFn, cancelTitle, w, h,
  379. addButtons, noHide, noWrap, applyTitle, helpLink, customButtons, header)
  380. {
  381. w = (w != null) ? w : 300;
  382. h = (h != null) ? h : 120;
  383. noHide = (noHide != null) ? noHide : false;
  384. var div = document.createElement('div');
  385. div.style.position = 'absolute';
  386. div.style.top = '20px';
  387. div.style.bottom = '20px';
  388. div.style.left = '20px';
  389. div.style.right = '20px';
  390. var top = document.createElement('div');
  391. top.style.position = 'absolute';
  392. top.style.left = '0px';
  393. top.style.right = '0px';
  394. var main = top.cloneNode(false);
  395. var buttons = top.cloneNode(false);
  396. top.style.top = '0px';
  397. top.style.height = '20px';
  398. main.style.top = '20px';
  399. main.style.bottom = '64px';
  400. buttons.style.bottom = '0px';
  401. buttons.style.height = '60px';
  402. buttons.style.textAlign = 'center';
  403. mxUtils.write(top, title);
  404. div.appendChild(top);
  405. div.appendChild(main);
  406. div.appendChild(buttons);
  407. if (header != null)
  408. {
  409. top.appendChild(header);
  410. }
  411. var nameInput = document.createElement('textarea');
  412. if (noWrap)
  413. {
  414. nameInput.setAttribute('wrap', 'off');
  415. }
  416. nameInput.setAttribute('spellcheck', 'false');
  417. nameInput.setAttribute('autocorrect', 'off');
  418. nameInput.setAttribute('autocomplete', 'off');
  419. nameInput.setAttribute('autocapitalize', 'off');
  420. mxUtils.write(nameInput, url || '');
  421. nameInput.style.resize = 'none';
  422. nameInput.style.outline = 'none';
  423. nameInput.style.position = 'absolute';
  424. nameInput.style.boxSizing = 'border-box';
  425. nameInput.style.top = '0px';
  426. nameInput.style.left = '0px';
  427. nameInput.style.height = '100%';
  428. nameInput.style.width = '100%';
  429. this.textarea = nameInput;
  430. this.init = function()
  431. {
  432. nameInput.focus();
  433. nameInput.scrollTop = 0;
  434. };
  435. main.appendChild(nameInput);
  436. if (helpLink != null)
  437. {
  438. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  439. {
  440. editorUi.editor.graph.openLink(helpLink);
  441. });
  442. helpBtn.className = 'geBtn';
  443. buttons.appendChild(helpBtn);
  444. }
  445. if (customButtons != null)
  446. {
  447. for (var i = 0; i < customButtons.length; i++)
  448. {
  449. (function(label, fn, title)
  450. {
  451. var customBtn = mxUtils.button(label, function(e)
  452. {
  453. fn(e, nameInput);
  454. });
  455. if (title != null)
  456. {
  457. customBtn.setAttribute('title', title);
  458. }
  459. customBtn.className = 'geBtn';
  460. buttons.appendChild(customBtn);
  461. })(customButtons[i][0], customButtons[i][1], customButtons[i][2]);
  462. }
  463. }
  464. var cancelBtn = mxUtils.button(cancelTitle || mxResources.get('cancel'), function()
  465. {
  466. editorUi.hideDialog();
  467. if (cancelFn != null)
  468. {
  469. cancelFn();
  470. }
  471. });
  472. cancelBtn.setAttribute('title', 'Escape');
  473. cancelBtn.className = 'geBtn';
  474. if (editorUi.editor.cancelFirst)
  475. {
  476. buttons.appendChild(cancelBtn);
  477. }
  478. if (addButtons != null)
  479. {
  480. addButtons(buttons, nameInput);
  481. }
  482. if (fn != null)
  483. {
  484. var genericBtn = mxUtils.button(applyTitle || mxResources.get('apply'), function()
  485. {
  486. if (!noHide)
  487. {
  488. editorUi.hideDialog();
  489. }
  490. fn(nameInput.value);
  491. });
  492. genericBtn.setAttribute('title', 'Ctrl+Enter');
  493. genericBtn.className = 'geBtn gePrimaryBtn';
  494. buttons.appendChild(genericBtn);
  495. mxEvent.addListener(nameInput, 'keypress', function(e)
  496. {
  497. if (e.keyCode == 13 && mxEvent.isControlDown(e))
  498. {
  499. genericBtn.click();
  500. }
  501. });
  502. }
  503. if (!editorUi.editor.cancelFirst)
  504. {
  505. buttons.appendChild(cancelBtn);
  506. }
  507. this.container = div;
  508. };
  509. /**
  510. * Constructs a new edit file dialog.
  511. */
  512. var EditDiagramDialog = function(editorUi)
  513. {
  514. var div = document.createElement('div');
  515. div.style.textAlign = 'right';
  516. var textarea = document.createElement('textarea');
  517. textarea.setAttribute('wrap', 'off');
  518. textarea.setAttribute('spellcheck', 'false');
  519. textarea.setAttribute('autocorrect', 'off');
  520. textarea.setAttribute('autocomplete', 'off');
  521. textarea.setAttribute('autocapitalize', 'off');
  522. textarea.style.overflow = 'auto';
  523. textarea.style.resize = 'none';
  524. textarea.style.width = '600px';
  525. textarea.style.height = '360px';
  526. textarea.style.marginBottom = '16px';
  527. textarea.value = mxUtils.getPrettyXml(editorUi.editor.getGraphXml());
  528. div.appendChild(textarea);
  529. this.init = function()
  530. {
  531. textarea.focus();
  532. };
  533. // Enables dropping files
  534. if (Graph.fileSupport)
  535. {
  536. function handleDrop(evt)
  537. {
  538. evt.stopPropagation();
  539. evt.preventDefault();
  540. if (evt.dataTransfer.files.length > 0)
  541. {
  542. var file = evt.dataTransfer.files[0];
  543. var reader = new FileReader();
  544. reader.onload = function(e)
  545. {
  546. textarea.value = e.target.result;
  547. };
  548. reader.readAsText(file);
  549. }
  550. else
  551. {
  552. textarea.value = editorUi.extractGraphModelFromEvent(evt);
  553. }
  554. };
  555. function handleDragOver(evt)
  556. {
  557. evt.stopPropagation();
  558. evt.preventDefault();
  559. };
  560. // Setup the dnd listeners.
  561. textarea.addEventListener('dragover', handleDragOver, false);
  562. textarea.addEventListener('drop', handleDrop, false);
  563. }
  564. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  565. {
  566. editorUi.hideDialog();
  567. });
  568. cancelBtn.className = 'geBtn';
  569. if (editorUi.editor.cancelFirst)
  570. {
  571. div.appendChild(cancelBtn);
  572. }
  573. var select = document.createElement('select');
  574. select.style.width = '180px';
  575. select.className = 'geBtn';
  576. if (editorUi.editor.graph.isEnabled())
  577. {
  578. var replaceOption = document.createElement('option');
  579. replaceOption.setAttribute('value', 'replace');
  580. mxUtils.write(replaceOption, mxResources.get('replaceExistingDrawing'));
  581. select.appendChild(replaceOption);
  582. }
  583. var newOption = document.createElement('option');
  584. newOption.setAttribute('value', 'new');
  585. mxUtils.write(newOption, mxResources.get('openInNewWindow'));
  586. if (EditDiagramDialog.showNewWindowOption)
  587. {
  588. select.appendChild(newOption);
  589. }
  590. if (editorUi.editor.graph.isEnabled())
  591. {
  592. var importOption = document.createElement('option');
  593. importOption.setAttribute('value', 'import');
  594. mxUtils.write(importOption, mxResources.get('addToExistingDrawing'));
  595. select.appendChild(importOption);
  596. }
  597. div.appendChild(select);
  598. var okBtn = mxUtils.button(mxResources.get('ok'), function()
  599. {
  600. // Removes all illegal control characters before parsing
  601. var data = Graph.zapGremlins(mxUtils.trim(textarea.value));
  602. var error = null;
  603. if (select.value == 'new')
  604. {
  605. editorUi.hideDialog();
  606. editorUi.editor.editAsNew(data);
  607. }
  608. else if (select.value == 'replace')
  609. {
  610. editorUi.editor.graph.model.beginUpdate();
  611. try
  612. {
  613. editorUi.editor.setGraphXml(mxUtils.parseXml(data).documentElement);
  614. // LATER: Why is hideDialog between begin-/endUpdate faster?
  615. editorUi.hideDialog();
  616. }
  617. catch (e)
  618. {
  619. error = e;
  620. }
  621. finally
  622. {
  623. editorUi.editor.graph.model.endUpdate();
  624. }
  625. }
  626. else if (select.value == 'import')
  627. {
  628. editorUi.editor.graph.model.beginUpdate();
  629. try
  630. {
  631. var doc = mxUtils.parseXml(data);
  632. var model = new mxGraphModel();
  633. var codec = new mxCodec(doc);
  634. codec.decode(doc.documentElement, model);
  635. var children = model.getChildren(model.getChildAt(model.getRoot(), 0));
  636. editorUi.editor.graph.setSelectionCells(editorUi.editor.graph.importCells(children));
  637. // LATER: Why is hideDialog between begin-/endUpdate faster?
  638. editorUi.hideDialog();
  639. }
  640. catch (e)
  641. {
  642. error = e;
  643. }
  644. finally
  645. {
  646. editorUi.editor.graph.model.endUpdate();
  647. }
  648. }
  649. if (error != null)
  650. {
  651. mxUtils.alert(error.message);
  652. }
  653. });
  654. okBtn.className = 'geBtn gePrimaryBtn';
  655. div.appendChild(okBtn);
  656. if (!editorUi.editor.cancelFirst)
  657. {
  658. div.appendChild(cancelBtn);
  659. }
  660. this.container = div;
  661. };
  662. /**
  663. *
  664. */
  665. EditDiagramDialog.showNewWindowOption = true;
  666. /**
  667. * Constructs a new export dialog.
  668. */
  669. var ExportDialog = function(editorUi)
  670. {
  671. var graph = editorUi.editor.graph;
  672. var bounds = graph.getGraphBounds();
  673. var scale = graph.view.scale;
  674. var width = Math.ceil(bounds.width / scale);
  675. var height = Math.ceil(bounds.height / scale);
  676. var row, td;
  677. var table = document.createElement('table');
  678. var tbody = document.createElement('tbody');
  679. table.setAttribute('cellpadding', (mxClient.IS_SF) ? '0' : '2');
  680. row = document.createElement('tr');
  681. td = document.createElement('td');
  682. td.style.fontSize = '10pt';
  683. td.style.width = '100px';
  684. mxUtils.write(td, mxResources.get('filename') + ':');
  685. row.appendChild(td);
  686. var nameInput = document.createElement('input');
  687. nameInput.setAttribute('value', editorUi.editor.getOrCreateFilename());
  688. nameInput.style.width = '180px';
  689. td = document.createElement('td');
  690. td.appendChild(nameInput);
  691. row.appendChild(td);
  692. tbody.appendChild(row);
  693. row = document.createElement('tr');
  694. td = document.createElement('td');
  695. td.style.fontSize = '10pt';
  696. mxUtils.write(td, mxResources.get('format') + ':');
  697. row.appendChild(td);
  698. var imageFormatSelect = document.createElement('select');
  699. imageFormatSelect.style.width = '180px';
  700. var pngOption = document.createElement('option');
  701. pngOption.setAttribute('value', 'png');
  702. mxUtils.write(pngOption, mxResources.get('formatPng'));
  703. imageFormatSelect.appendChild(pngOption);
  704. var gifOption = document.createElement('option');
  705. if (ExportDialog.showGifOption)
  706. {
  707. gifOption.setAttribute('value', 'gif');
  708. mxUtils.write(gifOption, mxResources.get('formatGif'));
  709. imageFormatSelect.appendChild(gifOption);
  710. }
  711. var jpgOption = document.createElement('option');
  712. jpgOption.setAttribute('value', 'jpg');
  713. mxUtils.write(jpgOption, mxResources.get('formatJpg'));
  714. imageFormatSelect.appendChild(jpgOption);
  715. if (!editorUi.printPdfExport)
  716. {
  717. var pdfOption = document.createElement('option');
  718. pdfOption.setAttribute('value', 'pdf');
  719. mxUtils.write(pdfOption, mxResources.get('formatPdf'));
  720. imageFormatSelect.appendChild(pdfOption);
  721. }
  722. var svgOption = document.createElement('option');
  723. svgOption.setAttribute('value', 'svg');
  724. mxUtils.write(svgOption, mxResources.get('formatSvg'));
  725. imageFormatSelect.appendChild(svgOption);
  726. if (ExportDialog.showXmlOption)
  727. {
  728. var xmlOption = document.createElement('option');
  729. xmlOption.setAttribute('value', 'xml');
  730. mxUtils.write(xmlOption, mxResources.get('formatXml'));
  731. imageFormatSelect.appendChild(xmlOption);
  732. }
  733. td = document.createElement('td');
  734. td.appendChild(imageFormatSelect);
  735. row.appendChild(td);
  736. tbody.appendChild(row);
  737. row = document.createElement('tr');
  738. td = document.createElement('td');
  739. td.style.fontSize = '10pt';
  740. mxUtils.write(td, mxResources.get('zoom') + ' (%):');
  741. row.appendChild(td);
  742. var zoomInput = document.createElement('input');
  743. zoomInput.setAttribute('type', 'number');
  744. zoomInput.setAttribute('value', '100');
  745. zoomInput.style.width = '180px';
  746. td = document.createElement('td');
  747. td.appendChild(zoomInput);
  748. row.appendChild(td);
  749. tbody.appendChild(row);
  750. row = document.createElement('tr');
  751. td = document.createElement('td');
  752. td.style.fontSize = '10pt';
  753. mxUtils.write(td, mxResources.get('width') + ':');
  754. row.appendChild(td);
  755. var widthInput = document.createElement('input');
  756. widthInput.setAttribute('value', width);
  757. widthInput.style.width = '180px';
  758. td = document.createElement('td');
  759. td.appendChild(widthInput);
  760. row.appendChild(td);
  761. tbody.appendChild(row);
  762. row = document.createElement('tr');
  763. td = document.createElement('td');
  764. td.style.fontSize = '10pt';
  765. mxUtils.write(td, mxResources.get('height') + ':');
  766. row.appendChild(td);
  767. var heightInput = document.createElement('input');
  768. heightInput.setAttribute('value', height);
  769. heightInput.style.width = '180px';
  770. td = document.createElement('td');
  771. td.appendChild(heightInput);
  772. row.appendChild(td);
  773. tbody.appendChild(row);
  774. row = document.createElement('tr');
  775. td = document.createElement('td');
  776. td.style.fontSize = '10pt';
  777. mxUtils.write(td, mxResources.get('dpi') + ':');
  778. row.appendChild(td);
  779. var dpiSelect = document.createElement('select');
  780. dpiSelect.style.width = '180px';
  781. var dpi100Option = document.createElement('option');
  782. dpi100Option.setAttribute('value', '100');
  783. mxUtils.write(dpi100Option, '100dpi');
  784. dpiSelect.appendChild(dpi100Option);
  785. var dpi200Option = document.createElement('option');
  786. dpi200Option.setAttribute('value', '200');
  787. mxUtils.write(dpi200Option, '200dpi');
  788. dpiSelect.appendChild(dpi200Option);
  789. var dpi300Option = document.createElement('option');
  790. dpi300Option.setAttribute('value', '300');
  791. mxUtils.write(dpi300Option, '300dpi');
  792. dpiSelect.appendChild(dpi300Option);
  793. var dpi400Option = document.createElement('option');
  794. dpi400Option.setAttribute('value', '400');
  795. mxUtils.write(dpi400Option, '400dpi');
  796. dpiSelect.appendChild(dpi400Option);
  797. var dpiCustOption = document.createElement('option');
  798. dpiCustOption.setAttribute('value', 'custom');
  799. mxUtils.write(dpiCustOption, mxResources.get('custom'));
  800. dpiSelect.appendChild(dpiCustOption);
  801. var customDpi = document.createElement('input');
  802. customDpi.style.width = '180px';
  803. customDpi.style.display = 'none';
  804. customDpi.setAttribute('value', '100');
  805. customDpi.setAttribute('type', 'number');
  806. customDpi.setAttribute('min', '50');
  807. customDpi.setAttribute('step', '50');
  808. var zoomUserChanged = false;
  809. mxEvent.addListener(dpiSelect, 'change', function()
  810. {
  811. if (this.value == 'custom')
  812. {
  813. this.style.display = 'none';
  814. customDpi.style.display = '';
  815. customDpi.focus();
  816. }
  817. else
  818. {
  819. customDpi.value = this.value;
  820. if (!zoomUserChanged)
  821. {
  822. zoomInput.value = this.value;
  823. }
  824. }
  825. });
  826. mxEvent.addListener(customDpi, 'change', function()
  827. {
  828. var dpi = parseInt(customDpi.value);
  829. if (isNaN(dpi) || dpi <= 0)
  830. {
  831. customDpi.style.backgroundColor = 'red';
  832. }
  833. else
  834. {
  835. customDpi.style.backgroundColor = '';
  836. if (!zoomUserChanged)
  837. {
  838. zoomInput.value = dpi;
  839. }
  840. }
  841. });
  842. td = document.createElement('td');
  843. td.appendChild(dpiSelect);
  844. td.appendChild(customDpi);
  845. row.appendChild(td);
  846. tbody.appendChild(row);
  847. row = document.createElement('tr');
  848. td = document.createElement('td');
  849. td.style.fontSize = '10pt';
  850. mxUtils.write(td, mxResources.get('background') + ':');
  851. row.appendChild(td);
  852. var transparentCheckbox = document.createElement('input');
  853. transparentCheckbox.setAttribute('type', 'checkbox');
  854. transparentCheckbox.checked = graph.background == null || graph.background == mxConstants.NONE;
  855. td = document.createElement('td');
  856. td.appendChild(transparentCheckbox);
  857. mxUtils.write(td, mxResources.get('transparent'));
  858. row.appendChild(td);
  859. tbody.appendChild(row);
  860. row = document.createElement('tr');
  861. td = document.createElement('td');
  862. td.style.fontSize = '10pt';
  863. mxUtils.write(td, mxResources.get('grid') + ':');
  864. row.appendChild(td);
  865. var gridCheckbox = document.createElement('input');
  866. gridCheckbox.setAttribute('type', 'checkbox');
  867. gridCheckbox.checked = false;
  868. td = document.createElement('td');
  869. td.appendChild(gridCheckbox);
  870. row.appendChild(td);
  871. tbody.appendChild(row);
  872. row = document.createElement('tr');
  873. td = document.createElement('td');
  874. td.style.fontSize = '10pt';
  875. mxUtils.write(td, mxResources.get('borderWidth') + ':');
  876. row.appendChild(td);
  877. var borderInput = document.createElement('input');
  878. borderInput.setAttribute('type', 'number');
  879. borderInput.setAttribute('value', ExportDialog.lastBorderValue);
  880. borderInput.style.width = '180px';
  881. td = document.createElement('td');
  882. td.appendChild(borderInput);
  883. row.appendChild(td);
  884. tbody.appendChild(row);
  885. table.appendChild(tbody);
  886. // Handles changes in the export format
  887. function formatChanged()
  888. {
  889. var name = nameInput.value;
  890. var dot = name.lastIndexOf('.');
  891. if (dot > 0)
  892. {
  893. nameInput.value = name.substring(0, dot + 1) + imageFormatSelect.value;
  894. }
  895. else
  896. {
  897. nameInput.value = name + '.' + imageFormatSelect.value;
  898. }
  899. if (imageFormatSelect.value === 'xml')
  900. {
  901. zoomInput.setAttribute('disabled', 'true');
  902. widthInput.setAttribute('disabled', 'true');
  903. heightInput.setAttribute('disabled', 'true');
  904. borderInput.setAttribute('disabled', 'true');
  905. }
  906. else
  907. {
  908. zoomInput.removeAttribute('disabled');
  909. widthInput.removeAttribute('disabled');
  910. heightInput.removeAttribute('disabled');
  911. borderInput.removeAttribute('disabled');
  912. }
  913. if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'svg' || imageFormatSelect.value === 'pdf')
  914. {
  915. transparentCheckbox.removeAttribute('disabled');
  916. }
  917. else
  918. {
  919. transparentCheckbox.setAttribute('disabled', 'disabled');
  920. }
  921. if (imageFormatSelect.value === 'png' || imageFormatSelect.value === 'jpg' || imageFormatSelect.value === 'pdf')
  922. {
  923. gridCheckbox.removeAttribute('disabled');
  924. }
  925. else
  926. {
  927. gridCheckbox.setAttribute('disabled', 'disabled');
  928. }
  929. if (imageFormatSelect.value === 'png')
  930. {
  931. dpiSelect.removeAttribute('disabled');
  932. customDpi.removeAttribute('disabled');
  933. }
  934. else
  935. {
  936. dpiSelect.setAttribute('disabled', 'disabled');
  937. customDpi.setAttribute('disabled', 'disabled');
  938. }
  939. };
  940. mxEvent.addListener(imageFormatSelect, 'change', formatChanged);
  941. formatChanged();
  942. function checkValues()
  943. {
  944. if (widthInput.value * heightInput.value > MAX_AREA || widthInput.value <= 0)
  945. {
  946. widthInput.style.backgroundColor = 'red';
  947. }
  948. else
  949. {
  950. widthInput.style.backgroundColor = '';
  951. }
  952. if (widthInput.value * heightInput.value > MAX_AREA || heightInput.value <= 0)
  953. {
  954. heightInput.style.backgroundColor = 'red';
  955. }
  956. else
  957. {
  958. heightInput.style.backgroundColor = '';
  959. }
  960. };
  961. mxEvent.addListener(zoomInput, 'change', function()
  962. {
  963. zoomUserChanged = true;
  964. var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100;
  965. zoomInput.value = parseFloat((s * 100).toFixed(2));
  966. if (width > 0)
  967. {
  968. widthInput.value = Math.floor(width * s);
  969. heightInput.value = Math.floor(height * s);
  970. }
  971. else
  972. {
  973. zoomInput.value = '100';
  974. widthInput.value = width;
  975. heightInput.value = height;
  976. }
  977. checkValues();
  978. });
  979. mxEvent.addListener(widthInput, 'change', function()
  980. {
  981. var s = parseInt(widthInput.value) / width;
  982. if (s > 0)
  983. {
  984. zoomInput.value = parseFloat((s * 100).toFixed(2));
  985. heightInput.value = Math.floor(height * s);
  986. }
  987. else
  988. {
  989. zoomInput.value = '100';
  990. widthInput.value = width;
  991. heightInput.value = height;
  992. }
  993. checkValues();
  994. });
  995. mxEvent.addListener(heightInput, 'change', function()
  996. {
  997. var s = parseInt(heightInput.value) / height;
  998. if (s > 0)
  999. {
  1000. zoomInput.value = parseFloat((s * 100).toFixed(2));
  1001. widthInput.value = Math.floor(width * s);
  1002. }
  1003. else
  1004. {
  1005. zoomInput.value = '100';
  1006. widthInput.value = width;
  1007. heightInput.value = height;
  1008. }
  1009. checkValues();
  1010. });
  1011. row = document.createElement('tr');
  1012. td = document.createElement('td');
  1013. td.setAttribute('align', 'right');
  1014. td.style.paddingTop = '22px';
  1015. td.colSpan = 2;
  1016. var saveBtn = mxUtils.button(mxResources.get('export'), mxUtils.bind(this, function()
  1017. {
  1018. if (parseInt(zoomInput.value) <= 0)
  1019. {
  1020. mxUtils.alert(mxResources.get('drawingEmpty'));
  1021. }
  1022. else
  1023. {
  1024. var name = nameInput.value;
  1025. var format = imageFormatSelect.value;
  1026. var s = Math.max(0, parseFloat(zoomInput.value) || 100) / 100;
  1027. var b = Math.max(0, parseInt(borderInput.value));
  1028. var bg = graph.background;
  1029. var dpi = Math.max(1, parseInt(customDpi.value));
  1030. if ((format == 'svg' || format == 'png' || format == 'pdf') && transparentCheckbox.checked)
  1031. {
  1032. bg = null;
  1033. }
  1034. else if (bg == null || bg == mxConstants.NONE)
  1035. {
  1036. bg = '#ffffff';
  1037. }
  1038. ExportDialog.lastBorderValue = b;
  1039. ExportDialog.exportFile(editorUi, name, format, bg, s, b, dpi, gridCheckbox.checked);
  1040. }
  1041. }));
  1042. saveBtn.className = 'geBtn gePrimaryBtn';
  1043. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1044. {
  1045. editorUi.hideDialog();
  1046. });
  1047. cancelBtn.className = 'geBtn';
  1048. if (editorUi.editor.cancelFirst)
  1049. {
  1050. td.appendChild(cancelBtn);
  1051. td.appendChild(saveBtn);
  1052. }
  1053. else
  1054. {
  1055. td.appendChild(saveBtn);
  1056. td.appendChild(cancelBtn);
  1057. }
  1058. row.appendChild(td);
  1059. tbody.appendChild(row);
  1060. table.appendChild(tbody);
  1061. this.container = table;
  1062. };
  1063. /**
  1064. * Remembers last value for border.
  1065. */
  1066. ExportDialog.lastBorderValue = 0;
  1067. /**
  1068. * Global switches for the export dialog.
  1069. */
  1070. ExportDialog.showGifOption = true;
  1071. /**
  1072. * Global switches for the export dialog.
  1073. */
  1074. ExportDialog.showXmlOption = true;
  1075. /**
  1076. * Hook for getting the export format. Returns null for the default
  1077. * intermediate XML export format or a function that returns the
  1078. * parameter and value to be used in the request in the form
  1079. * key=value, where value should be URL encoded.
  1080. */
  1081. ExportDialog.exportFile = function(editorUi, name, format, bg, s, b, dpi, grid)
  1082. {
  1083. var graph = editorUi.editor.graph;
  1084. if (format == 'xml')
  1085. {
  1086. ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(editorUi.editor.getGraphXml()), name, format);
  1087. }
  1088. else if (format == 'svg')
  1089. {
  1090. ExportDialog.saveLocalFile(editorUi, mxUtils.getXml(graph.getSvg(bg, s, b)), name, format);
  1091. }
  1092. else
  1093. {
  1094. var bounds = graph.getGraphBounds();
  1095. // New image export
  1096. var xmlDoc = mxUtils.createXmlDocument();
  1097. var root = xmlDoc.createElement('output');
  1098. xmlDoc.appendChild(root);
  1099. // Renders graph. Offset will be multiplied with state's scale when painting state.
  1100. var xmlCanvas = new mxXmlCanvas2D(root);
  1101. xmlCanvas.translate(Math.floor((b / s - bounds.x) / graph.view.scale),
  1102. Math.floor((b / s - bounds.y) / graph.view.scale));
  1103. xmlCanvas.scale(s / graph.view.scale);
  1104. var imgExport = new mxImageExport()
  1105. imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
  1106. // Puts request data together
  1107. var param = 'xml=' + encodeURIComponent(mxUtils.getXml(root));
  1108. var w = Math.ceil(bounds.width * s / graph.view.scale + 2 * b);
  1109. var h = Math.ceil(bounds.height * s / graph.view.scale + 2 * b);
  1110. // Requests image if request is valid
  1111. if (param.length <= MAX_REQUEST_SIZE && w * h < MAX_AREA)
  1112. {
  1113. editorUi.hideDialog();
  1114. var req = new mxXmlRequest(EXPORT_URL, 'format=' + format +
  1115. '&filename=' + encodeURIComponent(name) +
  1116. '&bg=' + ((bg != null) ? bg : 'none') +
  1117. '&w=' + w + '&h=' + h + '&' + param +
  1118. '&dpi=' + dpi);
  1119. req.simulate(document, '_blank');
  1120. }
  1121. else
  1122. {
  1123. mxUtils.alert(mxResources.get('drawingTooLarge'));
  1124. }
  1125. }
  1126. };
  1127. /**
  1128. * Hook for getting the export format. Returns null for the default
  1129. * intermediate XML export format or a function that returns the
  1130. * parameter and value to be used in the request in the form
  1131. * key=value, where value should be URL encoded.
  1132. */
  1133. ExportDialog.saveLocalFile = function(editorUi, data, filename, format)
  1134. {
  1135. if (data.length < MAX_REQUEST_SIZE)
  1136. {
  1137. editorUi.hideDialog();
  1138. var req = new mxXmlRequest(SAVE_URL, 'xml=' + encodeURIComponent(data) + '&filename=' +
  1139. encodeURIComponent(filename) + '&format=' + format);
  1140. req.simulate(document, '_blank');
  1141. }
  1142. else
  1143. {
  1144. mxUtils.alert(mxResources.get('drawingTooLarge'));
  1145. mxUtils.popup(xml);
  1146. }
  1147. };
  1148. /**
  1149. * Constructs a new metadata dialog.
  1150. */
  1151. var EditDataDialog = function(ui, cell)
  1152. {
  1153. var div = document.createElement('div');
  1154. var graph = ui.editor.graph;
  1155. var value = graph.getModel().getValue(cell);
  1156. // Converts the value to an XML node
  1157. if (!mxUtils.isNode(value))
  1158. {
  1159. var doc = mxUtils.createXmlDocument();
  1160. var obj = doc.createElement('object');
  1161. obj.setAttribute('label', value || '');
  1162. value = obj;
  1163. }
  1164. var meta = {};
  1165. try
  1166. {
  1167. var temp = mxUtils.getValue(ui.editor.graph.getCurrentCellStyle(cell), 'metaData', null);
  1168. if (temp != null)
  1169. {
  1170. meta = JSON.parse(temp);
  1171. }
  1172. }
  1173. catch (e)
  1174. {
  1175. // ignore
  1176. }
  1177. // Creates the dialog contents
  1178. var form = new mxForm('properties');
  1179. form.table.style.width = '100%';
  1180. var attrs = value.attributes;
  1181. var names = [];
  1182. var texts = [];
  1183. var count = 0;
  1184. var id = (EditDataDialog.getDisplayIdForCell != null) ?
  1185. EditDataDialog.getDisplayIdForCell(ui, cell) : null;
  1186. var addRemoveButton = function(text, name)
  1187. {
  1188. var wrapper = document.createElement('div');
  1189. wrapper.style.position = 'relative';
  1190. wrapper.style.paddingRight = '20px';
  1191. wrapper.style.boxSizing = 'border-box';
  1192. wrapper.style.width = '100%';
  1193. var removeAttr = document.createElement('a');
  1194. var img = mxUtils.createImage(Dialog.prototype.closeImage);
  1195. img.style.height = '9px';
  1196. img.style.fontSize = '9px';
  1197. img.style.marginBottom = (mxClient.IS_IE11) ? '-1px' : '5px';
  1198. removeAttr.className = 'geButton';
  1199. removeAttr.setAttribute('title', mxResources.get('delete'));
  1200. removeAttr.style.position = 'absolute';
  1201. removeAttr.style.top = '4px';
  1202. removeAttr.style.right = '0px';
  1203. removeAttr.style.margin = '0px';
  1204. removeAttr.style.width = '9px';
  1205. removeAttr.style.height = '9px';
  1206. removeAttr.style.cursor = 'pointer';
  1207. removeAttr.appendChild(img);
  1208. var removeAttrFn = (function(name)
  1209. {
  1210. return function()
  1211. {
  1212. var count = 0;
  1213. for (var j = 0; j < names.length; j++)
  1214. {
  1215. if (names[j] == name)
  1216. {
  1217. texts[j] = null;
  1218. form.table.deleteRow(count + ((id != null) ? 1 : 0));
  1219. break;
  1220. }
  1221. if (texts[j] != null)
  1222. {
  1223. count++;
  1224. }
  1225. }
  1226. };
  1227. })(name);
  1228. mxEvent.addListener(removeAttr, 'click', removeAttrFn);
  1229. var parent = text.parentNode;
  1230. wrapper.appendChild(text);
  1231. wrapper.appendChild(removeAttr);
  1232. parent.appendChild(wrapper);
  1233. };
  1234. var addTextArea = function(index, name, value)
  1235. {
  1236. names[index] = name;
  1237. texts[index] = form.addTextarea(names[count] + ':', value, 2);
  1238. texts[index].style.width = '100%';
  1239. if (value.indexOf('\n') > 0)
  1240. {
  1241. texts[index].setAttribute('rows', '2');
  1242. }
  1243. addRemoveButton(texts[index], name);
  1244. if (meta[name] != null && meta[name].editable == false)
  1245. {
  1246. texts[index].setAttribute('disabled', 'disabled');
  1247. }
  1248. };
  1249. var temp = [];
  1250. var isLayer = graph.getModel().getParent(cell) == graph.getModel().getRoot();
  1251. for (var i = 0; i < attrs.length; i++)
  1252. {
  1253. if ((attrs[i].nodeName != 'label' || Graph.translateDiagram ||
  1254. isLayer) && attrs[i].nodeName != 'placeholders')
  1255. {
  1256. temp.push({name: attrs[i].nodeName, value: attrs[i].nodeValue});
  1257. }
  1258. }
  1259. // Sorts by name
  1260. temp.sort(function(a, b)
  1261. {
  1262. if (a.name < b.name)
  1263. {
  1264. return -1;
  1265. }
  1266. else if (a.name > b.name)
  1267. {
  1268. return 1;
  1269. }
  1270. else
  1271. {
  1272. return 0;
  1273. }
  1274. });
  1275. if (id != null)
  1276. {
  1277. var text = document.createElement('div');
  1278. text.style.width = '100%';
  1279. text.style.fontSize = '11px';
  1280. text.style.textAlign = 'center';
  1281. mxUtils.write(text, id);
  1282. var idInput = form.addField(mxResources.get('id') + ':', text);
  1283. mxEvent.addListener(text, 'dblclick', function(evt)
  1284. {
  1285. var dlg = new FilenameDialog(ui, id, mxResources.get('apply'), mxUtils.bind(this, function(value)
  1286. {
  1287. if (value != null && value.length > 0 && value != id)
  1288. {
  1289. if (graph.model.isRoot(cell))
  1290. {
  1291. var page = ui.getPageById(id);
  1292. if (page != null)
  1293. {
  1294. if (ui.getPageById(value) == null)
  1295. {
  1296. var index = ui.getPageIndex(page);
  1297. if (index >= 0)
  1298. {
  1299. ui.removePage(page);
  1300. page.node.setAttribute('id', value);
  1301. id = value;
  1302. idInput.innerHTML = mxUtils.htmlEntities(value);
  1303. ui.insertPage(page, index);
  1304. }
  1305. }
  1306. else
  1307. {
  1308. ui.handleError({message: mxResources.get('alreadyExst', [mxResources.get('page')])});
  1309. }
  1310. }
  1311. }
  1312. else
  1313. {
  1314. if (graph.getModel().getCell(value) == null)
  1315. {
  1316. graph.getModel().cellRemoved(cell);
  1317. cell.setId(value);
  1318. id = value;
  1319. idInput.innerHTML = mxUtils.htmlEntities(value);
  1320. graph.getModel().cellAdded(cell);
  1321. }
  1322. else
  1323. {
  1324. ui.handleError({message: mxResources.get('alreadyExst', [value])});
  1325. }
  1326. }
  1327. }
  1328. }), mxResources.get('id'), null, null, null, null, null, null, 200);
  1329. ui.showDialog(dlg.container, 300, 80, true, true);
  1330. dlg.init();
  1331. });
  1332. }
  1333. for (var i = 0; i < temp.length; i++)
  1334. {
  1335. addTextArea(count, temp[i].name, temp[i].value);
  1336. count++;
  1337. }
  1338. var top = document.createElement('div');
  1339. top.style.position = 'absolute';
  1340. top.style.top = '30px';
  1341. top.style.left = '30px';
  1342. top.style.right = '30px';
  1343. top.style.bottom = '80px';
  1344. top.style.overflowY = 'auto';
  1345. top.appendChild(form.table);
  1346. var newProp = document.createElement('div');
  1347. newProp.style.display = 'flex';
  1348. newProp.style.alignItems = 'center';
  1349. newProp.style.boxSizing = 'border-box';
  1350. newProp.style.paddingRight = '160px';
  1351. newProp.style.whiteSpace = 'nowrap';
  1352. newProp.style.marginTop = '6px';
  1353. newProp.style.width = '100%';
  1354. var nameInput = document.createElement('input');
  1355. nameInput.setAttribute('placeholder', mxResources.get('enterPropertyName'));
  1356. nameInput.setAttribute('type', 'text');
  1357. nameInput.setAttribute('size', (mxClient.IS_IE || mxClient.IS_IE11) ? '36' : '40');
  1358. nameInput.style.boxSizing = 'border-box';
  1359. nameInput.style.borderWidth = '1px';
  1360. nameInput.style.borderStyle = 'solid';
  1361. nameInput.style.marginLeft = '2px';
  1362. nameInput.style.padding = '4px';
  1363. nameInput.style.width = '100%';
  1364. newProp.appendChild(nameInput);
  1365. top.appendChild(newProp);
  1366. div.appendChild(top);
  1367. var addBtn = mxUtils.button(mxResources.get('addProperty'), function()
  1368. {
  1369. var name = nameInput.value;
  1370. // Avoid ':' in attribute names which seems to be valid in Chrome
  1371. if (name.length > 0 && name != 'label' && name != 'id' &&
  1372. name != 'placeholders' && name.indexOf(':') < 0)
  1373. {
  1374. try
  1375. {
  1376. var idx = mxUtils.indexOf(names, name);
  1377. if (idx >= 0 && texts[idx] != null)
  1378. {
  1379. texts[idx].focus();
  1380. }
  1381. else
  1382. {
  1383. // Checks if the name is valid
  1384. var clone = value.cloneNode(false);
  1385. clone.setAttribute(name, '');
  1386. if (idx >= 0)
  1387. {
  1388. names.splice(idx, 1);
  1389. texts.splice(idx, 1);
  1390. }
  1391. names.push(name);
  1392. var text = form.addTextarea(name + ':', '', 2);
  1393. text.style.width = '100%';
  1394. texts.push(text);
  1395. addRemoveButton(text, name);
  1396. text.focus();
  1397. }
  1398. addBtn.setAttribute('disabled', 'disabled');
  1399. nameInput.value = '';
  1400. }
  1401. catch (e)
  1402. {
  1403. mxUtils.alert(e);
  1404. }
  1405. }
  1406. else
  1407. {
  1408. mxUtils.alert(mxResources.get('invalidName'));
  1409. }
  1410. });
  1411. mxEvent.addListener(nameInput, 'keypress', function(e)
  1412. {
  1413. if (e.keyCode == 13 )
  1414. {
  1415. addBtn.click();
  1416. }
  1417. });
  1418. this.init = function()
  1419. {
  1420. if (texts.length > 0)
  1421. {
  1422. texts[0].focus();
  1423. }
  1424. else
  1425. {
  1426. nameInput.focus();
  1427. }
  1428. };
  1429. addBtn.setAttribute('title', mxResources.get('addProperty'));
  1430. addBtn.setAttribute('disabled', 'disabled');
  1431. addBtn.style.textOverflow = 'ellipsis';
  1432. addBtn.style.position = 'absolute';
  1433. addBtn.style.overflow = 'hidden';
  1434. addBtn.style.width = '144px';
  1435. addBtn.style.right = '0px';
  1436. addBtn.className = 'geBtn';
  1437. newProp.appendChild(addBtn);
  1438. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1439. {
  1440. ui.hideDialog.apply(ui, arguments);
  1441. });
  1442. cancelBtn.setAttribute('title', 'Escape');
  1443. cancelBtn.className = 'geBtn';
  1444. var exportBtn = mxUtils.button(mxResources.get('export'), mxUtils.bind(this, function(evt)
  1445. {
  1446. var result = graph.getDataForCells([cell]);
  1447. var dlg = new EmbedDialog(ui, JSON.stringify(result, null, 2), null, null, function()
  1448. {
  1449. console.log(result);
  1450. ui.alert('Written to Console (Dev Tools)');
  1451. }, mxResources.get('export'), null, 'Console', 'data.json');
  1452. ui.showDialog(dlg.container, 450, 240, true, true);
  1453. dlg.init();
  1454. }));
  1455. exportBtn.setAttribute('title', mxResources.get('export'));
  1456. exportBtn.className = 'geBtn';
  1457. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  1458. {
  1459. try
  1460. {
  1461. ui.hideDialog.apply(ui, arguments);
  1462. // Clones and updates the value
  1463. value = value.cloneNode(true);
  1464. var removeLabel = false;
  1465. for (var i = 0; i < names.length; i++)
  1466. {
  1467. if (texts[i] == null)
  1468. {
  1469. value.removeAttribute(names[i]);
  1470. }
  1471. else
  1472. {
  1473. value.setAttribute(names[i], texts[i].value);
  1474. removeLabel = removeLabel || (names[i] == 'placeholder' &&
  1475. value.getAttribute('placeholders') == '1');
  1476. }
  1477. }
  1478. // Removes label if placeholder is assigned
  1479. if (removeLabel)
  1480. {
  1481. value.removeAttribute('label');
  1482. }
  1483. // Updates the value of the cell (undoable)
  1484. graph.getModel().setValue(cell, value);
  1485. }
  1486. catch (e)
  1487. {
  1488. mxUtils.alert(e);
  1489. }
  1490. });
  1491. applyBtn.setAttribute('title', 'Ctrl+Enter');
  1492. applyBtn.className = 'geBtn gePrimaryBtn';
  1493. mxEvent.addListener(div, 'keypress', function(e)
  1494. {
  1495. if (e.keyCode == 13 && mxEvent.isControlDown(e))
  1496. {
  1497. applyBtn.click();
  1498. }
  1499. });
  1500. function updateAddBtn()
  1501. {
  1502. if (nameInput.value.length > 0)
  1503. {
  1504. addBtn.removeAttribute('disabled');
  1505. }
  1506. else
  1507. {
  1508. addBtn.setAttribute('disabled', 'disabled');
  1509. }
  1510. };
  1511. mxEvent.addListener(nameInput, 'keyup', updateAddBtn);
  1512. // Catches all changes that don't fire a keyup (such as paste via mouse)
  1513. mxEvent.addListener(nameInput, 'change', updateAddBtn);
  1514. var buttons = document.createElement('div');
  1515. buttons.style.cssText = 'position:absolute;left:30px;right:30px;text-align:right;bottom:30px;height:40px;'
  1516. if (ui.editor.graph.getModel().isVertex(cell) || ui.editor.graph.getModel().isEdge(cell))
  1517. {
  1518. var replace = document.createElement('span');
  1519. replace.style.marginRight = '10px';
  1520. var input = document.createElement('input');
  1521. input.setAttribute('type', 'checkbox');
  1522. input.style.marginRight = '6px';
  1523. if (value.getAttribute('placeholders') == '1')
  1524. {
  1525. input.setAttribute('checked', 'checked');
  1526. input.defaultChecked = true;
  1527. }
  1528. mxEvent.addListener(input, 'click', function()
  1529. {
  1530. if (value.getAttribute('placeholders') == '1')
  1531. {
  1532. value.removeAttribute('placeholders');
  1533. }
  1534. else
  1535. {
  1536. value.setAttribute('placeholders', '1');
  1537. }
  1538. });
  1539. replace.appendChild(input);
  1540. mxUtils.write(replace, mxResources.get('placeholders'));
  1541. if (EditDataDialog.placeholderHelpLink != null)
  1542. {
  1543. var link = document.createElement('a');
  1544. link.setAttribute('href', EditDataDialog.placeholderHelpLink);
  1545. link.setAttribute('title', mxResources.get('help'));
  1546. link.setAttribute('target', '_blank');
  1547. link.style.marginLeft = '8px';
  1548. link.style.cursor = 'help';
  1549. var icon = document.createElement('img');
  1550. mxUtils.setOpacity(icon, 50);
  1551. icon.style.height = '16px';
  1552. icon.style.width = '16px';
  1553. icon.setAttribute('border', '0');
  1554. icon.setAttribute('valign', 'middle');
  1555. icon.style.marginTop = (mxClient.IS_IE11) ? '0px' : '-4px';
  1556. icon.setAttribute('src', Editor.helpImage);
  1557. link.appendChild(icon);
  1558. replace.appendChild(link);
  1559. }
  1560. buttons.appendChild(replace);
  1561. }
  1562. if (ui.editor.cancelFirst)
  1563. {
  1564. buttons.appendChild(cancelBtn);
  1565. }
  1566. buttons.appendChild(exportBtn);
  1567. buttons.appendChild(applyBtn);
  1568. if (!ui.editor.cancelFirst)
  1569. {
  1570. buttons.appendChild(cancelBtn);
  1571. }
  1572. div.appendChild(buttons);
  1573. this.container = div;
  1574. };
  1575. /**
  1576. * Optional help link.
  1577. */
  1578. EditDataDialog.getDisplayIdForCell = function(ui, cell)
  1579. {
  1580. var id = null;
  1581. if (ui.editor.graph.getModel().getParent(cell) != null)
  1582. {
  1583. id = cell.getId();
  1584. }
  1585. return id;
  1586. };
  1587. /**
  1588. * Optional help link.
  1589. */
  1590. EditDataDialog.placeholderHelpLink = null;
  1591. /**
  1592. * Constructs a new link dialog.
  1593. */
  1594. var LinkDialog = function(editorUi, initialValue, btnLabel, fn)
  1595. {
  1596. var div = document.createElement('div');
  1597. mxUtils.write(div, mxResources.get('editLink') + ':');
  1598. var inner = document.createElement('div');
  1599. inner.className = 'geTitle';
  1600. inner.style.backgroundColor = 'transparent';
  1601. inner.style.borderColor = 'transparent';
  1602. inner.style.whiteSpace = 'nowrap';
  1603. inner.style.textOverflow = 'clip';
  1604. inner.style.cursor = 'default';
  1605. inner.style.paddingRight = '20px';
  1606. var linkInput = document.createElement('input');
  1607. linkInput.setAttribute('value', initialValue);
  1608. linkInput.setAttribute('placeholder', 'http://www.example.com/');
  1609. linkInput.setAttribute('type', 'text');
  1610. linkInput.style.marginTop = '6px';
  1611. linkInput.style.width = '400px';
  1612. linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
  1613. linkInput.style.backgroundRepeat = 'no-repeat';
  1614. linkInput.style.backgroundPosition = '100% 50%';
  1615. linkInput.style.paddingRight = '14px';
  1616. var cross = document.createElement('div');
  1617. cross.setAttribute('title', mxResources.get('reset'));
  1618. cross.style.position = 'relative';
  1619. cross.style.left = '-16px';
  1620. cross.style.width = '12px';
  1621. cross.style.height = '14px';
  1622. cross.style.cursor = 'pointer';
  1623. // Workaround for inline-block not supported in IE
  1624. cross.style.display = 'inline-block';
  1625. cross.style.top = '3px';
  1626. // Needed to block event transparency in IE
  1627. cross.style.background = 'url(' + IMAGE_PATH + '/transparent.gif)';
  1628. mxEvent.addListener(cross, 'click', function()
  1629. {
  1630. linkInput.value = '';
  1631. linkInput.focus();
  1632. });
  1633. inner.appendChild(linkInput);
  1634. inner.appendChild(cross);
  1635. div.appendChild(inner);
  1636. this.init = function()
  1637. {
  1638. linkInput.focus();
  1639. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  1640. {
  1641. linkInput.select();
  1642. }
  1643. else
  1644. {
  1645. document.execCommand('selectAll', false, null);
  1646. }
  1647. };
  1648. var btns = document.createElement('div');
  1649. btns.style.marginTop = '18px';
  1650. btns.style.textAlign = 'right';
  1651. mxEvent.addListener(linkInput, 'keypress', function(e)
  1652. {
  1653. if (e.keyCode == 13)
  1654. {
  1655. editorUi.hideDialog();
  1656. fn(linkInput.value);
  1657. }
  1658. });
  1659. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1660. {
  1661. editorUi.hideDialog();
  1662. });
  1663. cancelBtn.className = 'geBtn';
  1664. if (editorUi.editor.cancelFirst)
  1665. {
  1666. btns.appendChild(cancelBtn);
  1667. }
  1668. var mainBtn = mxUtils.button(btnLabel, function()
  1669. {
  1670. editorUi.hideDialog();
  1671. fn(linkInput.value);
  1672. });
  1673. mainBtn.className = 'geBtn gePrimaryBtn';
  1674. btns.appendChild(mainBtn);
  1675. if (!editorUi.editor.cancelFirst)
  1676. {
  1677. btns.appendChild(cancelBtn);
  1678. }
  1679. div.appendChild(btns);
  1680. this.container = div;
  1681. };
  1682. /**
  1683. *
  1684. */
  1685. var OutlineWindow = function(editorUi, x, y, w, h)
  1686. {
  1687. var graph = editorUi.editor.graph;
  1688. var div = document.createElement('div');
  1689. div.style.position = 'absolute';
  1690. div.style.width = '100%';
  1691. div.style.height = '100%';
  1692. div.style.overflow = 'hidden';
  1693. this.window = new mxWindow(mxResources.get('outline'), div, x, y, w, h, true, true);
  1694. this.window.minimumSize = new mxRectangle(0, 0, 80, 80);
  1695. this.window.destroyOnClose = false;
  1696. this.window.setMaximizable(false);
  1697. this.window.setResizable(true);
  1698. this.window.setClosable(true);
  1699. this.window.setVisible(true);
  1700. var outline = editorUi.createOutline(this.window);
  1701. editorUi.installResizeHandler(this, true, function()
  1702. {
  1703. outline.destroy();
  1704. });
  1705. this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
  1706. {
  1707. this.window.fit();
  1708. outline.setSuspended(false);
  1709. }));
  1710. this.window.addListener(mxEvent.HIDE, mxUtils.bind(this, function()
  1711. {
  1712. outline.setSuspended(true);
  1713. }));
  1714. this.window.addListener(mxEvent.NORMALIZE, mxUtils.bind(this, function()
  1715. {
  1716. outline.setSuspended(false);
  1717. }));
  1718. this.window.addListener(mxEvent.MINIMIZE, mxUtils.bind(this, function()
  1719. {
  1720. outline.setSuspended(true);
  1721. }));
  1722. outline.init(div);
  1723. mxEvent.addMouseWheelListener(function(evt, up)
  1724. {
  1725. var outlineWheel = false;
  1726. var source = mxEvent.getSource(evt);
  1727. while (source != null)
  1728. {
  1729. if (source == outline.svg)
  1730. {
  1731. outlineWheel = true;
  1732. break;
  1733. }
  1734. source = source.parentNode;
  1735. }
  1736. if (outlineWheel)
  1737. {
  1738. var factor = graph.zoomFactor;
  1739. // Slower zoom for pinch gesture on trackpad
  1740. if (evt.deltaY != null && Math.round(evt.deltaY) != evt.deltaY)
  1741. {
  1742. factor = 1 + (Math.abs(evt.deltaY) / 20) * (factor - 1);
  1743. }
  1744. graph.lazyZoom(up, null, null, factor);
  1745. mxEvent.consume(evt);
  1746. }
  1747. });
  1748. };
  1749. /**
  1750. *
  1751. */
  1752. var LayersWindow = function(editorUi, x, y, w, h)
  1753. {
  1754. var graph = editorUi.editor.graph;
  1755. var div = document.createElement('div');
  1756. div.className = 'geBackground';
  1757. div.style.userSelect = 'none';
  1758. div.style.border = '1px solid whiteSmoke';
  1759. div.style.height = '100%';
  1760. div.style.marginBottom = '10px';
  1761. div.style.overflow = 'auto';
  1762. var tbarHeight = (!EditorUi.compactUi) ? '30px' : '26px';
  1763. var listDiv = document.createElement('div')
  1764. listDiv.className = 'geBackground';
  1765. listDiv.style.position = 'absolute';
  1766. listDiv.style.overflow = 'auto';
  1767. listDiv.style.left = '0px';
  1768. listDiv.style.right = '0px';
  1769. listDiv.style.top = '0px';
  1770. listDiv.style.bottom = (parseInt(tbarHeight) + 7) + 'px';
  1771. div.appendChild(listDiv);
  1772. var dragSource = null;
  1773. var dropIndex = null;
  1774. mxEvent.addListener(div, 'dragover', function(evt)
  1775. {
  1776. evt.dataTransfer.dropEffect = 'move';
  1777. dropIndex = 0;
  1778. evt.stopPropagation();
  1779. evt.preventDefault();
  1780. });
  1781. // Workaround for "no element found" error in FF
  1782. mxEvent.addListener(div, 'drop', function(evt)
  1783. {
  1784. evt.stopPropagation();
  1785. evt.preventDefault();
  1786. });
  1787. var layerCount = null;
  1788. var selectionLayer = null;
  1789. var ldiv = document.createElement('div');
  1790. ldiv.className = 'geToolbarContainer';
  1791. ldiv.style.position = 'absolute';
  1792. ldiv.style.bottom = '0px';
  1793. ldiv.style.left = '0px';
  1794. ldiv.style.right = '0px';
  1795. ldiv.style.height = tbarHeight;
  1796. ldiv.style.overflow = 'hidden';
  1797. ldiv.style.padding = (!EditorUi.compactUi) ? '1px' : '4px 0px 3px 0px';
  1798. ldiv.style.borderWidth = '1px 0px 0px 0px';
  1799. ldiv.style.borderStyle = 'solid';
  1800. ldiv.style.display = 'block';
  1801. ldiv.style.whiteSpace = 'nowrap';
  1802. var link = document.createElement('a');
  1803. link.className = 'geButton';
  1804. var removeLink = link.cloneNode(false);
  1805. var img = document.createElement('img');
  1806. img.setAttribute('border', '0');
  1807. img.setAttribute('width', '22');
  1808. img.setAttribute('src', Editor.trashImage);
  1809. img.style.opacity = '0.9';
  1810. if (Editor.isDarkMode())
  1811. {
  1812. img.style.filter = 'invert(100%)';
  1813. }
  1814. removeLink.appendChild(img);
  1815. mxEvent.addListener(removeLink, 'click', function(evt)
  1816. {
  1817. if (graph.isEnabled())
  1818. {
  1819. graph.model.beginUpdate();
  1820. try
  1821. {
  1822. var index = graph.model.root.getIndex(selectionLayer);
  1823. graph.removeCells([selectionLayer], false);
  1824. // Creates default layer if no layer exists
  1825. if (graph.model.getChildCount(graph.model.root) == 0)
  1826. {
  1827. graph.model.add(graph.model.root, new mxCell());
  1828. graph.setDefaultParent(null);
  1829. }
  1830. else if (index > 0 && index <= graph.model.getChildCount(graph.model.root))
  1831. {
  1832. graph.setDefaultParent(graph.model.getChildAt(graph.model.root, index - 1));
  1833. }
  1834. else
  1835. {
  1836. graph.setDefaultParent(null);
  1837. }
  1838. }
  1839. finally
  1840. {
  1841. graph.model.endUpdate();
  1842. }
  1843. }
  1844. mxEvent.consume(evt);
  1845. });
  1846. if (!graph.isEnabled())
  1847. {
  1848. removeLink.className = 'geButton mxDisabled';
  1849. }
  1850. ldiv.appendChild(removeLink);
  1851. var insertLink = link.cloneNode();
  1852. insertLink.setAttribute('title', mxUtils.trim(mxResources.get('moveSelectionTo', ['...'])));
  1853. img = img.cloneNode(false);
  1854. img.setAttribute('src', Editor.verticalDotsImage);
  1855. insertLink.appendChild(img);
  1856. mxEvent.addListener(insertLink, 'click', function(evt)
  1857. {
  1858. if (graph.isEnabled() && !graph.isSelectionEmpty())
  1859. {
  1860. var offset = mxUtils.getOffset(insertLink);
  1861. editorUi.showPopupMenu(mxUtils.bind(this, function(menu, parent)
  1862. {
  1863. for (var i = layerCount - 1; i >= 0; i--)
  1864. {
  1865. (mxUtils.bind(this, function(child)
  1866. {
  1867. var item = menu.addItem(graph.convertValueToString(child) ||
  1868. mxResources.get('background'), null, mxUtils.bind(this, function()
  1869. {
  1870. graph.moveCells(graph.getSelectionCells(), 0, 0, false, child);
  1871. }), parent);
  1872. if (graph.getSelectionCount() == 1 && graph.model.isAncestor(child, graph.getSelectionCell()))
  1873. {
  1874. menu.addCheckmark(item, Editor.checkmarkImage);
  1875. }
  1876. }))(graph.model.getChildAt(graph.model.root, i));
  1877. }
  1878. }), offset.x, offset.y + insertLink.offsetHeight, evt);
  1879. }
  1880. });
  1881. ldiv.appendChild(insertLink);
  1882. var dataLink = link.cloneNode(false);
  1883. dataLink.setAttribute('title', mxResources.get('editData'));
  1884. img = img.cloneNode(false);
  1885. img.setAttribute('src', Editor.editImage);
  1886. dataLink.appendChild(img);
  1887. mxEvent.addListener(dataLink, 'click', function(evt)
  1888. {
  1889. if (graph.isEnabled())
  1890. {
  1891. editorUi.showDataDialog(selectionLayer);
  1892. }
  1893. mxEvent.consume(evt);
  1894. });
  1895. if (!graph.isEnabled())
  1896. {
  1897. dataLink.className = 'geButton mxDisabled';
  1898. }
  1899. ldiv.appendChild(dataLink);
  1900. function renameLayer(layer)
  1901. {
  1902. if (graph.isEnabled() && layer != null)
  1903. {
  1904. var label = graph.convertValueToString(layer);
  1905. var dlg = new FilenameDialog(editorUi, label || mxResources.get('background'),
  1906. mxResources.get('rename'), mxUtils.bind(this, function(newValue)
  1907. {
  1908. if (newValue != null)
  1909. {
  1910. graph.cellLabelChanged(layer, newValue);
  1911. }
  1912. }), mxResources.get('enterName'));
  1913. editorUi.showDialog(dlg.container, 300, 100, true, true);
  1914. dlg.init();
  1915. }
  1916. };
  1917. var duplicateLink = link.cloneNode(false);
  1918. duplicateLink.setAttribute('title', mxResources.get('duplicate'));
  1919. img = img.cloneNode(false);
  1920. img.setAttribute('src', Editor.duplicateImage);
  1921. duplicateLink.appendChild(img);
  1922. mxEvent.addListener(duplicateLink, 'click', function(evt)
  1923. {
  1924. if (graph.isEnabled())
  1925. {
  1926. var newCell = null;
  1927. graph.model.beginUpdate();
  1928. try
  1929. {
  1930. newCell = graph.cloneCell(selectionLayer);
  1931. graph.cellLabelChanged(newCell, mxResources.get('untitledLayer'));
  1932. newCell.setVisible(true);
  1933. newCell = graph.addCell(newCell, graph.model.root);
  1934. graph.setDefaultParent(newCell);
  1935. }
  1936. finally
  1937. {
  1938. graph.model.endUpdate();
  1939. }
  1940. if (newCell != null && !graph.isCellLocked(newCell))
  1941. {
  1942. graph.selectAll(newCell);
  1943. }
  1944. }
  1945. });
  1946. if (!graph.isEnabled())
  1947. {
  1948. duplicateLink.className = 'geButton mxDisabled';
  1949. }
  1950. ldiv.appendChild(duplicateLink);
  1951. var addLink = link.cloneNode(false);
  1952. addLink.setAttribute('title', mxResources.get('addLayer'));
  1953. img = img.cloneNode(false);
  1954. img.setAttribute('src', Editor.addImage);
  1955. addLink.appendChild(img);
  1956. mxEvent.addListener(addLink, 'click', function(evt)
  1957. {
  1958. if (graph.isEnabled())
  1959. {
  1960. graph.model.beginUpdate();
  1961. try
  1962. {
  1963. var cell = graph.addCell(new mxCell(mxResources.get('untitledLayer')), graph.model.root);
  1964. graph.setDefaultParent(cell);
  1965. }
  1966. finally
  1967. {
  1968. graph.model.endUpdate();
  1969. }
  1970. }
  1971. mxEvent.consume(evt);
  1972. });
  1973. if (!graph.isEnabled())
  1974. {
  1975. addLink.className = 'geButton mxDisabled';
  1976. }
  1977. ldiv.appendChild(addLink);
  1978. div.appendChild(ldiv);
  1979. var layerDivs = new mxDictionary();
  1980. var dot = document.createElement('span');
  1981. dot.setAttribute('title', mxResources.get('selectionOnly'));
  1982. dot.innerHTML = '&#8226;';
  1983. dot.style.position = 'absolute';
  1984. dot.style.fontWeight = 'bold';
  1985. dot.style.fontSize = '16pt';
  1986. dot.style.right = '2px';
  1987. dot.style.top = '2px';
  1988. function updateLayerDot()
  1989. {
  1990. var div = layerDivs.get(graph.getLayerForCells(graph.getSelectionCells()));
  1991. if (div != null)
  1992. {
  1993. div.appendChild(dot);
  1994. }
  1995. else if (dot.parentNode != null)
  1996. {
  1997. dot.parentNode.removeChild(dot);
  1998. }
  1999. };
  2000. function refresh()
  2001. {
  2002. layerCount = graph.model.getChildCount(graph.model.root)
  2003. listDiv.innerText = '';
  2004. layerDivs.clear();
  2005. function addLayer(index, label, child, defaultParent)
  2006. {
  2007. var ldiv = document.createElement('div');
  2008. ldiv.className = 'geToolbarContainer';
  2009. layerDivs.put(child, ldiv);
  2010. ldiv.style.overflow = 'hidden';
  2011. ldiv.style.position = 'relative';
  2012. ldiv.style.padding = '4px';
  2013. ldiv.style.height = '22px';
  2014. ldiv.style.display = 'block';
  2015. ldiv.style.backgroundColor = (Editor.isDarkMode()) ?
  2016. Editor.darkColor : 'whiteSmoke';
  2017. ldiv.style.borderWidth = '0px 0px 1px 0px';
  2018. ldiv.style.borderColor = '#c3c3c3';
  2019. ldiv.style.borderStyle = 'solid';
  2020. ldiv.style.whiteSpace = 'nowrap';
  2021. ldiv.setAttribute('title', label);
  2022. var left = document.createElement('div');
  2023. left.style.display = 'inline-block';
  2024. left.style.width = '100%';
  2025. left.style.textOverflow = 'ellipsis';
  2026. left.style.overflow = 'hidden';
  2027. mxEvent.addListener(ldiv, 'dragover', function(evt)
  2028. {
  2029. evt.dataTransfer.dropEffect = 'move';
  2030. dropIndex = index;
  2031. evt.stopPropagation();
  2032. evt.preventDefault();
  2033. });
  2034. mxEvent.addListener(ldiv, 'dragstart', function(evt)
  2035. {
  2036. dragSource = ldiv;
  2037. // Workaround for no DnD on DIV in FF
  2038. if (mxClient.IS_FF)
  2039. {
  2040. // LATER: Check what triggers a parse as XML on this in FF after drop
  2041. evt.dataTransfer.setData('Text', '<layer/>');
  2042. }
  2043. });
  2044. mxEvent.addListener(ldiv, 'dragend', function(evt)
  2045. {
  2046. if (dragSource != null && dropIndex != null)
  2047. {
  2048. graph.addCell(child, graph.model.root, dropIndex);
  2049. }
  2050. dragSource = null;
  2051. dropIndex = null;
  2052. evt.stopPropagation();
  2053. evt.preventDefault();
  2054. });
  2055. var inp = document.createElement('img');
  2056. inp.setAttribute('draggable', 'false');
  2057. inp.setAttribute('align', 'top');
  2058. inp.setAttribute('border', '0');
  2059. inp.style.width = '16px';
  2060. inp.style.padding = '0px 6px 0 4px';
  2061. inp.style.marginTop = '2px';
  2062. inp.style.cursor = 'pointer';
  2063. inp.setAttribute('title', mxResources.get(
  2064. graph.model.isVisible(child) ?
  2065. 'hide' : 'show'));
  2066. if (graph.model.isVisible(child))
  2067. {
  2068. inp.setAttribute('src', Editor.visibleImage);
  2069. mxUtils.setOpacity(ldiv, 75);
  2070. }
  2071. else
  2072. {
  2073. inp.setAttribute('src', Editor.hiddenImage);
  2074. mxUtils.setOpacity(ldiv, 25);
  2075. }
  2076. if (Editor.isDarkMode())
  2077. {
  2078. inp.style.filter = 'invert(100%)';
  2079. }
  2080. left.appendChild(inp);
  2081. mxEvent.addListener(inp, 'click', function(evt)
  2082. {
  2083. graph.model.setVisible(child, !graph.model.isVisible(child));
  2084. mxEvent.consume(evt);
  2085. });
  2086. var btn = document.createElement('img');
  2087. btn.setAttribute('draggable', 'false');
  2088. btn.setAttribute('align', 'top');
  2089. btn.setAttribute('border', '0');
  2090. btn.style.width = '16px';
  2091. btn.style.padding = '0px 6px 0 0';
  2092. btn.style.marginTop = '2px';
  2093. btn.setAttribute('title', mxResources.get('lockUnlock'));
  2094. var style = graph.getCurrentCellStyle(child);
  2095. if (mxUtils.getValue(style, 'locked', '0') == '1')
  2096. {
  2097. btn.setAttribute('src', Editor.lockedImage);
  2098. mxUtils.setOpacity(btn, 75);
  2099. }
  2100. else
  2101. {
  2102. btn.setAttribute('src', Editor.unlockedImage);
  2103. mxUtils.setOpacity(btn, 25);
  2104. }
  2105. if (Editor.isDarkMode())
  2106. {
  2107. btn.style.filter = 'invert(100%)';
  2108. }
  2109. if (graph.isEnabled())
  2110. {
  2111. btn.style.cursor = 'pointer';
  2112. }
  2113. mxEvent.addListener(btn, 'click', function(evt)
  2114. {
  2115. if (graph.isEnabled())
  2116. {
  2117. var value = null;
  2118. graph.getModel().beginUpdate();
  2119. try
  2120. {
  2121. value = (mxUtils.getValue(style, 'locked', '0') == '1') ? null : '1';
  2122. graph.setCellStyles('locked', value, [child]);
  2123. }
  2124. finally
  2125. {
  2126. graph.getModel().endUpdate();
  2127. }
  2128. if (value == '1')
  2129. {
  2130. graph.removeSelectionCells(graph.getModel().getDescendants(child));
  2131. }
  2132. mxEvent.consume(evt);
  2133. }
  2134. });
  2135. left.appendChild(btn);
  2136. var span = document.createElement('span');
  2137. mxUtils.write(span, label);
  2138. span.style.display = 'block';
  2139. span.style.whiteSpace = 'nowrap';
  2140. span.style.overflow = 'hidden';
  2141. span.style.textOverflow = 'ellipsis';
  2142. span.style.position = 'absolute';
  2143. span.style.left = '52px';
  2144. span.style.right = '8px';
  2145. span.style.top = '8px';
  2146. left.appendChild(span);
  2147. ldiv.appendChild(left);
  2148. if (graph.isEnabled())
  2149. {
  2150. // Fallback if no drag and drop is available
  2151. if (mxClient.IS_TOUCH || mxClient.IS_POINTER ||
  2152. (mxClient.IS_IE && document.documentMode < 10))
  2153. {
  2154. var right = document.createElement('div');
  2155. right.style.display = 'block';
  2156. right.style.textAlign = 'right';
  2157. right.style.whiteSpace = 'nowrap';
  2158. right.style.position = 'absolute';
  2159. right.style.right = '16px';
  2160. right.style.top = '6px';
  2161. // Poor man's change layer order
  2162. if (index > 0)
  2163. {
  2164. var img2 = document.createElement('a');
  2165. img2.setAttribute('title', mxResources.get('toBack'));
  2166. img2.className = 'geButton';
  2167. img2.style.cssFloat = 'none';
  2168. img2.innerHTML = '&#9660;';
  2169. img2.style.width = '14px';
  2170. img2.style.height = '14px';
  2171. img2.style.fontSize = '14px';
  2172. img2.style.margin = '0px';
  2173. img2.style.marginTop = '-1px';
  2174. right.appendChild(img2);
  2175. mxEvent.addListener(img2, 'click', function(evt)
  2176. {
  2177. if (graph.isEnabled())
  2178. {
  2179. graph.addCell(child, graph.model.root, index - 1);
  2180. }
  2181. mxEvent.consume(evt);
  2182. });
  2183. }
  2184. if (index >= 0 && index < layerCount - 1)
  2185. {
  2186. var img1 = document.createElement('a');
  2187. img1.setAttribute('title', mxResources.get('toFront'));
  2188. img1.className = 'geButton';
  2189. img1.style.cssFloat = 'none';
  2190. img1.innerHTML = '&#9650;';
  2191. img1.style.width = '14px';
  2192. img1.style.height = '14px';
  2193. img1.style.fontSize = '14px';
  2194. img1.style.margin = '0px';
  2195. img1.style.marginTop = '-1px';
  2196. right.appendChild(img1);
  2197. mxEvent.addListener(img1, 'click', function(evt)
  2198. {
  2199. if (graph.isEnabled())
  2200. {
  2201. graph.addCell(child, graph.model.root, index + 1);
  2202. }
  2203. mxEvent.consume(evt);
  2204. });
  2205. }
  2206. ldiv.appendChild(right);
  2207. }
  2208. if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10))
  2209. {
  2210. ldiv.setAttribute('draggable', 'true');
  2211. ldiv.style.cursor = 'move';
  2212. }
  2213. }
  2214. mxEvent.addListener(ldiv, 'dblclick', function(evt)
  2215. {
  2216. var nodeName = mxEvent.getSource(evt).nodeName;
  2217. if (nodeName != 'INPUT' && nodeName != 'IMG')
  2218. {
  2219. renameLayer(child);
  2220. mxEvent.consume(evt);
  2221. }
  2222. });
  2223. if (graph.getDefaultParent() == child)
  2224. {
  2225. ldiv.style.background = (!Editor.isDarkMode()) ? '#e6eff8' : '#505759';
  2226. ldiv.style.fontWeight = (graph.isEnabled()) ? 'bold' : '';
  2227. selectionLayer = child;
  2228. }
  2229. mxEvent.addListener(ldiv, 'click', function(evt)
  2230. {
  2231. if (graph.isEnabled())
  2232. {
  2233. graph.setDefaultParent(defaultParent);
  2234. graph.view.setCurrentRoot(null);
  2235. if (mxEvent.isShiftDown(evt))
  2236. {
  2237. graph.setSelectionCells(child.children);
  2238. }
  2239. mxEvent.consume(evt);
  2240. }
  2241. });
  2242. listDiv.appendChild(ldiv);
  2243. };
  2244. // Cannot be moved or deleted
  2245. for (var i = layerCount - 1; i >= 0; i--)
  2246. {
  2247. (mxUtils.bind(this, function(child)
  2248. {
  2249. addLayer(i, graph.convertValueToString(child) ||
  2250. mxResources.get('background'), child, child);
  2251. }))(graph.model.getChildAt(graph.model.root, i));
  2252. }
  2253. var label = graph.convertValueToString(selectionLayer) || mxResources.get('background');
  2254. removeLink.setAttribute('title', mxResources.get('removeIt', [label]));
  2255. duplicateLink.setAttribute('title', mxResources.get('duplicateIt', [label]));
  2256. if (graph.isSelectionEmpty())
  2257. {
  2258. insertLink.className = 'geButton mxDisabled';
  2259. }
  2260. updateLayerDot();
  2261. };
  2262. refresh();
  2263. graph.model.addListener(mxEvent.CHANGE, refresh);
  2264. graph.addListener('defaultParentChanged', refresh);
  2265. graph.selectionModel.addListener(mxEvent.CHANGE, function()
  2266. {
  2267. if (graph.isSelectionEmpty())
  2268. {
  2269. insertLink.className = 'geButton mxDisabled';
  2270. }
  2271. else
  2272. {
  2273. insertLink.className = 'geButton';
  2274. }
  2275. updateLayerDot();
  2276. });
  2277. this.window = new mxWindow(mxResources.get('layers'), div, x, y, w, h, true, true);
  2278. this.window.minimumSize = new mxRectangle(0, 0, 150, 120);
  2279. this.window.destroyOnClose = false;
  2280. this.window.setMaximizable(false);
  2281. this.window.setResizable(true);
  2282. this.window.setClosable(true);
  2283. this.window.setVisible(true);
  2284. this.init = function()
  2285. {
  2286. listDiv.scrollTop = listDiv.scrollHeight - listDiv.clientHeight;
  2287. };
  2288. this.window.addListener(mxEvent.SHOW, mxUtils.bind(this, function()
  2289. {
  2290. this.window.fit();
  2291. }));
  2292. // Make refresh available via instance
  2293. this.refreshLayers = refresh;
  2294. editorUi.installResizeHandler(this, true);
  2295. };