Dialogs.js 62 KB

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