Editor.js 85 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704
  1. /**
  2. * Copyright (c) 2006-2012, JGraph Ltd
  3. */
  4. /**
  5. * Editor constructor executed on page load.
  6. */
  7. Editor = function(chromeless, themes, model, graph, editable)
  8. {
  9. mxEventSource.call(this);
  10. this.chromeless = (chromeless != null) ? chromeless : this.chromeless;
  11. this.initStencilRegistry();
  12. this.graph = graph || this.createGraph(themes, model);
  13. this.editable = (editable != null) ? editable : !chromeless;
  14. this.undoManager = this.createUndoManager();
  15. this.status = '';
  16. this.getOrCreateFilename = function()
  17. {
  18. return this.filename || mxResources.get('drawing', [Editor.pageCounter]) + '.xml';
  19. };
  20. this.getFilename = function()
  21. {
  22. return this.filename;
  23. };
  24. // Sets the status and fires a statusChanged event
  25. this.setStatus = function(value)
  26. {
  27. this.status = value;
  28. this.fireEvent(new mxEventObject('statusChanged'));
  29. };
  30. // Returns the current status
  31. this.getStatus = function()
  32. {
  33. return this.status;
  34. };
  35. // Updates modified state if graph changes
  36. this.graphChangeListener = function(sender, eventObject)
  37. {
  38. var edit = (eventObject != null) ? eventObject.getProperty('edit') : null;
  39. if (edit == null || !edit.ignoreEdit)
  40. {
  41. this.setModified(true);
  42. }
  43. };
  44. this.graph.getModel().addListener(mxEvent.CHANGE, mxUtils.bind(this, function()
  45. {
  46. this.graphChangeListener.apply(this, arguments);
  47. }));
  48. // Sets persistent graph state defaults
  49. this.graph.resetViewOnRootChange = false;
  50. this.init();
  51. };
  52. /**
  53. * Counts open editor tabs (must be global for cross-window access)
  54. */
  55. Editor.pageCounter = 0;
  56. // Cross-domain window access is not allowed in FF, so if we
  57. // were opened from another domain then this will fail.
  58. (function()
  59. {
  60. try
  61. {
  62. var op = window;
  63. while (op.opener != null && typeof op.opener.Editor !== 'undefined' &&
  64. !isNaN(op.opener.Editor.pageCounter) &&
  65. // Workaround for possible infinite loop in FF https://drawio.atlassian.net/browse/DS-795
  66. op.opener != op)
  67. {
  68. op = op.opener;
  69. }
  70. // Increments the counter in the first opener in the chain
  71. if (op != null)
  72. {
  73. op.Editor.pageCounter++;
  74. Editor.pageCounter = op.Editor.pageCounter;
  75. }
  76. }
  77. catch (e)
  78. {
  79. // ignore
  80. }
  81. })();
  82. /**
  83. * Specifies if local storage should be used (eg. on the iPad which has no filesystem)
  84. */
  85. Editor.useLocalStorage = typeof(Storage) != 'undefined' && mxClient.IS_IOS;
  86. /**
  87. *
  88. */
  89. Editor.moveImage = (mxClient.IS_SVG) ? 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI4cHgiIGhlaWdodD0iMjhweCI+PGc+PC9nPjxnPjxnPjxnPjxwYXRoIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIuNCwyLjQpc2NhbGUoMC44KXJvdGF0ZSg0NSwxMiwxMikiIHN0cm9rZT0iIzI5YjZmMiIgZmlsbD0iIzI5YjZmMiIgZD0iTTE1LDNsMi4zLDIuM2wtMi44OSwyLjg3bDEuNDIsMS40MkwxOC43LDYuN0wyMSw5VjNIMTV6IE0zLDlsMi4zLTIuM2wyLjg3LDIuODlsMS40Mi0xLjQyTDYuNyw1LjNMOSwzSDNWOXogTTksMjEgbC0yLjMtMi4zbDIuODktMi44N2wtMS40Mi0xLjQyTDUuMywxNy4zTDMsMTV2Nkg5eiBNMjEsMTVsLTIuMywyLjNsLTIuODctMi44OWwtMS40MiwxLjQybDIuODksMi44N0wxNSwyMWg2VjE1eiIvPjwvZz48L2c+PC9nPjwvc3ZnPgo=' :
  90. IMAGE_PATH + '/move.png';
  91. /**
  92. * Images below are for lightbox and embedding toolbars.
  93. */
  94. Editor.helpImage = (mxClient.IS_SVG) ? 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDB6Ii8+PHBhdGggZD0iTTExIDE4aDJ2LTJoLTJ2MnptMS0xNkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTAtMTRjLTIuMjEgMC00IDEuNzktNCA0aDJjMC0xLjEuOS0yIDItMnMyIC45IDIgMmMwIDItMyAxLjc1LTMgNWgyYzAtMi4yNSAzLTIuNSAzLTUgMC0yLjIxLTEuNzktNC00LTR6Ii8+PC9zdmc+' :
  95. IMAGE_PATH + '/help.png';
  96. /**
  97. * Sets the default font size.
  98. */
  99. Editor.checkmarkImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhFQAVAMQfAGxsbHx8fIqKioaGhvb29nJycvr6+sDAwJqamltbW5OTk+np6YGBgeTk5Ly8vJiYmP39/fLy8qWlpa6ursjIyOLi4vj4+N/f3+3t7fT09LCwsHZ2dubm5r6+vmZmZv///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OEY4NTZERTQ5QUFBMTFFMUE5MTVDOTM5MUZGMTE3M0QiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OEY4NTZERTU5QUFBMTFFMUE5MTVDOTM5MUZGMTE3M0QiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Rjg1NkRFMjlBQUExMUUxQTkxNUM5MzkxRkYxMTczRCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Rjg1NkRFMzlBQUExMUUxQTkxNUM5MzkxRkYxMTczRCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAB8ALAAAAAAVABUAAAVI4CeOZGmeaKqubKtylktSgCOLRyLd3+QJEJnh4VHcMoOfYQXQLBcBD4PA6ngGlIInEHEhPOANRkaIFhq8SuHCE1Hb8Lh8LgsBADs=' :
  100. IMAGE_PATH + '/checkmark.gif';
  101. /**
  102. * Images below are for lightbox and embedding toolbars.
  103. */
  104. Editor.maximizeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVBAMAAABbObilAAAAElBMVEUAAAAAAAAAAAAAAAAAAAAAAADgKxmiAAAABXRSTlMA758vX1Pw3BoAAABJSURBVAjXY8AJQkODGBhUQ0MhbAUGBiYY24CBgRnGFmZgMISwgwwDGRhEhVVBbAVmEQYGRwMmBjIAQi/CTIRd6G5AuA3dzYQBAHj0EFdHkvV4AAAAAElFTkSuQmCC';
  105. /**
  106. * Specifies the image URL to be used for the transparent background.
  107. */
  108. Editor.zoomOutImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVBAMAAABbObilAAAAElBMVEUAAAAAAAAsLCxxcXEhISFgYGChjTUxAAAAAXRSTlMAQObYZgAAAEdJREFUCNdjIAMwCQrB2YKCggJQJqMwA7MglK1owMBgqABVApITgLJZXFxgbIQ4Qj3CHIT5ggoIe5kgNkM1KSDYKBKqxPkDAPo5BAZBE54hAAAAAElFTkSuQmCC';
  109. /**
  110. * Specifies the image URL to be used for the transparent background.
  111. */
  112. Editor.zoomInImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVBAMAAABbObilAAAAElBMVEUAAAAAAAAsLCwhISFxcXFgYGBavKaoAAAAAXRSTlMAQObYZgAAAElJREFUCNdjIAMwCQrB2YKCggJQJqMIA4sglK3owMzgqABVwsDMwCgAZTMbG8PYCHGEeoQ5CPMFFRD2MkFshmpSQLBRJFSJ8wcAEqcEM2uhl2MAAAAASUVORK5CYII=';
  113. /**
  114. * Specifies the image URL to be used for the transparent background.
  115. */
  116. Editor.zoomFitImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVBAMAAABbObilAAAAD1BMVEUAAAAAAAAwMDBwcHBgYGC1xl09AAAAAXRSTlMAQObYZgAAAEFJREFUCNdjIAMwCQrB2YKCggJQJqMwA7MglK1owMBgqABVApITwMdGqEeYgzBfUAFhLxPEZqgmBQQbRUKFOH8AAK5OA3lA+FFOAAAAAElFTkSuQmCC';
  117. /**
  118. * Specifies the image URL to be used for the transparent background.
  119. */
  120. Editor.layersImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAMAAACeyVWkAAAAaVBMVEUAAAAgICAICAgdHR0PDw8WFhYICAgLCwsXFxcvLy8ODg4uLi4iIiIqKiokJCQYGBgKCgonJycFBQUCAgIqKiocHBwcHBwODg4eHh4cHBwnJycJCQkUFBQqKiojIyMuLi4ZGRkgICAEBATOWYXAAAAAGnRSTlMAD7+fnz8/H7/ff18/77+vr5+fn39/b28fH2xSoKsAAACQSURBVBjTrYxJEsMgDARZZMAY73sgCcn/HxnhKtnk7j6oRq0psfuoyndZ/SuODkHPLzfVT6KeyPePnJ7KrnkRjWMXTn4SMnN8mXe2SSM3ts8L/ZUxxrbAULSYJJULE0Iw9pjpenoICcgcX61mGgTgtCv9Be99pzCoDhNQWQnchD1mup5++CYGcoQexajZbfwAj/0MD8ZOaUgAAAAASUVORK5CYII=';
  121. /**
  122. * Specifies the image URL to be used for the transparent background.
  123. */
  124. Editor.previousImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAAh0lEQVQ4je3UsQnCUBCA4U8hpa1NsoEjpHQJS0dxADdwEMuMIJkgA1hYChbGQgMi+JC8q4L/AB/vDu7x74cWWEZhJU44RmA1zujR5GIbXF9YNrjD/Q0bDRY4fEBZ4P4LlgTnCbAf84pUM8/9hY08tMUtEoQ1LpEgrNBFglChFXR6Q6GfwwR6AGKJMF74Vtt3AAAAAElFTkSuQmCC';
  125. /**
  126. * Specifies the image URL to be used for the transparent background.
  127. */
  128. Editor.nextImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAAi0lEQVQ4jeXUIQ7CUAwA0MeGxWI2yylwnALJUdBcgYvM7QYLmjOQIAkIPmJZghiIvypoUtX0tfnJL38X5ZfaEgUeUcManFBHgS0SLlhHggk3bCPBhCf2keCQR8wjwYTDp6YiZxJmOU1jGw7vGALescuBxsArNlOwd/CM1VSM/ut1qCIw+uOwiMJ+OF4CQzBCXm3hyAAAAABJRU5ErkJggg==';
  129. /**
  130. * Specifies the image URL to be used for the transparent background.
  131. */
  132. Editor.editImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhCwALAIABAFdXV////yH5BAEAAAEALAAAAAALAAsAAAIZjB8AiKuc4jvLOGqzrjX6zmkWyChXaUJBAQA7' : IMAGE_PATH + '/edit.gif';
  133. /**
  134. * Specifies the image URL to be used for the transparent background.
  135. */
  136. Editor.zoomOutLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAilBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2N2iNAAAALXRSTlMA+vTcKMM96GRBHwXxi0YaX1HLrKWhiHpWEOnOr52Vb2xKSDcT19PKv5l/Ngdk8+viAAABJklEQVQ4y4WT2XaDMAxEvWD2nSSUNEnTJN3r//+9Sj7ILAY6L0ijC4ONYVZRpo6cByrz2YKSUGorGTpz71lPVHvT+avoB5wIkU/mxk8veceSuNoLg44IzziXjvpih72wKQnm8yc2UoiP/LAd8jQfe2Xf4Pq+2EyYIvv9wbzHHCgwxDdlBtWZOdqDfTCVgqpygQpsZaojVAVc9UjQxnAJDIBhiQv84tq3gMQCAVTxVoSibXJf8tMuc7e1TB/DCmejBNg/w1Y3c+AM5vv4w7xM59/oXamrHaLVqPQ+OTCnmMZxgz0SdL5zji0/ld6j88qGa5KIiBB6WeJGKfUKwSMKLuXgvl1TW0tm5R9UQL/efSDYsnzxD8CinhBsTTdugJatKpJwf8v+ADb8QmvW7AeAAAAAAElFTkSuQmCC';
  137. /**
  138. * Specifies the image URL to be used for the transparent background.
  139. */
  140. Editor.zoomInLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAilBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2N2iNAAAALXRSTlMA+vTcKMM96GRBHwXxi0YaX1HLrKWhiHpWEOnOr52Vb2xKSDcT19PKv5l/Ngdk8+viAAABKElEQVQ4y4WT6WKCMBCENwkBwn2oFKvWqr3L+79es4EkQIDOH2d3Pxk2ABiJlB8JCXjqw4LikHVGLHTm3nM3UeVN5690GBBN0GwyV/3kkrUQR+WeKnREeKpzaXWd77CmJiXGfPIEI4V4yQ9TIW/ntlcMBe731Vts9w5TWG8F5j3mQI4hvrKpdGeYA7CX9qAcl650gVJartxRuhyHVghF8idQAIbFLvCLu28BsQEC6aKtCK6Pyb3JT7PmbmtNH8Ny56CotD/2qOs5cJbuffxgXmCib+xddVU5RNOhkvvkhTlFehzVWCOh3++MYElOhfdovaImnRYVmqDdsuhNp1QrBBE6uGC2+3ZNjGdg5B94oD+9uyVgWT79BwAxEBTWdOu3bWBVgsn/N/AHUD9IC01Oe40AAAAASUVORK5CYII=';
  141. /**
  142. * Specifies the image URL to be used for the transparent background.
  143. */
  144. Editor.actualSizeLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAilBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////2N2iNAAAALXRSTlMA+vTcKMM96GRBHwXxi0YaX1HLrKWhiHpWEOnOr52Vb2xKSDcT19PKv5l/Ngdk8+viAAABIUlEQVQ4y4WT2XqDIBCFBxDc9yTWNEnTJN3r+79eGT4BEbXnaubMr8dBBaM450dCQp4LWFAascGIRd48eB4cNYE7f6XjgGiCFs5c+dml6CFN6j1V6IQIlHPpdV/usKcmJcV88gQTRXjLD9Mhb+fWq8YG9/uCmTCFjeeDeY85UGKIUGUuqzN42kv7oCouq9oHamlzVR1lVfpAIu1QVRiW+sAv7r4FpAYIZZVsRXB9TP5Dfpo1d1trCgzz1iiptH/sUbdz4CzN9+mLeXHn3+hdddd4RDegsrvzwZwSs2GLPRJidAqCLTlVwaMPqpYMWjTWBB2WRW86pVkhSKyDK2bdt2tmagZG4sBD/evdLQHLEvQfAOKRoLCmG1FAB6uKmby+gz+REDn7O5+EwQAAAABJRU5ErkJggg==';
  145. /**
  146. * Specifies the image URL to be used for the transparent background.
  147. */
  148. Editor.printLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAXVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9RKvvlAAAAHnRSTlMAydnl77qbMLT093H7K4Nd4Ktn082+lYt5bkklEgP44nQSAAAApUlEQVQ4y73P2Q6DIBRF0cOgbRHHzhP//5m9mBAQKjG1cT0Yc7ITAMu1LNQgUZiQ2DYoNQ0sCQb6qgHAfRx48opq3J9AZ6xuF7uOew8Ik1OsCZRS2UAC9V+D9a+QZYxNA45YFQftPtSkATOhw7dAc0vPBwKWiIOjP0JZ0yMuQJ27g36DipOUsqRAM0dR8KD1/ILHaHSE/w8DIx09E3g/BTce6rHUB5sAPKvfF+JdAAAAAElFTkSuQmCC';
  149. /**
  150. * Specifies the image URL to be used for the transparent background.
  151. */
  152. Editor.layersLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAmVBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+/v7///+bnZkkAAAAMnRSTlMABPr8ByiD88KsTi/rvJb272mjeUA1CuPe1M/KjVxYHxMP6KZ0S9nYzGRGGRaznpGIbzaGUf0AAAHESURBVDjLbZLZYoIwEEVDgLCjbKIgAlqXqt3m/z+uNwu1rcyDhjl3ktnYL7OY254C0VX3yWFZfzDrOClbbgKxi0YDHjwl4jbnRkXxJS/C1YP3DbBhD1n7Ex4uaAqdVDb3yJ/4J/3nJD2to/ngQz/DfUvzMp4JJ5sSCaF5oXmemgQDfDxzbi+Kq4sU+vNcuAmx94JtyOP2DD4Epz2asWSCz4Z/4fECxyNj9zC9xNLHcdPEO+awDKeSaUu0W4twZQiO2hYVisTR3RCtK/c1X6t4xMEpiGqXqVntEBLolkZZsKY4QtwH6jzq67dEHlJysB1aNOD3XT7n1UkasQN59L4yC2RELMDSeCRtz3yV22Ub3ozIUTknYx8JWqDdQxbUes98cR2kZtUSveF/bAhcedwEWmlxIkpZUy4XOCb6VBjjxHvbwo/1lBAHHi2JCr0NI570QhyHq/DhJoE2lLgyA4RVe6KmZ47O/3b86MCP0HWa73A8/C3SUc5Qc1ajt6fgpXJ+RGpMvDSchepZDOOQRcZVIKcK90x2D7etqtI+56+u6n3sPriO6nfphitR4+O2m3EbM7lh3me1FM1o+LMI887rN+s3/wZdTFlpNVJiOAAAAABJRU5ErkJggg==';
  153. /**
  154. * Specifies the image URL to be used for the transparent background.
  155. */
  156. Editor.closeLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAUVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////8IN+deAAAAGnRSTlMAuvAIg/dDM/QlOeuFhj0S5s4vKgzjxJRQNiLSey0AAADNSURBVDjLfZLbEoMgDEQjRRRs1XqX///QNmOHJSnjPkHOGR7IEmeoGtJZstnwjqbRfIsmgEdtPCqe9Ynz7ZSc07rE2QiSc+qv8TvjRXA2PDUm3dpe82iJhOEUfxJJo3aCv+jKmRmH4lcCjCjeh9GWOdL/GZZkXH3PYYDrHBnfc4D/RVZf5sjoC1was+Y6HQxwaUxFvq/a0Pv343VCTxfBSRiB+ab3M3eiQZXmMNBJ3Y8pGRZtYQ7DgHMXJEdPLTaN/qBjzJOBc3nmNcbsA16bMR0oLqf+AAAAAElFTkSuQmCC';
  157. /**
  158. * Specifies the image URL to be used for the transparent background.
  159. */
  160. Editor.editLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAgVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9d3yJTAAAAKnRSTlMA+hzi3nRQWyXzkm0h2j3u54gzEgSXjlYoTBgJxL2loGpAOS3Jt7Wxm35Ga7gRAAAA6UlEQVQ4y63Q2XaCMBSF4Q0JBasoQ5DJqbXjfv8HbCK2BZNwo/8FXHx7rcMC7lQu0iX8qU/qtvAWCpoqH8dYzS0SwaV5eK/UAf8X9pd2CWKzuF5Jrftp1owXwnIGLUaL3PYndOHf4kNNXWrXK/m7CHunk7K8LE6YtBpcknwG9GKxnroY+ylBXcx4xKyx/u/EuXi509cP9V7OO1oyHnzrdFTcqLG/4ibBA5pIMr/4xvKzuQDkVy9wW8SgBFD6HDvuzMvrZcC9QlkfMzI7w64m+b4PqBMNHB05lH21PVxJo2/fBXxV4hB38PcD+5AkI4FuETsAAAAASUVORK5CYII=';
  161. /**
  162. * Specifies the image URL to be used for the transparent background.
  163. */
  164. Editor.previousLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAPFBMVEUAAAD////////////////////////////////////////////////////////////////////////////YSWgTAAAAE3RSTlMA7fci493c0MW8uJ6CZks4MxQHEZL6ewAAAFZJREFUOMvdkskRgDAMA4lDwg2B7b9XOlge/KKvdsa25KFb5XlRvxXC/DNBEv8IFNjBgGdDgXtFgTyhwDXiQAUHCvwa4Uv6mR6UR+1led2mVonvl+tML45qCQNQLIx7AAAAAElFTkSuQmCC';
  165. /**
  166. * Specifies the image URL to be used for the transparent background.
  167. */
  168. Editor.nextLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAPFBMVEUAAAD////////////////////////////////////////////////////////////////////////////YSWgTAAAAE3RSTlMA7fci493c0MW8uJ6CZks4MxQHEZL6ewAAAFRJREFUOMvd0skRgCAQBVEFwQ0V7fxzNQP6wI05v6pZ/kyj1b7FNgik2gQzzLcAwiUAigHOTwDHK4A1CmB5BJANJG1hQ9qafYcqFlZP3IFc9eVGrR+iIgkDQRUXIAAAAABJRU5ErkJggg==';
  169. /**
  170. * Specifies the image to be used for the refresh button.
  171. */
  172. Editor.refreshLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAolBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////8ELnaCAAAANXRSTlMABfyE2QKU+dfNyyDyoVYKwnTv7N+6rntsYlFNQjEqEw316uSzf2c1JB3GvqebiVw6GAjQB4DQr10AAAE7SURBVDjLvZLXcoMwEABPIgRCx3TT3A3udqL//7UgAdGRcR4yk8k+idsdmgS/QyWEqD/axS2JDV33zlnzLHIzQ2MDq9OeJ3m8l76KKENYlxrmM/b65Ys1+8YxnTEZFIEY0vVhszFWfUGZDJpQTDznTgAe5k4XhQxILB7ruzBQn+kkyDXuHfRtjoYDEvH7J9Lz98dBZXXL94X0Ofco2PFlChKbjVzEdakoSlKjoNoqPYkJ/wUZAYwc+PpLj1Ei7+jdoBWlwQZoJv2H1w3CWgRvo7dd9DP5btgwCWz0M02+oVoxCcIWeY9PNmR6B++m9prMxYEISpCBYBlfy9bc745is7UUULAem1Ww7FfalsiA2uaJsgmWP3pQI9q9/yMLkaaHAp2fxhHff/cNq7dBdHXhGW7l+Mo2zU0Cf8knJ2xA0oJ8enwAAAAASUVORK5CYII=';
  173. /**
  174. * Specifies the image to be used for the back button.
  175. */
  176. Editor.backLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAclBMVEUAAAD////////////////+/v7////////////////////////////////////////////+/v7///////////////////////////////////////////////////////////////////////////////8vKLfTAAAAJXRSTlMACh7h9gby3NLIwzwZ55uVJgH57b+8tbCljYV1RRMQ46FrTzQw+vtxOQAAAJ5JREFUOMuF00cWgzAQA1DRDQFCbwFSdf8rZpdVrNH2z3tuMv7mldZQ2WN2yi8x+TT8JvyTkqvwpiKvwsOIrA1fWr+XGTklfj8dOQR+D3KyUF6QufBkJN0hfCazEv6sZBRCJDUcPasGKpu1RLtYE8lkHAPBQLoTsK/SfAyRw5FjAuhCzC2MSj0gJ+66lHatgXdKboD9tfREB5m9/+3iC9jHDYvsGNcUAAAAAElFTkSuQmCC';
  177. /**
  178. * Specifies the image to be used for the back button.
  179. */
  180. Editor.fullscreenLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAllBMVEUAAAD////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AJcWoAAAAMXRSTlMA+wIFxPWPCIb446tnUxmsoIykgxTe29jQnpKBe2MNsZhVTR/KyLuWbFhEPjUq7L9z+bQj+gAAAWxJREFUOMttk4l2gkAMRTODCO4FtQgIbnWpS9v8/881iZFh8R51NO8GJ+gAjMN8zuTRFSw04cIOHQcqFHH6oaQFGxf0jeBjEgB8Y52TpW9Ag4zB5QICWOtHrgwGuFZBcw+gPP0MFS7+iiD5inOmDIQS9sZgTwUzwEzyxhxHVEEU7NdDUXsqUPtqjIgR2IZSCT4upzSeIeOdcMHnfDsx3giPoezfU6MrQGB5//SckLEG2xYscK4GfnUFqaix39zrwooaOD/cXoYuvHKQIc7pzd3HVPusp6t2FAW/RmjMonbl8vwHDeZo/GkleJC7e+p5XA/rAq1X/V10wKag04rBpa2/d0LL4OYYceOEtsG5jyMntI1wS+N1BGcQBl/CoLoPOl9ABrW/BP53e1bwSJHHlkIVchJwmHwyyfJ4kIvEnKtwkxNSEct83KSChT7WiWgDZ3ccZ0BM4tloJow2YUAtifNT3njnyD+y/pMsnP4DN3Y4yl1Gyk0AAAAASUVORK5CYII=';
  181. /**
  182. * Specifies the image URL to be used for the transparent background.
  183. */
  184. Editor.ctrlKey = (mxClient.IS_MAC) ? 'Cmd' : 'Ctrl';
  185. /**
  186. * Specifies the image URL to be used for the transparent background.
  187. */
  188. Editor.hintOffset = 20;
  189. /**
  190. * Specifies if the diagram should be saved automatically if possible. Default
  191. * is true.
  192. */
  193. Editor.popupsAllowed = true;
  194. /**
  195. * Editor inherits from mxEventSource
  196. */
  197. mxUtils.extend(Editor, mxEventSource);
  198. /**
  199. * Stores initial state of mxClient.NO_FO.
  200. */
  201. Editor.prototype.originalNoForeignObject = mxClient.NO_FO;
  202. /**
  203. * Specifies the image URL to be used for the transparent background.
  204. */
  205. Editor.prototype.transparentImage = (mxClient.IS_SVG) ? 'data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7' :
  206. IMAGE_PATH + '/transparent.gif';
  207. /**
  208. * Specifies if the canvas should be extended in all directions. Default is true.
  209. */
  210. Editor.prototype.extendCanvas = true;
  211. /**
  212. * Specifies if the app should run in chromeless mode. Default is false.
  213. * This default is only used if the contructor argument is null.
  214. */
  215. Editor.prototype.chromeless = false;
  216. /**
  217. * Specifies the order of OK/Cancel buttons in dialogs. Default is true.
  218. * Cancel first is used on Macs, Windows/Confluence uses cancel last.
  219. */
  220. Editor.prototype.cancelFirst = true;
  221. /**
  222. * Specifies if the editor is enabled. Default is true.
  223. */
  224. Editor.prototype.enabled = true;
  225. /**
  226. * Contains the name which was used for the last save. Default value is null.
  227. */
  228. Editor.prototype.filename = null;
  229. /**
  230. * Contains the current modified state of the diagram. This is false for
  231. * new diagrams and after the diagram was saved.
  232. */
  233. Editor.prototype.modified = false;
  234. /**
  235. * Specifies if the diagram should be saved automatically if possible. Default
  236. * is true.
  237. */
  238. Editor.prototype.autosave = true;
  239. /**
  240. * Specifies the top spacing for the initial page view. Default is 0.
  241. */
  242. Editor.prototype.initialTopSpacing = 0;
  243. /**
  244. * Specifies the app name. Default is document.title.
  245. */
  246. Editor.prototype.appName = document.title;
  247. /**
  248. *
  249. */
  250. Editor.prototype.editBlankUrl = window.location.protocol + '//' + window.location.host + '/';
  251. /**
  252. * Default value for the graph container overflow style.
  253. */
  254. Editor.prototype.defaultGraphOverflow = 'hidden';
  255. /**
  256. * Initializes the environment.
  257. */
  258. Editor.prototype.init = function() { };
  259. /**
  260. * Sets the XML node for the current diagram.
  261. */
  262. Editor.prototype.isChromelessView = function()
  263. {
  264. return this.chromeless;
  265. };
  266. /**
  267. * Sets the XML node for the current diagram.
  268. */
  269. Editor.prototype.setAutosave = function(value)
  270. {
  271. this.autosave = value;
  272. this.fireEvent(new mxEventObject('autosaveChanged'));
  273. };
  274. /**
  275. *
  276. */
  277. Editor.prototype.getEditBlankUrl = function(params)
  278. {
  279. return this.editBlankUrl + params;
  280. }
  281. /**
  282. *
  283. */
  284. Editor.prototype.editAsNew = function(xml, title)
  285. {
  286. var p = (title != null) ? '?title=' + encodeURIComponent(title) : '';
  287. if (urlParams['ui'] != null)
  288. {
  289. p += ((p.length > 0) ? '&' : '?') + 'ui=' + urlParams['ui'];
  290. }
  291. if (typeof window.postMessage !== 'undefined' &&
  292. (document.documentMode == null ||
  293. document.documentMode >= 10))
  294. {
  295. var wnd = null;
  296. var l = mxUtils.bind(this, function(evt)
  297. {
  298. if (evt.data == 'ready' && evt.source == wnd)
  299. {
  300. mxEvent.removeListener(window, 'message', l);
  301. wnd.postMessage(xml, '*');
  302. }
  303. });
  304. mxEvent.addListener(window, 'message', l);
  305. wnd = this.graph.openLink(this.getEditBlankUrl(
  306. p + ((p.length > 0) ? '&' : '?') +
  307. 'client=1'), null, true);
  308. }
  309. else
  310. {
  311. this.graph.openLink(this.getEditBlankUrl(p) +
  312. '#R' + encodeURIComponent(xml));
  313. }
  314. };
  315. /**
  316. * Sets the XML node for the current diagram.
  317. */
  318. Editor.prototype.createGraph = function(themes, model)
  319. {
  320. var graph = new Graph(null, model, null, null, themes);
  321. graph.transparentBackground = false;
  322. // Opens all links in a new window while editing
  323. if (!this.chromeless)
  324. {
  325. graph.isBlankLink = function(href)
  326. {
  327. return !this.isExternalProtocol(href);
  328. };
  329. }
  330. return graph;
  331. };
  332. /**
  333. * Sets the XML node for the current diagram.
  334. */
  335. Editor.prototype.resetGraph = function()
  336. {
  337. this.graph.gridEnabled = !this.isChromelessView() || urlParams['grid'] == '1';
  338. this.graph.graphHandler.guidesEnabled = true;
  339. this.graph.setTooltips(true);
  340. this.graph.setConnectable(true);
  341. this.graph.foldingEnabled = true;
  342. this.graph.scrollbars = this.graph.defaultScrollbars;
  343. this.graph.pageVisible = this.graph.defaultPageVisible;
  344. this.graph.pageBreaksVisible = this.graph.pageVisible;
  345. this.graph.preferPageSize = this.graph.pageBreaksVisible;
  346. this.graph.background = null;
  347. this.graph.pageScale = mxGraph.prototype.pageScale;
  348. this.graph.pageFormat = mxGraph.prototype.pageFormat;
  349. this.graph.currentScale = 1;
  350. this.graph.currentTranslate.x = 0;
  351. this.graph.currentTranslate.y = 0;
  352. this.updateGraphComponents();
  353. this.graph.view.setScale(1);
  354. };
  355. /**
  356. * Sets the XML node for the current diagram.
  357. */
  358. Editor.prototype.readGraphState = function(node)
  359. {
  360. this.graph.gridEnabled = node.getAttribute('grid') != '0' && (!this.isChromelessView() || urlParams['grid'] == '1');
  361. this.graph.gridSize = parseFloat(node.getAttribute('gridSize')) || mxGraph.prototype.gridSize;
  362. this.graph.graphHandler.guidesEnabled = node.getAttribute('guides') != '0';
  363. this.graph.setTooltips(node.getAttribute('tooltips') != '0');
  364. this.graph.setConnectable(node.getAttribute('connect') != '0');
  365. this.graph.connectionArrowsEnabled = node.getAttribute('arrows') != '0';
  366. this.graph.foldingEnabled = node.getAttribute('fold') != '0';
  367. if (this.isChromelessView() && this.graph.foldingEnabled)
  368. {
  369. this.graph.foldingEnabled = urlParams['nav'] == '1';
  370. this.graph.cellRenderer.forceControlClickHandler = this.graph.foldingEnabled;
  371. }
  372. var ps = parseFloat(node.getAttribute('pageScale'));
  373. if (!isNaN(ps) && ps > 0)
  374. {
  375. this.graph.pageScale = ps;
  376. }
  377. else
  378. {
  379. this.graph.pageScale = mxGraph.prototype.pageScale;
  380. }
  381. if (!this.graph.isLightboxView() && !this.graph.isViewer())
  382. {
  383. var pv = node.getAttribute('page');
  384. if (pv != null)
  385. {
  386. this.graph.pageVisible = (pv != '0');
  387. }
  388. else
  389. {
  390. this.graph.pageVisible = this.graph.defaultPageVisible;
  391. }
  392. }
  393. else
  394. {
  395. this.graph.pageVisible = false;
  396. }
  397. this.graph.pageBreaksVisible = this.graph.pageVisible;
  398. this.graph.preferPageSize = this.graph.pageBreaksVisible;
  399. var pw = parseFloat(node.getAttribute('pageWidth'));
  400. var ph = parseFloat(node.getAttribute('pageHeight'));
  401. if (!isNaN(pw) && !isNaN(ph))
  402. {
  403. this.graph.pageFormat = new mxRectangle(0, 0, pw, ph);
  404. }
  405. // Loads the persistent state settings
  406. var bg = node.getAttribute('background');
  407. if (bg != null && bg.length > 0)
  408. {
  409. this.graph.background = bg;
  410. }
  411. else
  412. {
  413. this.graph.background = null;
  414. }
  415. };
  416. /**
  417. * Sets the XML node for the current diagram.
  418. */
  419. Editor.prototype.setGraphXml = function(node)
  420. {
  421. if (node != null)
  422. {
  423. var dec = new mxCodec(node.ownerDocument);
  424. if (node.nodeName == 'mxGraphModel')
  425. {
  426. this.graph.model.beginUpdate();
  427. try
  428. {
  429. this.graph.model.clear();
  430. this.graph.view.scale = 1;
  431. this.readGraphState(node);
  432. this.updateGraphComponents();
  433. dec.decode(node, this.graph.getModel());
  434. }
  435. finally
  436. {
  437. this.graph.model.endUpdate();
  438. }
  439. this.fireEvent(new mxEventObject('resetGraphView'));
  440. }
  441. else if (node.nodeName == 'root')
  442. {
  443. this.resetGraph();
  444. // Workaround for invalid XML output in Firefox 20 due to bug in mxUtils.getXml
  445. var wrapper = dec.document.createElement('mxGraphModel');
  446. wrapper.appendChild(node);
  447. dec.decode(wrapper, this.graph.getModel());
  448. this.updateGraphComponents();
  449. this.fireEvent(new mxEventObject('resetGraphView'));
  450. }
  451. else
  452. {
  453. throw {
  454. message: mxResources.get('cannotOpenFile'),
  455. node: node,
  456. toString: function() { return this.message; }
  457. };
  458. }
  459. }
  460. else
  461. {
  462. this.resetGraph();
  463. this.graph.model.clear();
  464. this.fireEvent(new mxEventObject('resetGraphView'));
  465. }
  466. };
  467. /**
  468. * Returns the XML node that represents the current diagram.
  469. */
  470. Editor.prototype.getGraphXml = function(ignoreSelection)
  471. {
  472. ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
  473. var node = null;
  474. if (ignoreSelection)
  475. {
  476. var enc = new mxCodec(mxUtils.createXmlDocument());
  477. node = enc.encode(this.graph.getModel());
  478. }
  479. else
  480. {
  481. node = this.graph.encodeCells(mxUtils.sortCells(this.graph.model.getTopmostCells(
  482. this.graph.getSelectionCells())));
  483. }
  484. if (this.graph.view.translate.x != 0 || this.graph.view.translate.y != 0)
  485. {
  486. node.setAttribute('dx', Math.round(this.graph.view.translate.x * 100) / 100);
  487. node.setAttribute('dy', Math.round(this.graph.view.translate.y * 100) / 100);
  488. }
  489. node.setAttribute('grid', (this.graph.isGridEnabled()) ? '1' : '0');
  490. node.setAttribute('gridSize', this.graph.gridSize);
  491. node.setAttribute('guides', (this.graph.graphHandler.guidesEnabled) ? '1' : '0');
  492. node.setAttribute('tooltips', (this.graph.tooltipHandler.isEnabled()) ? '1' : '0');
  493. node.setAttribute('connect', (this.graph.connectionHandler.isEnabled()) ? '1' : '0');
  494. node.setAttribute('arrows', (this.graph.connectionArrowsEnabled) ? '1' : '0');
  495. node.setAttribute('fold', (this.graph.foldingEnabled) ? '1' : '0');
  496. node.setAttribute('page', (this.graph.pageVisible) ? '1' : '0');
  497. node.setAttribute('pageScale', this.graph.pageScale);
  498. node.setAttribute('pageWidth', this.graph.pageFormat.width);
  499. node.setAttribute('pageHeight', this.graph.pageFormat.height);
  500. if (this.graph.background != null)
  501. {
  502. node.setAttribute('background', this.graph.background);
  503. }
  504. return node;
  505. };
  506. /**
  507. * Keeps the graph container in sync with the persistent graph state
  508. */
  509. Editor.prototype.updateGraphComponents = function()
  510. {
  511. var graph = this.graph;
  512. if (graph.container != null)
  513. {
  514. graph.view.validateBackground();
  515. graph.container.style.overflow = (graph.scrollbars) ? 'auto' : this.defaultGraphOverflow;
  516. this.fireEvent(new mxEventObject('updateGraphComponents'));
  517. }
  518. };
  519. /**
  520. * Sets the modified flag.
  521. */
  522. Editor.prototype.setModified = function(value)
  523. {
  524. this.modified = value;
  525. };
  526. /**
  527. * Sets the filename.
  528. */
  529. Editor.prototype.setFilename = function(value)
  530. {
  531. this.filename = value;
  532. };
  533. /**
  534. * Creates and returns a new undo manager.
  535. */
  536. Editor.prototype.createUndoManager = function()
  537. {
  538. var graph = this.graph;
  539. var undoMgr = new mxUndoManager();
  540. this.undoListener = function(sender, evt)
  541. {
  542. undoMgr.undoableEditHappened(evt.getProperty('edit'));
  543. };
  544. // Installs the command history
  545. var listener = mxUtils.bind(this, function(sender, evt)
  546. {
  547. this.undoListener.apply(this, arguments);
  548. });
  549. graph.getModel().addListener(mxEvent.UNDO, listener);
  550. graph.getView().addListener(mxEvent.UNDO, listener);
  551. // Keeps the selection in sync with the history
  552. var undoHandler = function(sender, evt)
  553. {
  554. var cand = graph.getSelectionCellsForChanges(evt.getProperty('edit').changes, function(change)
  555. {
  556. // Only selects changes to the cell hierarchy
  557. return !(change instanceof mxChildChange);
  558. });
  559. if (cand.length > 0)
  560. {
  561. var model = graph.getModel();
  562. var cells = [];
  563. for (var i = 0; i < cand.length; i++)
  564. {
  565. if (graph.view.getState(cand[i]) != null)
  566. {
  567. cells.push(cand[i]);
  568. }
  569. }
  570. graph.setSelectionCells(cells);
  571. }
  572. };
  573. undoMgr.addListener(mxEvent.UNDO, undoHandler);
  574. undoMgr.addListener(mxEvent.REDO, undoHandler);
  575. return undoMgr;
  576. };
  577. /**
  578. * Adds basic stencil set (no namespace).
  579. */
  580. Editor.prototype.initStencilRegistry = function() { };
  581. /**
  582. * Creates and returns a new undo manager.
  583. */
  584. Editor.prototype.destroy = function()
  585. {
  586. if (this.graph != null)
  587. {
  588. this.graph.destroy();
  589. this.graph = null;
  590. }
  591. };
  592. /**
  593. * Class for asynchronously opening a new window and loading a file at the same
  594. * time. This acts as a bridge between the open dialog and the new editor.
  595. */
  596. OpenFile = function(done)
  597. {
  598. this.producer = null;
  599. this.consumer = null;
  600. this.done = done;
  601. this.args = null;
  602. };
  603. /**
  604. * Registers the editor from the new window.
  605. */
  606. OpenFile.prototype.setConsumer = function(value)
  607. {
  608. this.consumer = value;
  609. this.execute();
  610. };
  611. /**
  612. * Sets the data from the loaded file.
  613. */
  614. OpenFile.prototype.setData = function()
  615. {
  616. this.args = arguments;
  617. this.execute();
  618. };
  619. /**
  620. * Displays an error message.
  621. */
  622. OpenFile.prototype.error = function(msg)
  623. {
  624. this.cancel(true);
  625. mxUtils.alert(msg);
  626. };
  627. /**
  628. * Consumes the data.
  629. */
  630. OpenFile.prototype.execute = function()
  631. {
  632. if (this.consumer != null && this.args != null)
  633. {
  634. this.cancel(false);
  635. this.consumer.apply(this, this.args);
  636. }
  637. };
  638. /**
  639. * Cancels the operation.
  640. */
  641. OpenFile.prototype.cancel = function(cancel)
  642. {
  643. if (this.done != null)
  644. {
  645. this.done((cancel != null) ? cancel : true);
  646. }
  647. };
  648. /**
  649. * Basic dialogs that are available in the viewer (print dialog).
  650. */
  651. function Dialog(editorUi, elt, w, h, modal, closable, onClose, noScroll, transparent, onResize, ignoreBgClick)
  652. {
  653. var dx = 0;
  654. if (mxClient.IS_VML && (document.documentMode == null || document.documentMode < 8))
  655. {
  656. // Adds padding as a workaround for box model in older IE versions
  657. // This needs to match the total padding of geDialog in CSS
  658. dx = 80;
  659. }
  660. w += dx;
  661. h += dx;
  662. var w0 = w;
  663. var h0 = h;
  664. var ds = mxUtils.getDocumentSize();
  665. // Workaround for print dialog offset in viewer lightbox
  666. if (window.innerHeight != null)
  667. {
  668. ds.height = window.innerHeight;
  669. }
  670. var dh = ds.height;
  671. var left = Math.max(1, Math.round((ds.width - w - 64) / 2));
  672. var top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
  673. // Keeps window size inside available space
  674. if (!mxClient.IS_QUIRKS)
  675. {
  676. elt.style.maxHeight = '100%';
  677. }
  678. w = (document.body != null) ? Math.min(w, document.body.scrollWidth - 64) : w;
  679. h = Math.min(h, dh - 64);
  680. // Increments zIndex to put subdialogs and background over existing dialogs and background
  681. if (editorUi.dialogs.length > 0)
  682. {
  683. this.zIndex += editorUi.dialogs.length * 2;
  684. }
  685. if (this.bg == null)
  686. {
  687. this.bg = editorUi.createDiv('background');
  688. this.bg.style.position = 'absolute';
  689. this.bg.style.background = Dialog.backdropColor;
  690. this.bg.style.height = dh + 'px';
  691. this.bg.style.right = '0px';
  692. this.bg.style.zIndex = this.zIndex - 2;
  693. mxUtils.setOpacity(this.bg, this.bgOpacity);
  694. if (mxClient.IS_QUIRKS)
  695. {
  696. new mxDivResizer(this.bg);
  697. }
  698. }
  699. var origin = mxUtils.getDocumentScrollOrigin(document);
  700. this.bg.style.left = origin.x + 'px';
  701. this.bg.style.top = origin.y + 'px';
  702. left += origin.x;
  703. top += origin.y;
  704. if (modal)
  705. {
  706. document.body.appendChild(this.bg);
  707. }
  708. var div = editorUi.createDiv(transparent? 'geTransDialog' : 'geDialog');
  709. var pos = this.getPosition(left, top, w, h);
  710. left = pos.x;
  711. top = pos.y;
  712. div.style.width = w + 'px';
  713. div.style.height = h + 'px';
  714. div.style.left = left + 'px';
  715. div.style.top = top + 'px';
  716. div.style.zIndex = this.zIndex;
  717. div.appendChild(elt);
  718. document.body.appendChild(div);
  719. // Adds vertical scrollbars if needed
  720. if (!noScroll && elt.clientHeight > div.clientHeight - 64)
  721. {
  722. elt.style.overflowY = 'auto';
  723. }
  724. if (closable)
  725. {
  726. var img = document.createElement('img');
  727. img.setAttribute('src', Dialog.prototype.closeImage);
  728. img.setAttribute('title', mxResources.get('close'));
  729. img.className = 'geDialogClose';
  730. img.style.top = (top + 14) + 'px';
  731. img.style.left = (left + w + 38 - dx) + 'px';
  732. img.style.zIndex = this.zIndex;
  733. mxEvent.addListener(img, 'click', mxUtils.bind(this, function()
  734. {
  735. editorUi.hideDialog(true);
  736. }));
  737. document.body.appendChild(img);
  738. this.dialogImg = img;
  739. if (!ignoreBgClick)
  740. {
  741. var mouseDownSeen = false;
  742. mxEvent.addGestureListeners(this.bg, mxUtils.bind(this, function(evt)
  743. {
  744. mouseDownSeen = true;
  745. }), null, mxUtils.bind(this, function(evt)
  746. {
  747. if (mouseDownSeen)
  748. {
  749. editorUi.hideDialog(true);
  750. mouseDownSeen = false;
  751. }
  752. }));
  753. }
  754. }
  755. this.resizeListener = mxUtils.bind(this, function()
  756. {
  757. if (onResize != null)
  758. {
  759. var newWH = onResize();
  760. if (newWH != null)
  761. {
  762. w0 = w = newWH.w;
  763. h0 = h = newWH.h;
  764. }
  765. }
  766. var ds = mxUtils.getDocumentSize();
  767. dh = ds.height;
  768. this.bg.style.height = dh + 'px';
  769. left = Math.max(1, Math.round((ds.width - w - 64) / 2));
  770. top = Math.max(1, Math.round((dh - h - editorUi.footerHeight) / 3));
  771. w = (document.body != null) ? Math.min(w0, document.body.scrollWidth - 64) : w0;
  772. h = Math.min(h0, dh - 64);
  773. var pos = this.getPosition(left, top, w, h);
  774. left = pos.x;
  775. top = pos.y;
  776. div.style.left = left + 'px';
  777. div.style.top = top + 'px';
  778. div.style.width = w + 'px';
  779. div.style.height = h + 'px';
  780. // Adds vertical scrollbars if needed
  781. if (!noScroll && elt.clientHeight > div.clientHeight - 64)
  782. {
  783. elt.style.overflowY = 'auto';
  784. }
  785. if (this.dialogImg != null)
  786. {
  787. this.dialogImg.style.top = (top + 14) + 'px';
  788. this.dialogImg.style.left = (left + w + 38 - dx) + 'px';
  789. }
  790. });
  791. mxEvent.addListener(window, 'resize', this.resizeListener);
  792. this.onDialogClose = onClose;
  793. this.container = div;
  794. editorUi.editor.fireEvent(new mxEventObject('showDialog'));
  795. };
  796. /**
  797. *
  798. */
  799. Dialog.backdropColor = 'white';
  800. /**
  801. *
  802. */
  803. Dialog.prototype.zIndex = mxPopupMenu.prototype.zIndex - 1;
  804. /**
  805. *
  806. */
  807. Dialog.prototype.noColorImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/nocolor.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkEzRDlBMUUwODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkEzRDlBMUUxODYxMTExRTFCMzA4RDdDMjJBMEMxRDM3Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTNEOUExREU4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTNEOUExREY4NjExMTFFMUIzMDhEN0MyMkEwQzFEMzciLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5xh3fmAAAABlBMVEX////MzMw46qqDAAAAGElEQVR42mJggAJGKGAYIIGBth8KAAIMAEUQAIElnLuQAAAAAElFTkSuQmCC';
  808. /**
  809. *
  810. */
  811. Dialog.prototype.closeImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/close.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJAQMAAADaX5RTAAAABlBMVEV7mr3///+wksspAAAAAnRSTlP/AOW3MEoAAAAdSURBVAgdY9jXwCDDwNDRwHCwgeExmASygSL7GgB12QiqNHZZIwAAAABJRU5ErkJggg==';
  812. /**
  813. *
  814. */
  815. Dialog.prototype.clearImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/clear.gif' : 'data:image/gif;base64,R0lGODlhDQAKAIABAMDAwP///yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUIzOEM1NzI4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUIzOEM1NzM4NjEyMTFFMUEzMkNDMUE3NjZERDE2QjIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QjM4QzU3MDg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QjM4QzU3MTg2MTIxMUUxQTMyQ0MxQTc2NkREMTZCMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAAEALAAAAAANAAoAAAIXTGCJebD9jEOTqRlttXdrB32PJ2ncyRQAOw==';
  816. /**
  817. *
  818. */
  819. Dialog.prototype.lockedImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/locked.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzdDMDZCODExNzIxMTFFNUI0RTk5NTg4OTcyMUUyODEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzdDMDZCODIxNzIxMTFFNUI0RTk5NTg4OTcyMUUyODEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozN0MwNkI3RjE3MjExMUU1QjRFOTk1ODg5NzIxRTI4MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozN0MwNkI4MDE3MjExMUU1QjRFOTk1ODg5NzIxRTI4MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvqMCFYAAAAVUExURZmZmb+/v7KysqysrMzMzLGxsf///4g8N1cAAAAHdFJOU////////wAaSwNGAAAAPElEQVR42lTMQQ4AIQgEwUa0//9kTQirOweYOgDqAMbZUr10AGlAwx4/BJ2QJ4U0L5brYjovvpv32xZgAHZaATFtMbu4AAAAAElFTkSuQmCC';
  820. /**
  821. *
  822. */
  823. Dialog.prototype.unlockedImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/unlocked.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAMAAABhq6zVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MzdDMDZCN0QxNzIxMTFFNUI0RTk5NTg4OTcyMUUyODEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MzdDMDZCN0UxNzIxMTFFNUI0RTk5NTg4OTcyMUUyODEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDozN0MwNkI3QjE3MjExMUU1QjRFOTk1ODg5NzIxRTI4MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDozN0MwNkI3QzE3MjExMUU1QjRFOTk1ODg5NzIxRTI4MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PkKMpVwAAAAYUExURZmZmbKysr+/v6ysrOXl5czMzLGxsf///zHN5lwAAAAIdFJOU/////////8A3oO9WQAAADxJREFUeNpUzFESACAEBNBVsfe/cZJU+8Mzs8CIABCidtfGOndnYsT40HDSiCcbPdoJo10o9aI677cpwACRoAF3dFNlswAAAABJRU5ErkJggg==';
  824. /**
  825. * Removes the dialog from the DOM.
  826. */
  827. Dialog.prototype.bgOpacity = 80;
  828. /**
  829. * Removes the dialog from the DOM.
  830. */
  831. Dialog.prototype.getPosition = function(left, top)
  832. {
  833. return new mxPoint(left, top);
  834. };
  835. /**
  836. * Removes the dialog from the DOM.
  837. */
  838. Dialog.prototype.close = function(cancel, isEsc)
  839. {
  840. if (this.onDialogClose != null)
  841. {
  842. if (this.onDialogClose(cancel, isEsc) == false)
  843. {
  844. return false;
  845. }
  846. this.onDialogClose = null;
  847. }
  848. if (this.dialogImg != null)
  849. {
  850. this.dialogImg.parentNode.removeChild(this.dialogImg);
  851. this.dialogImg = null;
  852. }
  853. if (this.bg != null && this.bg.parentNode != null)
  854. {
  855. this.bg.parentNode.removeChild(this.bg);
  856. }
  857. mxEvent.removeListener(window, 'resize', this.resizeListener);
  858. this.container.parentNode.removeChild(this.container);
  859. };
  860. /**
  861. *
  862. */
  863. var ErrorDialog = function(editorUi, title, message, buttonText, fn, retry, buttonText2, fn2, hide, buttonText3, fn3)
  864. {
  865. hide = (hide != null) ? hide : true;
  866. var div = document.createElement('div');
  867. div.style.textAlign = 'center';
  868. if (title != null)
  869. {
  870. var hd = document.createElement('div');
  871. hd.style.padding = '0px';
  872. hd.style.margin = '0px';
  873. hd.style.fontSize = '18px';
  874. hd.style.paddingBottom = '16px';
  875. hd.style.marginBottom = '10px';
  876. hd.style.borderBottom = '1px solid #c0c0c0';
  877. hd.style.color = 'gray';
  878. hd.style.whiteSpace = 'nowrap';
  879. hd.style.textOverflow = 'ellipsis';
  880. hd.style.overflow = 'hidden';
  881. mxUtils.write(hd, title);
  882. hd.setAttribute('title', title);
  883. div.appendChild(hd);
  884. }
  885. var p2 = document.createElement('div');
  886. p2.style.lineHeight = '1.2em';
  887. p2.style.padding = '6px';
  888. p2.innerHTML = message;
  889. div.appendChild(p2);
  890. var btns = document.createElement('div');
  891. btns.style.marginTop = '12px';
  892. btns.style.textAlign = 'center';
  893. if (retry != null)
  894. {
  895. var retryBtn = mxUtils.button(mxResources.get('tryAgain'), function()
  896. {
  897. editorUi.hideDialog();
  898. retry();
  899. });
  900. retryBtn.className = 'geBtn';
  901. btns.appendChild(retryBtn);
  902. btns.style.textAlign = 'center';
  903. }
  904. if (buttonText3 != null)
  905. {
  906. var btn3 = mxUtils.button(buttonText3, function()
  907. {
  908. if (fn3 != null)
  909. {
  910. fn3();
  911. }
  912. });
  913. btn3.className = 'geBtn';
  914. btns.appendChild(btn3);
  915. }
  916. var btn = mxUtils.button(buttonText, function()
  917. {
  918. if (hide)
  919. {
  920. editorUi.hideDialog();
  921. }
  922. if (fn != null)
  923. {
  924. fn();
  925. }
  926. });
  927. btn.className = 'geBtn';
  928. btns.appendChild(btn);
  929. if (buttonText2 != null)
  930. {
  931. var mainBtn = mxUtils.button(buttonText2, function()
  932. {
  933. if (hide)
  934. {
  935. editorUi.hideDialog();
  936. }
  937. if (fn2 != null)
  938. {
  939. fn2();
  940. }
  941. });
  942. mainBtn.className = 'geBtn gePrimaryBtn';
  943. btns.appendChild(mainBtn);
  944. }
  945. this.init = function()
  946. {
  947. btn.focus();
  948. };
  949. div.appendChild(btns);
  950. this.container = div;
  951. };
  952. /**
  953. * Constructs a new print dialog.
  954. */
  955. var PrintDialog = function(editorUi, title)
  956. {
  957. this.create(editorUi, title);
  958. };
  959. /**
  960. * Constructs a new print dialog.
  961. */
  962. PrintDialog.prototype.create = function(editorUi)
  963. {
  964. var graph = editorUi.editor.graph;
  965. var row, td;
  966. var table = document.createElement('table');
  967. table.style.width = '100%';
  968. table.style.height = '100%';
  969. var tbody = document.createElement('tbody');
  970. row = document.createElement('tr');
  971. var onePageCheckBox = document.createElement('input');
  972. onePageCheckBox.setAttribute('type', 'checkbox');
  973. td = document.createElement('td');
  974. td.setAttribute('colspan', '2');
  975. td.style.fontSize = '10pt';
  976. td.appendChild(onePageCheckBox);
  977. var span = document.createElement('span');
  978. mxUtils.write(span, ' ' + mxResources.get('fitPage'));
  979. td.appendChild(span);
  980. mxEvent.addListener(span, 'click', function(evt)
  981. {
  982. onePageCheckBox.checked = !onePageCheckBox.checked;
  983. pageCountCheckBox.checked = !onePageCheckBox.checked;
  984. mxEvent.consume(evt);
  985. });
  986. mxEvent.addListener(onePageCheckBox, 'change', function()
  987. {
  988. pageCountCheckBox.checked = !onePageCheckBox.checked;
  989. });
  990. row.appendChild(td);
  991. tbody.appendChild(row);
  992. row = row.cloneNode(false);
  993. var pageCountCheckBox = document.createElement('input');
  994. pageCountCheckBox.setAttribute('type', 'checkbox');
  995. td = document.createElement('td');
  996. td.style.fontSize = '10pt';
  997. td.appendChild(pageCountCheckBox);
  998. var span = document.createElement('span');
  999. mxUtils.write(span, ' ' + mxResources.get('posterPrint') + ':');
  1000. td.appendChild(span);
  1001. mxEvent.addListener(span, 'click', function(evt)
  1002. {
  1003. pageCountCheckBox.checked = !pageCountCheckBox.checked;
  1004. onePageCheckBox.checked = !pageCountCheckBox.checked;
  1005. mxEvent.consume(evt);
  1006. });
  1007. row.appendChild(td);
  1008. var pageCountInput = document.createElement('input');
  1009. pageCountInput.setAttribute('value', '1');
  1010. pageCountInput.setAttribute('type', 'number');
  1011. pageCountInput.setAttribute('min', '1');
  1012. pageCountInput.setAttribute('size', '4');
  1013. pageCountInput.setAttribute('disabled', 'disabled');
  1014. pageCountInput.style.width = '50px';
  1015. td = document.createElement('td');
  1016. td.style.fontSize = '10pt';
  1017. td.appendChild(pageCountInput);
  1018. mxUtils.write(td, ' ' + mxResources.get('pages') + ' (max)');
  1019. row.appendChild(td);
  1020. tbody.appendChild(row);
  1021. mxEvent.addListener(pageCountCheckBox, 'change', function()
  1022. {
  1023. if (pageCountCheckBox.checked)
  1024. {
  1025. pageCountInput.removeAttribute('disabled');
  1026. }
  1027. else
  1028. {
  1029. pageCountInput.setAttribute('disabled', 'disabled');
  1030. }
  1031. onePageCheckBox.checked = !pageCountCheckBox.checked;
  1032. });
  1033. row = row.cloneNode(false);
  1034. td = document.createElement('td');
  1035. mxUtils.write(td, mxResources.get('pageScale') + ':');
  1036. row.appendChild(td);
  1037. td = document.createElement('td');
  1038. var pageScaleInput = document.createElement('input');
  1039. pageScaleInput.setAttribute('value', '100 %');
  1040. pageScaleInput.setAttribute('size', '5');
  1041. pageScaleInput.style.width = '50px';
  1042. td.appendChild(pageScaleInput);
  1043. row.appendChild(td);
  1044. tbody.appendChild(row);
  1045. row = document.createElement('tr');
  1046. td = document.createElement('td');
  1047. td.colSpan = 2;
  1048. td.style.paddingTop = '20px';
  1049. td.setAttribute('align', 'right');
  1050. // Overall scale for print-out to account for print borders in dialogs etc
  1051. function preview(print)
  1052. {
  1053. var autoOrigin = onePageCheckBox.checked || pageCountCheckBox.checked;
  1054. var printScale = parseInt(pageScaleInput.value) / 100;
  1055. if (isNaN(printScale))
  1056. {
  1057. printScale = 1;
  1058. pageScaleInput.value = '100%';
  1059. }
  1060. // Workaround to match available paper size in actual print output
  1061. printScale *= 0.75;
  1062. var pf = graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT;
  1063. var scale = 1 / graph.pageScale;
  1064. if (autoOrigin)
  1065. {
  1066. var pageCount = (onePageCheckBox.checked) ? 1 : parseInt(pageCountInput.value);
  1067. if (!isNaN(pageCount))
  1068. {
  1069. scale = mxUtils.getScaleForPageCount(pageCount, graph, pf);
  1070. }
  1071. }
  1072. // Negative coordinates are cropped or shifted if page visible
  1073. var gb = graph.getGraphBounds();
  1074. var border = 0;
  1075. var x0 = 0;
  1076. var y0 = 0;
  1077. // Applies print scale
  1078. pf = mxRectangle.fromRectangle(pf);
  1079. pf.width = Math.ceil(pf.width * printScale);
  1080. pf.height = Math.ceil(pf.height * printScale);
  1081. scale *= printScale;
  1082. // Starts at first visible page
  1083. if (!autoOrigin && graph.pageVisible)
  1084. {
  1085. var layout = graph.getPageLayout();
  1086. x0 -= layout.x * pf.width;
  1087. y0 -= layout.y * pf.height;
  1088. }
  1089. else
  1090. {
  1091. autoOrigin = true;
  1092. }
  1093. var preview = PrintDialog.createPrintPreview(graph, scale, pf, border, x0, y0, autoOrigin);
  1094. preview.open();
  1095. if (print)
  1096. {
  1097. PrintDialog.printPreview(preview);
  1098. }
  1099. };
  1100. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1101. {
  1102. editorUi.hideDialog();
  1103. });
  1104. cancelBtn.className = 'geBtn';
  1105. if (editorUi.editor.cancelFirst)
  1106. {
  1107. td.appendChild(cancelBtn);
  1108. }
  1109. if (PrintDialog.previewEnabled)
  1110. {
  1111. var previewBtn = mxUtils.button(mxResources.get('preview'), function()
  1112. {
  1113. editorUi.hideDialog();
  1114. preview(false);
  1115. });
  1116. previewBtn.className = 'geBtn';
  1117. td.appendChild(previewBtn);
  1118. }
  1119. var printBtn = mxUtils.button(mxResources.get((!PrintDialog.previewEnabled) ? 'ok' : 'print'), function()
  1120. {
  1121. editorUi.hideDialog();
  1122. preview(true);
  1123. });
  1124. printBtn.className = 'geBtn gePrimaryBtn';
  1125. td.appendChild(printBtn);
  1126. if (!editorUi.editor.cancelFirst)
  1127. {
  1128. td.appendChild(cancelBtn);
  1129. }
  1130. row.appendChild(td);
  1131. tbody.appendChild(row);
  1132. table.appendChild(tbody);
  1133. this.container = table;
  1134. };
  1135. /**
  1136. * Constructs a new print dialog.
  1137. */
  1138. PrintDialog.printPreview = function(preview)
  1139. {
  1140. try
  1141. {
  1142. if (preview.wnd != null)
  1143. {
  1144. var printFn = function()
  1145. {
  1146. preview.wnd.focus();
  1147. preview.wnd.print();
  1148. preview.wnd.close();
  1149. };
  1150. // Workaround for Google Chrome which needs a bit of a
  1151. // delay in order to render the SVG contents
  1152. // Needs testing in production
  1153. if (mxClient.IS_GC)
  1154. {
  1155. window.setTimeout(printFn, 500);
  1156. }
  1157. else
  1158. {
  1159. printFn();
  1160. }
  1161. }
  1162. }
  1163. catch (e)
  1164. {
  1165. // ignores possible Access Denied
  1166. }
  1167. };
  1168. /**
  1169. * Constructs a new print dialog.
  1170. */
  1171. PrintDialog.createPrintPreview = function(graph, scale, pf, border, x0, y0, autoOrigin)
  1172. {
  1173. var preview = new mxPrintPreview(graph, scale, pf, border, x0, y0);
  1174. preview.title = mxResources.get('preview');
  1175. preview.printBackgroundImage = true;
  1176. preview.autoOrigin = autoOrigin;
  1177. var bg = graph.background;
  1178. if (bg == null || bg == '' || bg == mxConstants.NONE)
  1179. {
  1180. bg = '#ffffff';
  1181. }
  1182. preview.backgroundColor = bg;
  1183. var writeHead = preview.writeHead;
  1184. // Adds a border in the preview
  1185. preview.writeHead = function(doc)
  1186. {
  1187. writeHead.apply(this, arguments);
  1188. doc.writeln('<style type="text/css">');
  1189. doc.writeln('@media screen {');
  1190. doc.writeln(' body > div { padding:30px;box-sizing:content-box; }');
  1191. doc.writeln('}');
  1192. doc.writeln('</style>');
  1193. };
  1194. return preview;
  1195. };
  1196. /**
  1197. * Specifies if the preview button should be enabled. Default is true.
  1198. */
  1199. PrintDialog.previewEnabled = true;
  1200. /**
  1201. * Constructs a new page setup dialog.
  1202. */
  1203. var PageSetupDialog = function(editorUi)
  1204. {
  1205. var graph = editorUi.editor.graph;
  1206. var row, td;
  1207. var table = document.createElement('table');
  1208. table.style.width = '100%';
  1209. table.style.height = '100%';
  1210. var tbody = document.createElement('tbody');
  1211. row = document.createElement('tr');
  1212. td = document.createElement('td');
  1213. td.style.verticalAlign = 'top';
  1214. td.style.fontSize = '10pt';
  1215. mxUtils.write(td, mxResources.get('paperSize') + ':');
  1216. row.appendChild(td);
  1217. td = document.createElement('td');
  1218. td.style.verticalAlign = 'top';
  1219. td.style.fontSize = '10pt';
  1220. var accessor = PageSetupDialog.addPageFormatPanel(td, 'pagesetupdialog', graph.pageFormat);
  1221. row.appendChild(td);
  1222. tbody.appendChild(row);
  1223. row = document.createElement('tr');
  1224. td = document.createElement('td');
  1225. mxUtils.write(td, mxResources.get('background') + ':');
  1226. row.appendChild(td);
  1227. td = document.createElement('td');
  1228. td.style.whiteSpace = 'nowrap';
  1229. var backgroundInput = document.createElement('input');
  1230. backgroundInput.setAttribute('type', 'text');
  1231. var backgroundButton = document.createElement('button');
  1232. backgroundButton.style.width = '18px';
  1233. backgroundButton.style.height = '18px';
  1234. backgroundButton.style.marginRight = '20px';
  1235. backgroundButton.style.backgroundPosition = 'center center';
  1236. backgroundButton.style.backgroundRepeat = 'no-repeat';
  1237. var newBackgroundColor = graph.background;
  1238. function updateBackgroundColor()
  1239. {
  1240. if (newBackgroundColor == null || newBackgroundColor == mxConstants.NONE)
  1241. {
  1242. backgroundButton.style.backgroundColor = '';
  1243. backgroundButton.style.backgroundImage = 'url(\'' + Dialog.prototype.noColorImage + '\')';
  1244. }
  1245. else
  1246. {
  1247. backgroundButton.style.backgroundColor = newBackgroundColor;
  1248. backgroundButton.style.backgroundImage = '';
  1249. }
  1250. };
  1251. updateBackgroundColor();
  1252. mxEvent.addListener(backgroundButton, 'click', function(evt)
  1253. {
  1254. editorUi.pickColor(newBackgroundColor || 'none', function(color)
  1255. {
  1256. newBackgroundColor = color;
  1257. updateBackgroundColor();
  1258. });
  1259. mxEvent.consume(evt);
  1260. });
  1261. td.appendChild(backgroundButton);
  1262. mxUtils.write(td, mxResources.get('gridSize') + ':');
  1263. var gridSizeInput = document.createElement('input');
  1264. gridSizeInput.setAttribute('type', 'number');
  1265. gridSizeInput.setAttribute('min', '0');
  1266. gridSizeInput.style.width = '40px';
  1267. gridSizeInput.style.marginLeft = '6px';
  1268. gridSizeInput.value = graph.getGridSize();
  1269. td.appendChild(gridSizeInput);
  1270. mxEvent.addListener(gridSizeInput, 'change', function()
  1271. {
  1272. var value = parseInt(gridSizeInput.value);
  1273. gridSizeInput.value = Math.max(1, (isNaN(value)) ? graph.getGridSize() : value);
  1274. });
  1275. row.appendChild(td);
  1276. tbody.appendChild(row);
  1277. row = document.createElement('tr');
  1278. td = document.createElement('td');
  1279. mxUtils.write(td, mxResources.get('image') + ':');
  1280. row.appendChild(td);
  1281. td = document.createElement('td');
  1282. var changeImageLink = document.createElement('a');
  1283. changeImageLink.style.textDecoration = 'underline';
  1284. changeImageLink.style.cursor = 'pointer';
  1285. changeImageLink.style.color = '#a0a0a0';
  1286. var newBackgroundImage = graph.backgroundImage;
  1287. function updateBackgroundImage()
  1288. {
  1289. if (newBackgroundImage == null)
  1290. {
  1291. changeImageLink.removeAttribute('title');
  1292. changeImageLink.style.fontSize = '';
  1293. changeImageLink.innerHTML = mxResources.get('change') + '...';
  1294. }
  1295. else
  1296. {
  1297. changeImageLink.setAttribute('title', newBackgroundImage.src);
  1298. changeImageLink.style.fontSize = '11px';
  1299. changeImageLink.innerHTML = newBackgroundImage.src.substring(0, 42) + '...';
  1300. }
  1301. };
  1302. mxEvent.addListener(changeImageLink, 'click', function(evt)
  1303. {
  1304. editorUi.showBackgroundImageDialog(function(image)
  1305. {
  1306. newBackgroundImage = image;
  1307. updateBackgroundImage();
  1308. });
  1309. mxEvent.consume(evt);
  1310. });
  1311. updateBackgroundImage();
  1312. td.appendChild(changeImageLink);
  1313. row.appendChild(td);
  1314. tbody.appendChild(row);
  1315. row = document.createElement('tr');
  1316. td = document.createElement('td');
  1317. td.colSpan = 2;
  1318. td.style.paddingTop = '16px';
  1319. td.setAttribute('align', 'right');
  1320. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1321. {
  1322. editorUi.hideDialog();
  1323. });
  1324. cancelBtn.className = 'geBtn';
  1325. if (editorUi.editor.cancelFirst)
  1326. {
  1327. td.appendChild(cancelBtn);
  1328. }
  1329. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  1330. {
  1331. editorUi.hideDialog();
  1332. if (graph.gridSize !== gridSizeInput.value)
  1333. {
  1334. graph.setGridSize(parseInt(gridSizeInput.value));
  1335. }
  1336. var change = new ChangePageSetup(editorUi, newBackgroundColor,
  1337. newBackgroundImage, accessor.get());
  1338. change.ignoreColor = graph.background == newBackgroundColor;
  1339. var oldSrc = (graph.backgroundImage != null) ? graph.backgroundImage.src : null;
  1340. var newSrc = (newBackgroundImage != null) ? newBackgroundImage.src : null;
  1341. change.ignoreImage = oldSrc === newSrc;
  1342. if (graph.pageFormat.width != change.previousFormat.width ||
  1343. graph.pageFormat.height != change.previousFormat.height ||
  1344. !change.ignoreColor || !change.ignoreImage)
  1345. {
  1346. graph.model.execute(change);
  1347. }
  1348. });
  1349. applyBtn.className = 'geBtn gePrimaryBtn';
  1350. td.appendChild(applyBtn);
  1351. if (!editorUi.editor.cancelFirst)
  1352. {
  1353. td.appendChild(cancelBtn);
  1354. }
  1355. row.appendChild(td);
  1356. tbody.appendChild(row);
  1357. table.appendChild(tbody);
  1358. this.container = table;
  1359. };
  1360. /**
  1361. *
  1362. */
  1363. PageSetupDialog.addPageFormatPanel = function(div, namePostfix, pageFormat, pageFormatListener)
  1364. {
  1365. var formatName = 'format-' + namePostfix;
  1366. var portraitCheckBox = document.createElement('input');
  1367. portraitCheckBox.setAttribute('name', formatName);
  1368. portraitCheckBox.setAttribute('type', 'radio');
  1369. portraitCheckBox.setAttribute('value', 'portrait');
  1370. var landscapeCheckBox = document.createElement('input');
  1371. landscapeCheckBox.setAttribute('name', formatName);
  1372. landscapeCheckBox.setAttribute('type', 'radio');
  1373. landscapeCheckBox.setAttribute('value', 'landscape');
  1374. var paperSizeSelect = document.createElement('select');
  1375. paperSizeSelect.style.marginBottom = '8px';
  1376. paperSizeSelect.style.width = '202px';
  1377. var formatDiv = document.createElement('div');
  1378. formatDiv.style.marginLeft = '4px';
  1379. formatDiv.style.width = '210px';
  1380. formatDiv.style.height = '24px';
  1381. portraitCheckBox.style.marginRight = '6px';
  1382. formatDiv.appendChild(portraitCheckBox);
  1383. var portraitSpan = document.createElement('span');
  1384. portraitSpan.style.maxWidth = '100px';
  1385. mxUtils.write(portraitSpan, mxResources.get('portrait'));
  1386. formatDiv.appendChild(portraitSpan);
  1387. landscapeCheckBox.style.marginLeft = '10px';
  1388. landscapeCheckBox.style.marginRight = '6px';
  1389. formatDiv.appendChild(landscapeCheckBox);
  1390. var landscapeSpan = document.createElement('span');
  1391. landscapeSpan.style.width = '100px';
  1392. mxUtils.write(landscapeSpan, mxResources.get('landscape'));
  1393. formatDiv.appendChild(landscapeSpan)
  1394. var customDiv = document.createElement('div');
  1395. customDiv.style.marginLeft = '4px';
  1396. customDiv.style.width = '210px';
  1397. customDiv.style.height = '24px';
  1398. var widthInput = document.createElement('input');
  1399. widthInput.setAttribute('size', '7');
  1400. widthInput.style.textAlign = 'right';
  1401. customDiv.appendChild(widthInput);
  1402. mxUtils.write(customDiv, ' in x ');
  1403. var heightInput = document.createElement('input');
  1404. heightInput.setAttribute('size', '7');
  1405. heightInput.style.textAlign = 'right';
  1406. customDiv.appendChild(heightInput);
  1407. mxUtils.write(customDiv, ' in');
  1408. formatDiv.style.display = 'none';
  1409. customDiv.style.display = 'none';
  1410. var pf = new Object();
  1411. var formats = PageSetupDialog.getFormats();
  1412. for (var i = 0; i < formats.length; i++)
  1413. {
  1414. var f = formats[i];
  1415. pf[f.key] = f;
  1416. var paperSizeOption = document.createElement('option');
  1417. paperSizeOption.setAttribute('value', f.key);
  1418. mxUtils.write(paperSizeOption, f.title);
  1419. paperSizeSelect.appendChild(paperSizeOption);
  1420. }
  1421. var customSize = false;
  1422. function listener(sender, evt, force)
  1423. {
  1424. if (force || (widthInput != document.activeElement && heightInput != document.activeElement))
  1425. {
  1426. var detected = false;
  1427. for (var i = 0; i < formats.length; i++)
  1428. {
  1429. var f = formats[i];
  1430. // Special case where custom was chosen
  1431. if (customSize)
  1432. {
  1433. if (f.key == 'custom')
  1434. {
  1435. paperSizeSelect.value = f.key;
  1436. customSize = false;
  1437. }
  1438. }
  1439. else if (f.format != null)
  1440. {
  1441. // Fixes wrong values for previous A4 and A5 page sizes
  1442. if (f.key == 'a4')
  1443. {
  1444. if (pageFormat.width == 826)
  1445. {
  1446. pageFormat = mxRectangle.fromRectangle(pageFormat);
  1447. pageFormat.width = 827;
  1448. }
  1449. else if (pageFormat.height == 826)
  1450. {
  1451. pageFormat = mxRectangle.fromRectangle(pageFormat);
  1452. pageFormat.height = 827;
  1453. }
  1454. }
  1455. else if (f.key == 'a5')
  1456. {
  1457. if (pageFormat.width == 584)
  1458. {
  1459. pageFormat = mxRectangle.fromRectangle(pageFormat);
  1460. pageFormat.width = 583;
  1461. }
  1462. else if (pageFormat.height == 584)
  1463. {
  1464. pageFormat = mxRectangle.fromRectangle(pageFormat);
  1465. pageFormat.height = 583;
  1466. }
  1467. }
  1468. if (pageFormat.width == f.format.width && pageFormat.height == f.format.height)
  1469. {
  1470. paperSizeSelect.value = f.key;
  1471. portraitCheckBox.setAttribute('checked', 'checked');
  1472. portraitCheckBox.defaultChecked = true;
  1473. portraitCheckBox.checked = true;
  1474. landscapeCheckBox.removeAttribute('checked');
  1475. landscapeCheckBox.defaultChecked = false;
  1476. landscapeCheckBox.checked = false;
  1477. detected = true;
  1478. }
  1479. else if (pageFormat.width == f.format.height && pageFormat.height == f.format.width)
  1480. {
  1481. paperSizeSelect.value = f.key;
  1482. portraitCheckBox.removeAttribute('checked');
  1483. portraitCheckBox.defaultChecked = false;
  1484. portraitCheckBox.checked = false;
  1485. landscapeCheckBox.setAttribute('checked', 'checked');
  1486. landscapeCheckBox.defaultChecked = true;
  1487. landscapeCheckBox.checked = true;
  1488. detected = true;
  1489. }
  1490. }
  1491. }
  1492. // Selects custom format which is last in list
  1493. if (!detected)
  1494. {
  1495. widthInput.value = pageFormat.width / 100;
  1496. heightInput.value = pageFormat.height / 100;
  1497. portraitCheckBox.setAttribute('checked', 'checked');
  1498. paperSizeSelect.value = 'custom';
  1499. formatDiv.style.display = 'none';
  1500. customDiv.style.display = '';
  1501. }
  1502. else
  1503. {
  1504. formatDiv.style.display = '';
  1505. customDiv.style.display = 'none';
  1506. }
  1507. }
  1508. };
  1509. listener();
  1510. div.appendChild(paperSizeSelect);
  1511. mxUtils.br(div);
  1512. div.appendChild(formatDiv);
  1513. div.appendChild(customDiv);
  1514. var currentPageFormat = pageFormat;
  1515. var update = function(evt, selectChanged)
  1516. {
  1517. var f = pf[paperSizeSelect.value];
  1518. if (f.format != null)
  1519. {
  1520. widthInput.value = f.format.width / 100;
  1521. heightInput.value = f.format.height / 100;
  1522. customDiv.style.display = 'none';
  1523. formatDiv.style.display = '';
  1524. }
  1525. else
  1526. {
  1527. formatDiv.style.display = 'none';
  1528. customDiv.style.display = '';
  1529. }
  1530. var wi = parseFloat(widthInput.value);
  1531. if (isNaN(wi) || wi <= 0)
  1532. {
  1533. widthInput.value = pageFormat.width / 100;
  1534. }
  1535. var hi = parseFloat(heightInput.value);
  1536. if (isNaN(hi) || hi <= 0)
  1537. {
  1538. heightInput.value = pageFormat.height / 100;
  1539. }
  1540. var newPageFormat = new mxRectangle(0, 0,
  1541. Math.floor(parseFloat(widthInput.value) * 100),
  1542. Math.floor(parseFloat(heightInput.value) * 100));
  1543. if (paperSizeSelect.value != 'custom' && landscapeCheckBox.checked)
  1544. {
  1545. newPageFormat = new mxRectangle(0, 0, newPageFormat.height, newPageFormat.width);
  1546. }
  1547. // Initial select of custom should not update page format to avoid update of combo
  1548. if ((!selectChanged || !customSize) && (newPageFormat.width != currentPageFormat.width ||
  1549. newPageFormat.height != currentPageFormat.height))
  1550. {
  1551. currentPageFormat = newPageFormat;
  1552. // Updates page format and reloads format panel
  1553. if (pageFormatListener != null)
  1554. {
  1555. pageFormatListener(currentPageFormat);
  1556. }
  1557. }
  1558. };
  1559. mxEvent.addListener(portraitSpan, 'click', function(evt)
  1560. {
  1561. portraitCheckBox.checked = true;
  1562. update(evt);
  1563. mxEvent.consume(evt);
  1564. });
  1565. mxEvent.addListener(landscapeSpan, 'click', function(evt)
  1566. {
  1567. landscapeCheckBox.checked = true;
  1568. update(evt);
  1569. mxEvent.consume(evt);
  1570. });
  1571. mxEvent.addListener(widthInput, 'blur', update);
  1572. mxEvent.addListener(widthInput, 'click', update);
  1573. mxEvent.addListener(heightInput, 'blur', update);
  1574. mxEvent.addListener(heightInput, 'click', update);
  1575. mxEvent.addListener(landscapeCheckBox, 'change', update);
  1576. mxEvent.addListener(portraitCheckBox, 'change', update);
  1577. mxEvent.addListener(paperSizeSelect, 'change', function(evt)
  1578. {
  1579. // Handles special case where custom was chosen
  1580. customSize = paperSizeSelect.value == 'custom';
  1581. update(evt, true);
  1582. });
  1583. update();
  1584. return {set: function(value)
  1585. {
  1586. pageFormat = value;
  1587. listener(null, null, true);
  1588. },get: function()
  1589. {
  1590. return currentPageFormat;
  1591. }, widthInput: widthInput,
  1592. heightInput: heightInput};
  1593. };
  1594. /**
  1595. *
  1596. */
  1597. PageSetupDialog.getFormats = function()
  1598. {
  1599. return [{key: 'letter', title: 'US-Letter (8,5" x 11")', format: mxConstants.PAGE_FORMAT_LETTER_PORTRAIT},
  1600. {key: 'legal', title: 'US-Legal (8,5" x 14")', format: new mxRectangle(0, 0, 850, 1400)},
  1601. {key: 'tabloid', title: 'US-Tabloid (11" x 17")', format: new mxRectangle(0, 0, 1100, 1700)},
  1602. {key: 'executive', title: 'US-Executive (7" x 10")', format: new mxRectangle(0, 0, 700, 1000)},
  1603. {key: 'a0', title: 'A0 (841 mm x 1189 mm)', format: new mxRectangle(0, 0, 3300, 4681)},
  1604. {key: 'a1', title: 'A1 (594 mm x 841 mm)', format: new mxRectangle(0, 0, 2339, 3300)},
  1605. {key: 'a2', title: 'A2 (420 mm x 594 mm)', format: new mxRectangle(0, 0, 1654, 2336)},
  1606. {key: 'a3', title: 'A3 (297 mm x 420 mm)', format: new mxRectangle(0, 0, 1169, 1654)},
  1607. {key: 'a4', title: 'A4 (210 mm x 297 mm)', format: mxConstants.PAGE_FORMAT_A4_PORTRAIT},
  1608. {key: 'a5', title: 'A5 (148 mm x 210 mm)', format: new mxRectangle(0, 0, 583, 827)},
  1609. {key: 'a6', title: 'A6 (105 mm x 148 mm)', format: new mxRectangle(0, 0, 413, 583)},
  1610. {key: 'a7', title: 'A7 (74 mm x 105 mm)', format: new mxRectangle(0, 0, 291, 413)},
  1611. {key: 'b4', title: 'B4 (250 mm x 353 mm)', format: new mxRectangle(0, 0, 980, 1390)},
  1612. {key: 'b5', title: 'B5 (176 mm x 250 mm)', format: new mxRectangle(0, 0, 690, 980)},
  1613. {key: '16-9', title: '16:9 (1600 x 900)', format: new mxRectangle(0, 0, 1600, 900)},
  1614. {key: '16-10', title: '16:10 (1920 x 1200)', format: new mxRectangle(0, 0, 1920, 1200)},
  1615. {key: '4-3', title: '4:3 (1600 x 1200)', format: new mxRectangle(0, 0, 1600, 1200)},
  1616. {key: 'custom', title: mxResources.get('custom'), format: null}];
  1617. };
  1618. /**
  1619. * Constructs a new filename dialog.
  1620. */
  1621. var FilenameDialog = function(editorUi, filename, buttonText, fn, label, validateFn, content, helpLink, closeOnBtn, cancelFn, hints, w)
  1622. {
  1623. closeOnBtn = (closeOnBtn != null) ? closeOnBtn : true;
  1624. var row, td;
  1625. var table = document.createElement('table');
  1626. var tbody = document.createElement('tbody');
  1627. table.style.marginTop = '8px';
  1628. row = document.createElement('tr');
  1629. td = document.createElement('td');
  1630. td.style.whiteSpace = 'nowrap';
  1631. td.style.fontSize = '10pt';
  1632. td.style.width = '120px';
  1633. mxUtils.write(td, (label || mxResources.get('filename')) + ':');
  1634. row.appendChild(td);
  1635. var nameInput = document.createElement('input');
  1636. nameInput.setAttribute('value', filename || '');
  1637. nameInput.style.marginLeft = '4px';
  1638. nameInput.style.width = (w != null) ? w + 'px' : '180px';
  1639. var genericBtn = mxUtils.button(buttonText, function()
  1640. {
  1641. if (validateFn == null || validateFn(nameInput.value))
  1642. {
  1643. if (closeOnBtn)
  1644. {
  1645. editorUi.hideDialog();
  1646. }
  1647. fn(nameInput.value);
  1648. }
  1649. });
  1650. genericBtn.className = 'geBtn gePrimaryBtn';
  1651. this.init = function()
  1652. {
  1653. if (label == null && content != null)
  1654. {
  1655. return;
  1656. }
  1657. nameInput.focus();
  1658. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5 || mxClient.IS_QUIRKS)
  1659. {
  1660. nameInput.select();
  1661. }
  1662. else
  1663. {
  1664. document.execCommand('selectAll', false, null);
  1665. }
  1666. // Installs drag and drop handler for links
  1667. if (Graph.fileSupport)
  1668. {
  1669. // Setup the dnd listeners
  1670. var dlg = table.parentNode;
  1671. if (dlg != null)
  1672. {
  1673. var graph = editorUi.editor.graph;
  1674. var dropElt = null;
  1675. mxEvent.addListener(dlg, 'dragleave', function(evt)
  1676. {
  1677. if (dropElt != null)
  1678. {
  1679. dropElt.style.backgroundColor = '';
  1680. dropElt = null;
  1681. }
  1682. evt.stopPropagation();
  1683. evt.preventDefault();
  1684. });
  1685. mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
  1686. {
  1687. // IE 10 does not implement pointer-events so it can't have a drop highlight
  1688. if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10))
  1689. {
  1690. dropElt = nameInput;
  1691. dropElt.style.backgroundColor = '#ebf2f9';
  1692. }
  1693. evt.stopPropagation();
  1694. evt.preventDefault();
  1695. }));
  1696. mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
  1697. {
  1698. if (dropElt != null)
  1699. {
  1700. dropElt.style.backgroundColor = '';
  1701. dropElt = null;
  1702. }
  1703. if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
  1704. {
  1705. nameInput.value = decodeURIComponent(evt.dataTransfer.getData('text/uri-list'));
  1706. genericBtn.click();
  1707. }
  1708. evt.stopPropagation();
  1709. evt.preventDefault();
  1710. }));
  1711. }
  1712. }
  1713. };
  1714. td = document.createElement('td');
  1715. td.style.whiteSpace = 'nowrap';
  1716. td.appendChild(nameInput);
  1717. row.appendChild(td);
  1718. if (label != null || content == null)
  1719. {
  1720. tbody.appendChild(row);
  1721. if (hints != null)
  1722. {
  1723. td.appendChild(FilenameDialog.createTypeHint(editorUi, nameInput, hints));
  1724. }
  1725. }
  1726. if (content != null)
  1727. {
  1728. row = document.createElement('tr');
  1729. td = document.createElement('td');
  1730. td.colSpan = 2;
  1731. td.appendChild(content);
  1732. row.appendChild(td);
  1733. tbody.appendChild(row);
  1734. }
  1735. row = document.createElement('tr');
  1736. td = document.createElement('td');
  1737. td.colSpan = 2;
  1738. td.style.paddingTop = '20px';
  1739. td.style.whiteSpace = 'nowrap';
  1740. td.setAttribute('align', 'right');
  1741. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1742. {
  1743. editorUi.hideDialog();
  1744. if (cancelFn != null)
  1745. {
  1746. cancelFn();
  1747. }
  1748. });
  1749. cancelBtn.className = 'geBtn';
  1750. if (editorUi.editor.cancelFirst)
  1751. {
  1752. td.appendChild(cancelBtn);
  1753. }
  1754. if (helpLink != null)
  1755. {
  1756. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  1757. {
  1758. editorUi.editor.graph.openLink(helpLink);
  1759. });
  1760. helpBtn.className = 'geBtn';
  1761. td.appendChild(helpBtn);
  1762. }
  1763. mxEvent.addListener(nameInput, 'keypress', function(e)
  1764. {
  1765. if (e.keyCode == 13)
  1766. {
  1767. genericBtn.click();
  1768. }
  1769. });
  1770. td.appendChild(genericBtn);
  1771. if (!editorUi.editor.cancelFirst)
  1772. {
  1773. td.appendChild(cancelBtn);
  1774. }
  1775. row.appendChild(td);
  1776. tbody.appendChild(row);
  1777. table.appendChild(tbody);
  1778. this.container = table;
  1779. };
  1780. /**
  1781. *
  1782. */
  1783. FilenameDialog.filenameHelpLink = null;
  1784. /**
  1785. *
  1786. */
  1787. FilenameDialog.createTypeHint = function(ui, nameInput, hints)
  1788. {
  1789. var hint = document.createElement('img');
  1790. hint.style.cssText = 'vertical-align:top;height:16px;width:16px;margin-left:4px;background-repeat:no-repeat;background-position:center bottom;cursor:pointer;';
  1791. mxUtils.setOpacity(hint, 70);
  1792. var nameChanged = function()
  1793. {
  1794. hint.setAttribute('src', Editor.helpImage);
  1795. hint.setAttribute('title', mxResources.get('help'));
  1796. for (var i = 0; i < hints.length; i++)
  1797. {
  1798. if (hints[i].ext.length > 0 &&
  1799. nameInput.value.substring(nameInput.value.length -
  1800. hints[i].ext.length - 1) == '.' + hints[i].ext)
  1801. {
  1802. hint.setAttribute('src', mxClient.imageBasePath + '/warning.png');
  1803. hint.setAttribute('title', mxResources.get(hints[i].title));
  1804. break;
  1805. }
  1806. }
  1807. };
  1808. mxEvent.addListener(nameInput, 'keyup', nameChanged);
  1809. mxEvent.addListener(nameInput, 'change', nameChanged);
  1810. mxEvent.addListener(hint, 'click', function(evt)
  1811. {
  1812. var title = hint.getAttribute('title');
  1813. if (hint.getAttribute('src') == Editor.helpImage)
  1814. {
  1815. ui.editor.graph.openLink(FilenameDialog.filenameHelpLink);
  1816. }
  1817. else if (title != '')
  1818. {
  1819. ui.showError(null, title, mxResources.get('help'), function()
  1820. {
  1821. ui.editor.graph.openLink(FilenameDialog.filenameHelpLink);
  1822. }, null, mxResources.get('ok'), null, null, null, 340, 90);
  1823. }
  1824. mxEvent.consume(evt);
  1825. });
  1826. nameChanged();
  1827. return hint;
  1828. };
  1829. /**
  1830. * Static overrides
  1831. */
  1832. (function()
  1833. {
  1834. // Uses HTML for background pages (to support grid background image)
  1835. mxGraphView.prototype.validateBackgroundPage = function()
  1836. {
  1837. var graph = this.graph;
  1838. if (graph.container != null && !graph.transparentBackground)
  1839. {
  1840. if (graph.pageVisible)
  1841. {
  1842. var bounds = this.getBackgroundPageBounds();
  1843. if (this.backgroundPageShape == null)
  1844. {
  1845. // Finds first element in graph container
  1846. var firstChild = graph.container.firstChild;
  1847. while (firstChild != null && firstChild.nodeType != mxConstants.NODETYPE_ELEMENT)
  1848. {
  1849. firstChild = firstChild.nextSibling;
  1850. }
  1851. if (firstChild != null)
  1852. {
  1853. this.backgroundPageShape = this.createBackgroundPageShape(bounds);
  1854. this.backgroundPageShape.scale = 1;
  1855. // Shadow filter causes problems in outline window in quirks mode. IE8 standards
  1856. // also has known rendering issues inside mxWindow but not using shadow is worse.
  1857. this.backgroundPageShape.isShadow = !mxClient.IS_QUIRKS;
  1858. this.backgroundPageShape.dialect = mxConstants.DIALECT_STRICTHTML;
  1859. this.backgroundPageShape.init(graph.container);
  1860. // Required for the browser to render the background page in correct order
  1861. firstChild.style.position = 'absolute';
  1862. graph.container.insertBefore(this.backgroundPageShape.node, firstChild);
  1863. this.backgroundPageShape.redraw();
  1864. this.backgroundPageShape.node.className = 'geBackgroundPage';
  1865. // Adds listener for double click handling on background
  1866. mxEvent.addListener(this.backgroundPageShape.node, 'dblclick',
  1867. mxUtils.bind(this, function(evt)
  1868. {
  1869. graph.dblClick(evt);
  1870. })
  1871. );
  1872. // Adds basic listeners for graph event dispatching outside of the
  1873. // container and finishing the handling of a single gesture
  1874. mxEvent.addGestureListeners(this.backgroundPageShape.node,
  1875. mxUtils.bind(this, function(evt)
  1876. {
  1877. graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
  1878. }),
  1879. mxUtils.bind(this, function(evt)
  1880. {
  1881. // Hides the tooltip if mouse is outside container
  1882. if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover())
  1883. {
  1884. graph.tooltipHandler.hide();
  1885. }
  1886. if (graph.isMouseDown && !mxEvent.isConsumed(evt))
  1887. {
  1888. graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
  1889. }
  1890. }),
  1891. mxUtils.bind(this, function(evt)
  1892. {
  1893. graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
  1894. })
  1895. );
  1896. }
  1897. }
  1898. else
  1899. {
  1900. this.backgroundPageShape.scale = 1;
  1901. this.backgroundPageShape.bounds = bounds;
  1902. this.backgroundPageShape.redraw();
  1903. }
  1904. }
  1905. else if (this.backgroundPageShape != null)
  1906. {
  1907. this.backgroundPageShape.destroy();
  1908. this.backgroundPageShape = null;
  1909. }
  1910. this.validateBackgroundStyles();
  1911. }
  1912. };
  1913. // Updates the CSS of the background to draw the grid
  1914. mxGraphView.prototype.validateBackgroundStyles = function()
  1915. {
  1916. var graph = this.graph;
  1917. var color = (graph.background == null || graph.background == mxConstants.NONE) ? graph.defaultPageBackgroundColor : graph.background;
  1918. var gridColor = (color != null && this.gridColor != color.toLowerCase()) ? this.gridColor : '#ffffff';
  1919. var image = 'none';
  1920. var position = '';
  1921. if (graph.isGridEnabled())
  1922. {
  1923. var phase = 10;
  1924. if (mxClient.IS_SVG)
  1925. {
  1926. // Generates the SVG required for drawing the dynamic grid
  1927. image = unescape(encodeURIComponent(this.createSvgGrid(gridColor)));
  1928. image = (window.btoa) ? btoa(image) : Base64.encode(image, true);
  1929. image = 'url(' + 'data:image/svg+xml;base64,' + image + ')'
  1930. phase = graph.gridSize * this.scale * this.gridSteps;
  1931. }
  1932. else
  1933. {
  1934. // Fallback to grid wallpaper with fixed size
  1935. image = 'url(' + this.gridImage + ')';
  1936. }
  1937. var x0 = 0;
  1938. var y0 = 0;
  1939. if (graph.view.backgroundPageShape != null)
  1940. {
  1941. var bds = this.getBackgroundPageBounds();
  1942. x0 = 1 + bds.x;
  1943. y0 = 1 + bds.y;
  1944. }
  1945. // Computes the offset to maintain origin for grid
  1946. position = -Math.round(phase - mxUtils.mod(this.translate.x * this.scale - x0, phase)) + 'px ' +
  1947. -Math.round(phase - mxUtils.mod(this.translate.y * this.scale - y0, phase)) + 'px';
  1948. }
  1949. var canvas = graph.view.canvas;
  1950. if (canvas.ownerSVGElement != null)
  1951. {
  1952. canvas = canvas.ownerSVGElement;
  1953. }
  1954. if (graph.view.backgroundPageShape != null)
  1955. {
  1956. graph.view.backgroundPageShape.node.style.backgroundPosition = position;
  1957. graph.view.backgroundPageShape.node.style.backgroundImage = image;
  1958. graph.view.backgroundPageShape.node.style.backgroundColor = color;
  1959. graph.container.className = 'geDiagramContainer geDiagramBackdrop';
  1960. canvas.style.backgroundImage = 'none';
  1961. canvas.style.backgroundColor = '';
  1962. }
  1963. else
  1964. {
  1965. graph.container.className = 'geDiagramContainer';
  1966. canvas.style.backgroundPosition = position;
  1967. canvas.style.backgroundColor = color;
  1968. canvas.style.backgroundImage = image;
  1969. }
  1970. };
  1971. // Returns the SVG required for painting the background grid.
  1972. mxGraphView.prototype.createSvgGrid = function(color)
  1973. {
  1974. var tmp = this.graph.gridSize * this.scale;
  1975. while (tmp < this.minGridSize)
  1976. {
  1977. tmp *= 2;
  1978. }
  1979. var tmp2 = this.gridSteps * tmp;
  1980. // Small grid lines
  1981. var d = [];
  1982. for (var i = 1; i < this.gridSteps; i++)
  1983. {
  1984. var tmp3 = i * tmp;
  1985. d.push('M 0 ' + tmp3 + ' L ' + tmp2 + ' ' + tmp3 + ' M ' + tmp3 + ' 0 L ' + tmp3 + ' ' + tmp2);
  1986. }
  1987. // KNOWN: Rounding errors for certain scales (eg. 144%, 121% in Chrome, FF and Safari). Workaround
  1988. // in Chrome is to use 100% for the svg size, but this results in blurred grid for large diagrams.
  1989. var size = tmp2;
  1990. var svg = '<svg width="' + size + '" height="' + size + '" xmlns="' + mxConstants.NS_SVG + '">' +
  1991. '<defs><pattern id="grid" width="' + tmp2 + '" height="' + tmp2 + '" patternUnits="userSpaceOnUse">' +
  1992. '<path d="' + d.join(' ') + '" fill="none" stroke="' + color + '" opacity="0.2" stroke-width="1"/>' +
  1993. '<path d="M ' + tmp2 + ' 0 L 0 0 0 ' + tmp2 + '" fill="none" stroke="' + color + '" stroke-width="1"/>' +
  1994. '</pattern></defs><rect width="100%" height="100%" fill="url(#grid)"/></svg>';
  1995. return svg;
  1996. };
  1997. // Adds panning for the grid with no page view and disabled scrollbars
  1998. var mxGraphPanGraph = mxGraph.prototype.panGraph;
  1999. mxGraph.prototype.panGraph = function(dx, dy)
  2000. {
  2001. mxGraphPanGraph.apply(this, arguments);
  2002. if (this.shiftPreview1 != null)
  2003. {
  2004. var canvas = this.view.canvas;
  2005. if (canvas.ownerSVGElement != null)
  2006. {
  2007. canvas = canvas.ownerSVGElement;
  2008. }
  2009. var phase = this.gridSize * this.view.scale * this.view.gridSteps;
  2010. var position = -Math.round(phase - mxUtils.mod(this.view.translate.x * this.view.scale + dx, phase)) + 'px ' +
  2011. -Math.round(phase - mxUtils.mod(this.view.translate.y * this.view.scale + dy, phase)) + 'px';
  2012. canvas.style.backgroundPosition = position;
  2013. }
  2014. };
  2015. // Draws page breaks only within the page
  2016. mxGraph.prototype.updatePageBreaks = function(visible, width, height)
  2017. {
  2018. var scale = this.view.scale;
  2019. var tr = this.view.translate;
  2020. var fmt = this.pageFormat;
  2021. var ps = scale * this.pageScale;
  2022. var bounds2 = this.view.getBackgroundPageBounds();
  2023. width = bounds2.width;
  2024. height = bounds2.height;
  2025. var bounds = new mxRectangle(scale * tr.x, scale * tr.y, fmt.width * ps, fmt.height * ps);
  2026. // Does not show page breaks if the scale is too small
  2027. visible = visible && Math.min(bounds.width, bounds.height) > this.minPageBreakDist;
  2028. var horizontalCount = (visible) ? Math.ceil(height / bounds.height) - 1 : 0;
  2029. var verticalCount = (visible) ? Math.ceil(width / bounds.width) - 1 : 0;
  2030. var right = bounds2.x + width;
  2031. var bottom = bounds2.y + height;
  2032. if (this.horizontalPageBreaks == null && horizontalCount > 0)
  2033. {
  2034. this.horizontalPageBreaks = [];
  2035. }
  2036. if (this.verticalPageBreaks == null && verticalCount > 0)
  2037. {
  2038. this.verticalPageBreaks = [];
  2039. }
  2040. var drawPageBreaks = mxUtils.bind(this, function(breaks)
  2041. {
  2042. if (breaks != null)
  2043. {
  2044. var count = (breaks == this.horizontalPageBreaks) ? horizontalCount : verticalCount;
  2045. for (var i = 0; i <= count; i++)
  2046. {
  2047. var pts = (breaks == this.horizontalPageBreaks) ?
  2048. [new mxPoint(Math.round(bounds2.x), Math.round(bounds2.y + (i + 1) * bounds.height)),
  2049. new mxPoint(Math.round(right), Math.round(bounds2.y + (i + 1) * bounds.height))] :
  2050. [new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bounds2.y)),
  2051. new mxPoint(Math.round(bounds2.x + (i + 1) * bounds.width), Math.round(bottom))];
  2052. if (breaks[i] != null)
  2053. {
  2054. breaks[i].points = pts;
  2055. breaks[i].redraw();
  2056. }
  2057. else
  2058. {
  2059. var pageBreak = new mxPolyline(pts, this.pageBreakColor);
  2060. pageBreak.dialect = this.dialect;
  2061. pageBreak.isDashed = this.pageBreakDashed;
  2062. pageBreak.pointerEvents = false;
  2063. pageBreak.init(this.view.backgroundPane);
  2064. pageBreak.redraw();
  2065. breaks[i] = pageBreak;
  2066. }
  2067. }
  2068. for (var i = count; i < breaks.length; i++)
  2069. {
  2070. breaks[i].destroy();
  2071. }
  2072. breaks.splice(count, breaks.length - count);
  2073. }
  2074. });
  2075. drawPageBreaks(this.horizontalPageBreaks);
  2076. drawPageBreaks(this.verticalPageBreaks);
  2077. };
  2078. // Disables removing relative children from parents
  2079. var mxGraphHandlerShouldRemoveCellsFromParent = mxGraphHandler.prototype.shouldRemoveCellsFromParent;
  2080. mxGraphHandler.prototype.shouldRemoveCellsFromParent = function(parent, cells, evt)
  2081. {
  2082. for (var i = 0; i < cells.length; i++)
  2083. {
  2084. if (this.graph.getModel().isVertex(cells[i]))
  2085. {
  2086. var geo = this.graph.getCellGeometry(cells[i]);
  2087. if (geo != null && geo.relative)
  2088. {
  2089. return false;
  2090. }
  2091. }
  2092. }
  2093. return mxGraphHandlerShouldRemoveCellsFromParent.apply(this, arguments);
  2094. };
  2095. // Overrides to ignore hotspot only for target terminal
  2096. var mxConnectionHandlerCreateMarker = mxConnectionHandler.prototype.createMarker;
  2097. mxConnectionHandler.prototype.createMarker = function()
  2098. {
  2099. var marker = mxConnectionHandlerCreateMarker.apply(this, arguments);
  2100. marker.intersects = mxUtils.bind(this, function(state, evt)
  2101. {
  2102. if (this.isConnecting())
  2103. {
  2104. return true;
  2105. }
  2106. return mxCellMarker.prototype.intersects.apply(marker, arguments);
  2107. });
  2108. return marker;
  2109. };
  2110. // Creates background page shape
  2111. mxGraphView.prototype.createBackgroundPageShape = function(bounds)
  2112. {
  2113. return new mxRectangleShape(bounds, '#ffffff', this.graph.defaultPageBorderColor);
  2114. };
  2115. // Fits the number of background pages to the graph
  2116. mxGraphView.prototype.getBackgroundPageBounds = function()
  2117. {
  2118. var gb = this.getGraphBounds();
  2119. // Computes unscaled, untranslated graph bounds
  2120. var x = (gb.width > 0) ? gb.x / this.scale - this.translate.x : 0;
  2121. var y = (gb.height > 0) ? gb.y / this.scale - this.translate.y : 0;
  2122. var w = gb.width / this.scale;
  2123. var h = gb.height / this.scale;
  2124. var fmt = this.graph.pageFormat;
  2125. var ps = this.graph.pageScale;
  2126. var pw = fmt.width * ps;
  2127. var ph = fmt.height * ps;
  2128. var x0 = Math.floor(Math.min(0, x) / pw);
  2129. var y0 = Math.floor(Math.min(0, y) / ph);
  2130. var xe = Math.ceil(Math.max(1, x + w) / pw);
  2131. var ye = Math.ceil(Math.max(1, y + h) / ph);
  2132. var rows = xe - x0;
  2133. var cols = ye - y0;
  2134. var bounds = new mxRectangle(this.scale * (this.translate.x + x0 * pw), this.scale *
  2135. (this.translate.y + y0 * ph), this.scale * rows * pw, this.scale * cols * ph);
  2136. return bounds;
  2137. };
  2138. // Add panning for background page in VML
  2139. var graphPanGraph = mxGraph.prototype.panGraph;
  2140. mxGraph.prototype.panGraph = function(dx, dy)
  2141. {
  2142. graphPanGraph.apply(this, arguments);
  2143. if ((this.dialect != mxConstants.DIALECT_SVG && this.view.backgroundPageShape != null) &&
  2144. (!this.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.container)))
  2145. {
  2146. this.view.backgroundPageShape.node.style.marginLeft = dx + 'px';
  2147. this.view.backgroundPageShape.node.style.marginTop = dy + 'px';
  2148. }
  2149. };
  2150. /**
  2151. * Consumes click events for disabled menu items.
  2152. */
  2153. var mxPopupMenuAddItem = mxPopupMenu.prototype.addItem;
  2154. mxPopupMenu.prototype.addItem = function(title, image, funct, parent, iconCls, enabled)
  2155. {
  2156. var result = mxPopupMenuAddItem.apply(this, arguments);
  2157. if (enabled != null && !enabled)
  2158. {
  2159. mxEvent.addListener(result, 'mousedown', function(evt)
  2160. {
  2161. mxEvent.consume(evt);
  2162. });
  2163. }
  2164. return result;
  2165. };
  2166. // Selects ancestors before descendants
  2167. var graphHandlerGetInitialCellForEvent = mxGraphHandler.prototype.getInitialCellForEvent;
  2168. mxGraphHandler.prototype.getInitialCellForEvent = function(me)
  2169. {
  2170. var model = this.graph.getModel();
  2171. var psel = model.getParent(this.graph.getSelectionCell());
  2172. var cell = graphHandlerGetInitialCellForEvent.apply(this, arguments);
  2173. var parent = model.getParent(cell);
  2174. if (psel == null || (psel != cell && psel != parent))
  2175. {
  2176. while (!this.graph.isCellSelected(cell) && !this.graph.isCellSelected(parent) &&
  2177. model.isVertex(parent) && !this.graph.isContainer(parent))
  2178. {
  2179. cell = parent;
  2180. parent = this.graph.getModel().getParent(cell);
  2181. }
  2182. }
  2183. return cell;
  2184. };
  2185. // Selection is delayed to mouseup if ancestor is selected
  2186. var graphHandlerIsDelayedSelection = mxGraphHandler.prototype.isDelayedSelection;
  2187. mxGraphHandler.prototype.isDelayedSelection = function(cell, me)
  2188. {
  2189. var result = graphHandlerIsDelayedSelection.apply(this, arguments);
  2190. if (!result)
  2191. {
  2192. var model = this.graph.getModel();
  2193. var parent = model.getParent(cell);
  2194. while (parent != null)
  2195. {
  2196. // Inconsistency for unselected parent swimlane is intended for easier moving
  2197. // of stack layouts where the container title section is too far away
  2198. if (this.graph.isCellSelected(parent) && model.isVertex(parent))
  2199. {
  2200. result = true;
  2201. break;
  2202. }
  2203. parent = model.getParent(parent);
  2204. }
  2205. }
  2206. return result;
  2207. };
  2208. // Delayed selection of parent group
  2209. mxGraphHandler.prototype.selectDelayed = function(me)
  2210. {
  2211. if (!this.graph.popupMenuHandler.isPopupTrigger(me))
  2212. {
  2213. var cell = me.getCell();
  2214. if (cell == null)
  2215. {
  2216. cell = this.cell;
  2217. }
  2218. // Selects folded cell for hit on folding icon
  2219. var state = this.graph.view.getState(cell)
  2220. if (state != null && me.isSource(state.control))
  2221. {
  2222. this.graph.selectCellForEvent(cell, me.getEvent());
  2223. }
  2224. else
  2225. {
  2226. var model = this.graph.getModel();
  2227. var parent = model.getParent(cell);
  2228. while (!this.graph.isCellSelected(parent) && model.isVertex(parent))
  2229. {
  2230. cell = parent;
  2231. parent = model.getParent(cell);
  2232. }
  2233. this.graph.selectCellForEvent(cell, me.getEvent());
  2234. }
  2235. }
  2236. };
  2237. // Returns last selected ancestor
  2238. mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
  2239. {
  2240. var cell = me.getCell();
  2241. var model = this.graph.getModel();
  2242. var parent = model.getParent(cell);
  2243. while (model.isVertex(parent) && !this.graph.isContainer(parent))
  2244. {
  2245. if (this.graph.isCellSelected(parent))
  2246. {
  2247. cell = parent;
  2248. }
  2249. parent = model.getParent(parent);
  2250. }
  2251. return cell;
  2252. };
  2253. })();