Dialogs.js 64 KB

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