Editor.js 87 KB

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