Editor.js 166 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152
  1. /**
  2. * Copyright (c) 2006-2017, JGraph Ltd
  3. * Copyright (c) 2006-2017, Gaudenz Alder
  4. */
  5. (function()
  6. {
  7. /**
  8. * Specifies the app name. Default is document.title.
  9. */
  10. Editor.prototype.appName = 'draw.io';
  11. /**
  12. * Known extensions for own files.
  13. */
  14. Editor.prototype.fileExtensions = [
  15. {ext: 'html', title: 'filetypeHtml'},
  16. {ext: 'png', title: 'filetypePng'},
  17. {ext: 'svg', title: 'filetypeSvg'}];
  18. /**
  19. * Used in the GraphViewer lightbox.
  20. */
  21. Editor.closeImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/delete.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZCAMAAADzN3VRAAAApVBMVEUAAAD////k5OT///8AAAB1dXXMzMz9/f39/f37+/v5+fn+/v7///9iYmJaWlqFhYWnp6ejo6OHh4f////////////////7+/v5+fnx8fH///8AAAD///8bGxv7+/v5+fkoKCghISFDQ0MYGBjh4eHY2Njb29tQUFBvb29HR0c/Pz82NjYrKyu/v78SEhLu7u7s7OzV1dVVVVU7OzsVFRXAv78QEBBzqehMAAAAG3RSTlMAA/7p/vz5xZlrTiPL/v78+/v7+OXd2TYQDs8L70ZbAAABKUlEQVQoz3VS13LCMBBUXHChd8iukDslQChJ/v/TchaG4cXS+OSb1c7trU7V60OpdRz2ZtNZL4zXNlcN8BEtSG6+NxIXkeRPoBuQ1cjvZ31/VJFB10ISli6diYfH8iYO3WUNCcNlB0gTrXOtkxTo0O1aKKiBBMhhv2MNBQKoiA5wxlZo0JDzD3AYKbWacyj3fs01wxey0pyEP+R8pWKWXoqtIZ0DDg5pbki9krEKOa6LVDQsdoXEsi46Zqh69KFz7B1u7Hb2yDV8firXDKBlZ4UFiswKGRhXTS93/ECK7yxnJ3+S3y/ThpO+cfSD017nqa18aasabU0/t7d+tk0/1oMEJ1NaD67iwdF68OabFSLn+eHb0+vjy+uk8br9fdrftH0O2menfd7+AQfYM/lNjoDHAAAAAElFTkSuQmCC';
  22. /**
  23. *
  24. */
  25. Editor.plusImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/plus.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDdCMTdENjVCOEM4MTFFNDlCRjVBNDdCODU5NjNBNUMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDdCMTdENjZCOEM4MTFFNDlCRjVBNDdCODU5NjNBNUMiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowN0IxN0Q2M0I4QzgxMUU0OUJGNUE0N0I4NTk2M0E1QyIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowN0IxN0Q2NEI4QzgxMUU0OUJGNUE0N0I4NTk2M0E1QyIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PtjrjmgAAAAtSURBVHjaYvz//z8DMigvLwcLdHZ2MiKLMzEQCaivkLGsrOw/dU0cAr4GCDAARQsQbTFrv10AAAAASUVORK5CYII=';
  26. /**
  27. *
  28. */
  29. Editor.spinImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/spin.gif' : 'data:image/gif;base64,R0lGODlhDAAMAPUxAEVriVp7lmCAmmGBm2OCnGmHn3OPpneSqYKbr4OcsIScsI2kto6kt46lt5KnuZmtvpquvpuvv56ywaCzwqK1xKu7yay9yq+/zLHAzbfF0bjG0bzJ1LzK1MDN18jT28nT3M3X3tHa4dTc49Xd5Njf5dng5t3k6d/l6uDm6uru8e7x8/Dz9fT29/b4+Pj5+fj5+vr6+v///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkKADEAIf8LTkVUU0NBUEUyLjADAQAAACwAAAAADAAMAAAGR8CYcEgsOgYAIax4CCQuQldrCBEsiK8VS2hoFGOrlJDA+cZQwkLnqyoJFZKviSS0ICrE0ec0jDAwIiUeGyBFGhMPFBkhZo1BACH5BAkKAC4ALAAAAAAMAAwAhVB0kFR3k1V4k2CAmmWEnW6Lo3KOpXeSqH2XrIOcsISdsImhtIqhtJCmuJGnuZuwv52wwJ+ywZ+ywqm6yLHBzbLCzrXEz7fF0LnH0rrI0r7L1b/M1sXR2cfT28rV3czW3s/Z4Nfe5Nvi6ODm6uLn6+Ln7OLo7OXq7efs7+zw8u/y9PDy9PX3+Pr7+////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZDQJdwSCxGDAIAoVFkFBwYSyIwGE4OkCJxIdG6WkJEx8sSKj7elfBB0a5SQg1EQ0SVVMPKhDM6iUIkRR4ZFxsgJl6JQQAh+QQJCgAxACwAAAAADAAMAIVGa4lcfZdjgpxkg51nhp5ui6N3kqh5lKqFnbGHn7KIoLOQp7iRp7mSqLmTqbqarr6br7+fssGitcOitcSuvsuuv8uwwMyzw861xNC5x9K6x9K/zNbDztjE0NnG0drJ1NzQ2eDS2+LT2+LV3ePZ4Oba4ebb4ufc4+jm6+7t8PLt8PPt8fPx8/Xx9PX09vf19/j3+Pn///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ8CYcEgsUhQFggFSjCQmnE1jcBhqGBXiIuAQSi7FGEIgfIzCFoCXFCZiPO0hKBMiwl7ET6eUYqlWLkUnISImKC1xbUEAIfkECQoAMgAsAAAAAAwADACFTnKPT3KPVHaTYoKcb4yjcY6leZSpf5mtgZuvh5+yiqG0i6K1jqW3kae5nrHBnrLBn7LCoLPCobTDqbrIqrvIs8LOtMPPtcPPtcTPuMbRucfSvcrUvsvVwMzWxdHaydTcytXdzNbezdff0drh2ODl2+Ln3eTp4Obq4ujs5Ont5uvu6O3w6u7w6u7x7/L09vj5+vr7+vv7////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkdAmXBILHIcicOCUqxELKKPxKAYgiYd4oMAEWo8RVmjIMScwhmBcJMKXwLCECmMGAhPI1QRwBiaSixCMDFhLSorLi8wYYxCQQAh+QQJCgAxACwAAAAADAAMAIVZepVggJphgZtnhp5vjKN2kah3kqmBmq+KobSLorWNpLaRp7mWq7ybr7+gs8KitcSktsWnuManucexwM2ywc63xtG6yNO9ytS+ytW/zNbDz9jH0tvL1d3N197S2+LU3OPU3ePV3eTX3+Xa4efb4ufd5Onl6u7r7vHs7/Lt8PLw8/Xy9Pby9fb09ff2+Pn3+Pn6+vr///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGSMCYcEgseiwSR+RS7GA4JFGF8RiWNiEiJTERgkjFGAQh/KTCGoJwpApnBkITKrwoCFWnFlEhaAxXLC9CBwAGRS4wQgELYY1CQQAh+QQJCgAzACwAAAAADAAMAIVMcI5SdZFhgZtti6JwjaR4k6mAma6Cm6+KobSLorWLo7WNo7aPpredsMCescGitMOitcSmuMaqu8ixwc2zws63xdC4xtG5x9K9ytXAzdfCztjF0NnF0drK1d3M1t7P2N/P2eDT2+LX3+Xe5Onh5+vi5+vj6Ozk6e3n7O/o7O/q7vHs7/Lt8PPu8fPx8/X3+Pn6+vv7+/v8/Pz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRcCZcEgsmkIbTOZTLIlGqZNnchm2SCgiJ6IRqljFmQUiXIVnoITQde4chC9Y+LEQxmTFRkFSNFAqDAMIRQoCAAEEDmeLQQAh+QQJCgAwACwAAAAADAAMAIVXeZRefplff5lhgZtph59yjqV2kaeAmq6FnbGFnrGLorWNpLaQp7mRqLmYrb2essGgs8Klt8apusitvcquv8u2xNC7yNO8ydS8ytTAzdfBzdfM1t7N197Q2eDU3OPX3+XZ4ObZ4ebc4+jf5erg5erg5uvp7fDu8fPv8vTz9fb09vf19/j3+Pn4+fn5+vr6+/v///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRUCYcEgspkwjEKhUVJ1QsBNp0xm2VixiSOMRvlxFGAcTJook5eEHIhQcwpWIkAFQECkNy9AQWFwyEAkPRQ4FAwQIE2llQQAh+QQJCgAvACwAAAAADAAMAIVNcY5SdZFigptph6BvjKN0kKd8lquAmq+EnbGGn7KHn7ONpLaOpbearr+csMCdscCescGhtMOnuMauvsuzws60w862xdC9ytW/y9a/zNbCztjG0drH0tvK1N3M1t7N19/U3ePb4uff5urj6Ozk6e3l6u7m6u7o7PDq7vDt8PPv8vTw8vTw8/X19vf6+vv///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ8CXcEgsvlytVUplJLJIpSEDUESFTELBwSgCCQEV42kjDFiMo4uQsDB2MkLHoEHUTD7DRAHC8VAiZ0QSCgYIDxhNiUEAOw==';
  30. /**
  31. *
  32. */
  33. Editor.globeImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTEuOTkgMkM2LjQ3IDIgMiA2LjQ4IDIgMTJzNC40NyAxMCA5Ljk5IDEwQzE3LjUyIDIyIDIyIDE3LjUyIDIyIDEyUzE3LjUyIDIgMTEuOTkgMnptNi45MyA2aC0yLjk1Yy0uMzItMS4yNS0uNzgtMi40NS0xLjM4LTMuNTYgMS44NC42MyAzLjM3IDEuOTEgNC4zMyAzLjU2ek0xMiA0LjA0Yy44MyAxLjIgMS40OCAyLjUzIDEuOTEgMy45NmgtMy44MmMuNDMtMS40MyAxLjA4LTIuNzYgMS45MS0zLjk2ek00LjI2IDE0QzQuMSAxMy4zNiA0IDEyLjY5IDQgMTJzLjEtMS4zNi4yNi0yaDMuMzhjLS4wOC42Ni0uMTQgMS4zMi0uMTQgMiAwIC42OC4wNiAxLjM0LjE0IDJINC4yNnptLjgyIDJoMi45NWMuMzIgMS4yNS43OCAyLjQ1IDEuMzggMy41Ni0xLjg0LS42My0zLjM3LTEuOS00LjMzLTMuNTZ6bTIuOTUtOEg1LjA4Yy45Ni0xLjY2IDIuNDktMi45MyA0LjMzLTMuNTZDOC44MSA1LjU1IDguMzUgNi43NSA4LjAzIDh6TTEyIDE5Ljk2Yy0uODMtMS4yLTEuNDgtMi41My0xLjkxLTMuOTZoMy44MmMtLjQzIDEuNDMtMS4wOCAyLjc2LTEuOTEgMy45NnpNMTQuMzQgMTRIOS42NmMtLjA5LS42Ni0uMTYtMS4zMi0uMTYtMiAwLS42OC4wNy0xLjM1LjE2LTJoNC42OGMuMDkuNjUuMTYgMS4zMi4xNiAyIDAgLjY4LS4wNyAxLjM0LS4xNiAyem0uMjUgNS41NmMuNi0xLjExIDEuMDYtMi4zMSAxLjM4LTMuNTZoMi45NWMtLjk2IDEuNjUtMi40OSAyLjkzLTQuMzMgMy41NnpNMTYuMzYgMTRjLjA4LS42Ni4xNC0xLjMyLjE0LTIgMC0uNjgtLjA2LTEuMzQtLjE0LTJoMy4zOGMuMTYuNjQuMjYgMS4zMS4yNiAycy0uMSAxLjM2LS4yNiAyaC0zLjM4eiIvPjwvc3ZnPg==';
  34. /**
  35. *
  36. */
  37. Editor.commentImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMjEuOTkgNGMwLTEuMS0uODktMi0xLjk5LTJINGMtMS4xIDAtMiAuOS0yIDJ2MTJjMCAxLjEuOSAyIDIgMmgxNGw0IDQtLjAxLTE4ek0xOCAxNEg2di0yaDEydjJ6bTAtM0g2VjloMTJ2MnptMC0zSDZWNmgxMnYyeiIvPjxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz48L3N2Zz4=';
  38. /**
  39. *
  40. */
  41. Editor.commentImageInverted = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABLElEQVRYR+2Wvy4FQRjFf4dINAq9XqtSaVRqXArPINEodUqlhxC5/pU6nYdQSHQeQTRHNtmVuXuXrIxv1k1sN5vMOb85c75kxMCfBvZnCsD2ErAGzAfAvUt6THUnAGwfAWfAQoB5I3kh6aBZfALYXgGeg80b31VJT9UiBRgB48CTp9Lbku7aAPvAZSGAHUm3swEgKWtUbbsj1f4JDA4AbGb24iErgUzzr7bvSrrpVcKgK5ghgKAO9E/gvwNBJRxJuu41BUEd+BFARA3+JsAWcB9x3A7NzgSqt+ALsFwAYhqgMrW9Ub8J14G5QJBugAhD2yfAaUt7T9LVxBhGmDeato/rZJtfZQHq600hygPUEIfAOTAMQALxWrQD7X7ZXpT0VqyE3xU868n9G5PzASPvpiHavBAUAAAAAElFTkSuQmCC';
  42. /**
  43. *
  44. */
  45. Editor.userImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgMTJjMi4yMSAwIDQtMS43OSA0LTRzLTEuNzktNC00LTQtNCAxLjc5LTQgNCAxLjc5IDQgNCA0em0wIDJjLTIuNjcgMC04IDEuMzQtOCA0djJoMTZ2LTJjMC0yLjY2LTUuMzMtNC04LTR6Ii8+PC9zdmc+';
  46. /**
  47. *
  48. */
  49. Editor.shareImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTggMTYuMDhjLS43NiAwLTEuNDQuMy0xLjk2Ljc3TDguOTEgMTIuN2MuMDUtLjIzLjA5LS40Ni4wOS0uN3MtLjA0LS40Ny0uMDktLjdsNy4wNS00LjExYy41NC41IDEuMjUuODEgMi4wNC44MSAxLjY2IDAgMy0xLjM0IDMtM3MtMS4zNC0zLTMtMy0zIDEuMzQtMyAzYzAgLjI0LjA0LjQ3LjA5LjdMOC4wNCA5LjgxQzcuNSA5LjMxIDYuNzkgOSA2IDljLTEuNjYgMC0zIDEuMzQtMyAzczEuMzQgMyAzIDNjLjc5IDAgMS41LS4zMSAyLjA0LS44MWw3LjEyIDQuMTZjLS4wNS4yMS0uMDguNDMtLjA4LjY1IDAgMS42MSAxLjMxIDIuOTIgMi45MiAyLjkyIDEuNjEgMCAyLjkyLTEuMzEgMi45Mi0yLjkycy0xLjMxLTIuOTItMi45Mi0yLjkyeiIvPjwvc3ZnPg==';
  50. /**
  51. *
  52. */
  53. Editor.syncImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTIgNFYxTDggNWw0IDRWNmMzLjMxIDAgNiAyLjY5IDYgNiAwIDEuMDEtLjI1IDEuOTctLjcgMi44bDEuNDYgMS40NkMxOS41NCAxNS4wMyAyMCAxMy41NyAyMCAxMmMwLTQuNDItMy41OC04LTgtOHptMCAxNGMtMy4zMSAwLTYtMi42OS02LTYgMC0xLjAxLjI1LTEuOTcuNy0yLjhMNS4yNCA3Ljc0QzQuNDYgOC45NyA0IDEwLjQzIDQgMTJjMCA0LjQyIDMuNTggOCA4IDh2M2w0LTQtNC00djN6Ii8+PC9zdmc+';
  54. /**
  55. *
  56. */
  57. Editor.syncDisabledImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTAgNi4zNVY0LjI2Yy0uOC4yMS0xLjU1LjU0LTIuMjMuOTZsMS40NiAxLjQ2Yy4yNS0uMTIuNS0uMjQuNzctLjMzem0tNy4xNC0uOTRsMi4zNiAyLjM2QzQuNDUgOC45OSA0IDEwLjQ0IDQgMTJjMCAyLjIxLjkxIDQuMiAyLjM2IDUuNjRMNCAyMGg2di02bC0yLjI0IDIuMjRDNi42OCAxNS4xNSA2IDEzLjY2IDYgMTJjMC0xIC4yNS0xLjk0LjY4LTIuNzdsOC4wOCA4LjA4Yy0uMjUuMTMtLjUuMjUtLjc3LjM0djIuMDljLjgtLjIxIDEuNTUtLjU0IDIuMjMtLjk2bDIuMzYgMi4zNiAxLjI3LTEuMjdMNC4xNCA0LjE0IDIuODYgNS40MXpNMjAgNGgtNnY2bDIuMjQtMi4yNEMxNy4zMiA4Ljg1IDE4IDEwLjM0IDE4IDEyYzAgMS0uMjUgMS45NC0uNjggMi43N2wxLjQ2IDEuNDZDMTkuNTUgMTUuMDEgMjAgMTMuNTYgMjAgMTJjMC0yLjIxLS45MS00LjItMi4zNi01LjY0TDIwIDR6Ii8+PC9zdmc+';
  58. /**
  59. *
  60. */
  61. Editor.syncProblemImage = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMyAxMmMwIDIuMjEuOTEgNC4yIDIuMzYgNS42NEwzIDIwaDZ2LTZsLTIuMjQgMi4yNEM1LjY4IDE1LjE1IDUgMTMuNjYgNSAxMmMwLTIuNjEgMS42Ny00LjgzIDQtNS42NVY0LjI2QzUuNTUgNS4xNSAzIDguMjcgMyAxMnptOCA1aDJ2LTJoLTJ2MnpNMjEgNGgtNnY2bDIuMjQtMi4yNEMxOC4zMiA4Ljg1IDE5IDEwLjM0IDE5IDEyYzAgMi42MS0xLjY3IDQuODMtNCA1LjY1djIuMDljMy40NS0uODkgNi00LjAxIDYtNy43NCAwLTIuMjEtLjkxLTQuMi0yLjM2LTUuNjRMMjEgNHptLTEwIDloMlY3aC0ydjZ6Ii8+PC9zdmc+';
  62. /**
  63. * Used in the GraphViewer lightbox.
  64. */
  65. Editor.tweetImage = IMAGE_PATH + '/tweet.png';
  66. /**
  67. * Used in the GraphViewer lightbox.
  68. */
  69. Editor.facebookImage = IMAGE_PATH + '/facebook.png';
  70. /**
  71. * Blank 1x1 pixel transparent PNG image.
  72. */
  73. Editor.blankImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
  74. /**
  75. * Blank 1x1 pixel transparent PNG image.
  76. */
  77. Editor.hiResImage = (mxClient.IS_SVG) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA+CAMAAACLMWy1AAAAh1BMVEUAAABMTExERERBQUFBQUFFRUVAQEBCQkJAQEA6OjpDQ0NKSkpBQUFBQUFERERERERBQUFCQkJCQkJCQkJJSUlBQUFCQkJDQ0NDQ0NCQkJDQ0NBQUFBQUFCQkJBQUFCQkJCQkJDQ0NCQkJHR0dBQUFCQkJCQkJAQEBCQkJDQ0NAQEBERERCQkIk1hS2AAAAKnRSTlMAAjj96BL7PgQFRwfu3TYazKuVjRXl1V1DPCn1uLGjnWNVIgy9hU40eGqPkM38AAACG0lEQVRYw+2X63KbMBCFzwZblgGDceN74muatpLe//m6MHV3gHGFAv2RjM94MAbxzdnVsQbBDKwH8AH8MDAyafzjqYeyOG04XE7RS8nIRDXg6BlT+rA0nmtAPh+NQRDxIASIMG44rAMrGunBgHwy3uUldxggIStGKp2f+DQc2O4h4eQsX3O2IFB/oEbsjOKbStnjAEA+zJ0ylZTbgvoDn8xNyn6Dbj5Kd4GsNpABa6duQPfSdEj88TgMAhKuCWjAkgmFXPLnsD0pWd3OFGdrMugQII/eOMPEiGOzqPMIeWrcSoMCg71W1pXBPvCP+gS/OdXqQ3uW23+93XGWLl/OaBb805bNcBPoEIcVJsnHzcxpZH86u5KZ9gDby5dQCcnKqdbke4ItI4Tzd7IW9hZQt4EO6GG9b9sYuuK9Wwn8TIr2xKbF2+3Nhr+qxChJ/AI6pIfCu4z4Zowp4ZUNihz79vewzctnHDwTvQO/hCdFBzrUGDOPn2Y/F8YKT4oOATLvlhOznzmBSdFBJWtc58y7r+UVFOCQczy3wpN6pegDqHtsCPTGvH9JuTO0Dyg8icldYPk+RB6g8Aofj4m2EKBvtTmUPD9xDd1pPcSReV2U5iD/ik2yrngtvvqBfPzOvKiDTKTsCdoHZJ7pLLffgTwlJ5vJdtJV2/jiAYaLvLGhMAEDO5QcDg2M/jOw/8Zn+K3ZwJvHT7ZffgC/NvA3zcybTeIfE4EAAAAASUVORK5CYII=' : IMAGE_PATH + '/img-hi-res.png';
  78. /**
  79. * Blank 1x1 pixel transparent PNG image.
  80. */
  81. Editor.loResImage = (mxClient.IS_SVG) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAAA+CAMAAACLMWy1AAAAS1BMVEVAQEAAAAA1NTVBQUFDQ0NDQ0NFRUVERERBQUFBQUFBQUFAQEBBQUFBQUFCQkJCQkJCQkJBQUFCQkJDQ0NDQ0NCQkJCQkJCQkJGRkb5/XqTAAAAGXRSTlP+AAWODlASCsesX+Lc2LyWe3pwa1tCPjohjSJfoAAAAI1JREFUWMPt1MkKhTAMRuG0anvneXr/J71nUypKcdqI/N8yhLMKMZE1CahnClDQzMPB44ED3EgeCubgDWnWQMHpwTtKwTe+UHD4sJ94wbUEHHFGhILlYDeSnsQeabeCgsPBgB0MOZZ9oGA5GJFiJSfUULAfjLjARrhCwX7wh2YCDwVbwZkUBKqFFJRN+wOcwSgR2sREcgAAAABJRU5ErkJggg==' : IMAGE_PATH + '/img-lo-res.png';
  82. /**
  83. * Only needed in browsers with SVG support for export via lightbox toolbar.
  84. */
  85. Editor.cameraLargeImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAA/BJREFUWAnFl0uIjWEYx885buPSuGwmSYwtwsY1ikKSNYNclmQnadgrZSPlsnBLSlaGBdNYKY0Vdi4L4zYzIqxGxmXG//d+7//0+uY7nWMiT/2/53mf+3v7vnNKpf9M5UbrDw8Pj4m+wzmeT1FBUS6Xf+YNox6reMONukijMXUTM3NmI75PyXcJPwRWg5kS7xysDLNmfEUxpx2rceNE50IlYjyRklcLf0prY+x4BTqfmx3ZUHQaO9ISGngYq38V/1EH+ECPa+QaK1u1kVBQirDMChiS3CTeIkwWvghtwhKBpZ8g1CO2B99FynVU/KowSRgQ3mlrBsVZ1awmQlS0SGbfXglfBPbdRGMm5O8RXg2P835pDCvzWjghTHETcLpZLHwS8kTCtBEK1SN83Egam8YxyVZqc+Do5qkwS+gT9grNwkUBG6cbsG/gs3BTuC/0ChCxq4QtwgzBMdwUZBPyN4Ftfi4sYPZHktbOSRlIuutRP5jYj0ueZp88xyYcS/zZoiLyQT1IA/cTj7eSlwnrhI+JnkQbCwo2Sx/2M7VJt17wdhVtgxvrpoFnAuSAbJQ97biZAlKxBfD9wgOhV+BgIR/AZtJ4kwD5PGSj7OmmekjWEy0oAQHAS3+KpBpzXqYK3UItopHpSRMno2N+cm7gDYnfRCcr3QBqriMHLJDkeyhFfiG5aVbK+8rhtP9M6QcIEJHX5Fp9NMAyQlYiu+OOJNlODCIXyka/P23bncTdiC7OydC1+v1Bsb+5r84DK8S3Rdmf5cRUFW3bXtWUSt1Rdk6G4SyJV2o1YId+vNUxr+x5yCJiapFtcxQzLjrxboGcMxvFJwEOKnLwjIbkx/sdSmeSaUY++SwTAxV+4DJT7RVwkbk46gNCsifIItuy0e9PF33Cb4homhN5YRyzL5q5V2VNkv98kqgoGTo3YF9CnMM5Y5rItFfvBSi9JulVXOgI+VwIntkt+SaZ6weQfcovJf7zpTfl86P/wAF7Fz18NeKwmvAWCaX0Z/uMHQr42ZxvR/Rxcw5xM+9J/CJq8w2gduDhmDgso/QrBH47dEXQ1IqczyHpIOfIRtnTtV7SwO1oKXKkU3fbToFGSDHtMWcaH1WBuVYnDbRFi99iqSMySdzxXckrazUh23KBVYGIcfNBkTxca0e4ATJ0KukGYVBgr/MnlhPOtQq/ksUfCbzh+EFCjtnCUoHfjhA/OsiTv2HcEvJMELp0VakZDliTmriTdPivxU4VmEhtPrGV+KJhO7ZKt0doFZh1fgZSBWIW2AGEHwg3BUWOnKtH+suqdw07tYMfglCrWPD5mw9qVYuniaXkT0OtWaSuo5LJTY1RBf+roF9X5+y/5qU+DAAAAABJRU5ErkJggg==';
  86. /**
  87. * Default value for custom libraries in mxSettings.
  88. */
  89. Editor.defaultCustomLibraries = [];
  90. /**
  91. * Default value for custom libraries in mxSettings.
  92. */
  93. Editor.enableCustomLibraries = true;
  94. /**
  95. * Specifies if custom properties should be enabled.
  96. */
  97. Editor.enableCustomProperties = true;
  98. /**
  99. * Common properties for all edges.
  100. */
  101. Editor.commonEdgeProperties = [
  102. {type: 'separator'},
  103. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  104. {name: 'sourcePortConstraint', dispName: 'Source Constraint', type: 'enum', defVal: 'none',
  105. enumList: [{val: 'none', dispName: 'None'}, {val: 'north', dispName: 'North'}, {val: 'east', dispName: 'East'}, {val: 'south', dispName: 'South'}, {val: 'west', dispName: 'West'}]
  106. },
  107. {name: 'targetPortConstraint', dispName: 'Target Constraint', type: 'enum', defVal: 'none',
  108. enumList: [{val: 'none', dispName: 'None'}, {val: 'north', dispName: 'North'}, {val: 'east', dispName: 'East'}, {val: 'south', dispName: 'South'}, {val: 'west', dispName: 'West'}]
  109. },
  110. {name: 'jettySize', dispName: 'Jetty Size', type: 'int', min: 0, defVal: 'auto', allowAuto: true, isVisible: function(state)
  111. {
  112. return mxUtils.getValue(state.style, mxConstants.STYLE_EDGE, null) == 'orthogonalEdgeStyle';
  113. }},
  114. {name: 'fillOpacity', dispName: 'Fill Opacity', type: 'int', min: 0, max: 100, defVal: 100},
  115. {name: 'strokeOpacity', dispName: 'Stroke Opacity', type: 'int', min: 0, max: 100, defVal: 100},
  116. {name: 'startFill', dispName: 'Start Fill', type: 'bool', defVal: true},
  117. {name: 'endFill', dispName: 'End Fill', type: 'bool', defVal: true},
  118. {name: 'perimeterSpacing', dispName: 'Terminal Spacing', type: 'float', defVal: 0},
  119. {name: 'anchorPointDirection', dispName: 'Anchor Direction', type: 'bool', defVal: true},
  120. {name: 'snapToPoint', dispName: 'Snap to Anchor', type: 'bool', defVal: false},
  121. {name: 'fixDash', dispName: 'Fixed Dash', type: 'bool', defVal: false},
  122. {name: 'jiggle', dispName: 'Jiggle', type: 'float', min: 0, defVal: 1.5, isVisible: function(state)
  123. {
  124. return mxUtils.getValue(state.style, 'comic', '0') == '1';
  125. }},
  126. {name: 'editable', dispName: 'Editable', type: 'bool', defVal: true},
  127. {name: 'backgroundOutline', dispName: 'Background Outline', type: 'bool', defVal: false},
  128. {name: 'bendable', dispName: 'Bendable', type: 'bool', defVal: true},
  129. {name: 'movable', dispName: 'Movable', type: 'bool', defVal: true},
  130. {name: 'cloneable', dispName: 'Cloneable', type: 'bool', defVal: true},
  131. {name: 'deletable', dispName: 'Deletable', type: 'bool', defVal: true},
  132. {name: 'orthogonalLoop', dispName: 'Loop Routing', type: 'bool', defVal: false},
  133. {name: 'noJump', dispName: 'No Jumps', type: 'bool', defVal: false}
  134. ];
  135. /**
  136. * Common properties for all vertices.
  137. */
  138. Editor.commonVertexProperties = [
  139. {type: 'separator'},
  140. {name: 'fillOpacity', dispName: 'Fill Opacity', type: 'int', min: 0, max: 100, defVal: 100},
  141. {name: 'strokeOpacity', dispName: 'Stroke Opacity', type: 'int', min: 0, max: 100, defVal: 100},
  142. {name: 'overflow', dispName: 'Text Overflow', defVal: 'visible', type: 'enum',
  143. enumList: [{val: 'visible', dispName: 'Visible'}, {val: 'hidden', dispName: 'Hidden'}, {val: 'fill', dispName: 'Fill'}, {val: 'width', dispName: 'Width'}]
  144. },
  145. {name: 'noLabel', dispName: 'Hide Label', type: 'bool', defVal: false},
  146. {name: 'labelPadding', dispName: 'Label Padding', type: 'float', defVal: 0},
  147. {name: 'direction', dispName: 'Direction', type: 'enum', defVal: 'east',
  148. enumList: [{val: 'north', dispName: 'North'}, {val: 'east', dispName: 'East'}, {val: 'south', dispName: 'South'}, {val: 'west', dispName: 'West'}]
  149. },
  150. {name: 'portConstraint', dispName: 'Constraint', type: 'enum', defVal: 'none',
  151. enumList: [{val: 'none', dispName: 'None'}, {val: 'north', dispName: 'North'}, {val: 'east', dispName: 'East'}, {val: 'south', dispName: 'South'}, {val: 'west', dispName: 'West'}]
  152. },
  153. {name: 'portConstraintRotation', dispName: 'Rotate Constraint', type: 'bool', defVal: false},
  154. {name: 'connectable', dispName: 'Connectable', type: 'bool', defVal: true},
  155. {name: 'snapToPoint', dispName: 'Snap to Point', type: 'bool', defVal: false},
  156. {name: 'perimeter', dispName: 'Perimeter', defVal: 'none', type: 'enum',
  157. enumList: [{val: 'none', dispName: 'None'},
  158. {val: 'rectanglePerimeter', dispName: 'Rectangle'}, {val: 'ellipsePerimeter', dispName: 'Ellipse'},
  159. {val: 'rhombusPerimeter', dispName: 'Rhombus'}, {val: 'trianglePerimeter', dispName: 'Triangle'},
  160. {val: 'hexagonPerimeter2', dispName: 'Hexagon'}, {val: 'lifelinePerimeter', dispName: 'Lifeline'},
  161. {val: 'orthogonalPerimeter', dispName: 'Orthogonal'}, {val: 'backbonePerimeter', dispName: 'Backbone'},
  162. {val: 'calloutPerimeter', dispName: 'Callout'}, {val: 'parallelogramPerimeter', dispName: 'Parallelogram'},
  163. {val: 'trapezoidPerimeter', dispName: 'Trapezoid'}, {val: 'stepPerimeter', dispName: 'Step'}]
  164. },
  165. {name: 'fixDash', dispName: 'Fixed Dash', type: 'bool', defVal: false},
  166. {name: 'jiggle', dispName: 'Jiggle', type: 'float', min: 0, defVal: 1.5, isVisible: function(state)
  167. {
  168. return mxUtils.getValue(state.style, 'comic', '0') == '1';
  169. }},
  170. {name: 'autosize', dispName: 'Autosize', type: 'bool', defVal: false},
  171. {name: 'collapsible', dispName: 'Collapsible', type: 'bool', defVal: false},
  172. {name: 'container', dispName: 'Container', type: 'bool', defVal: false},
  173. {name: 'recursiveResize', dispName: 'Resize Children', type: 'bool', defVal: true},
  174. {name: 'part', dispName: 'Part', type: 'bool', defVal: false},
  175. {name: 'editable', dispName: 'Editable', type: 'bool', defVal: true},
  176. {name: 'backgroundOutline', dispName: 'Background Outline', type: 'bool', defVal: false},
  177. {name: 'movable', dispName: 'Movable', type: 'bool', defVal: true},
  178. {name: 'resizable', dispName: 'Resizable', type: 'bool', defVal: true},
  179. {name: 'resizeWidth', dispName: 'Resize Width', type: 'bool', defVal: false},
  180. {name: 'resizeHeight', dispName: 'Resize Height', type: 'bool', defVal: false},
  181. {name: 'rotatable', dispName: 'Rotatable', type: 'bool', defVal: true},
  182. {name: 'cloneable', dispName: 'Cloneable', type: 'bool', defVal: true},
  183. {name: 'deletable', dispName: 'Deletable', type: 'bool', defVal: true},
  184. {name: 'treeFolding', dispName: 'Tree Folding', type: 'bool', defVal: false},
  185. {name: 'treeMoving', dispName: 'Tree Moving', type: 'bool', defVal: false}
  186. ];
  187. /**
  188. * Default value for the CSV import dialog.
  189. */
  190. Editor.defaultCsvValue = '##\n' +
  191. '## Example CSV import. Use ## for comments and # for configuration. Paste CSV below.\n' +
  192. '## The following names are reserved and should not be used (or ignored):\n' +
  193. '## id, tooltip, placeholder(s), link and label (see below)\n' +
  194. '##\n' +
  195. '#\n' +
  196. '## Node label with placeholders and HTML.\n' +
  197. '## Default is \'%name_of_first_column%\'.\n' +
  198. '#\n' +
  199. '# label: %name%<br><i style="color:gray;">%position%</i><br><a href="mailto:%email%">Email</a>\n' +
  200. '#\n' +
  201. '## Node style (placeholders are replaced once).\n' +
  202. '## Default is the current style for nodes.\n' +
  203. '#\n' +
  204. '# style: label;image=%image%;whiteSpace=wrap;html=1;rounded=1;fillColor=%fill%;strokeColor=%stroke%;\n' +
  205. '#\n' +
  206. '## Parent style for nodes with child nodes (placeholders are replaced once).\n' +
  207. '#\n' +
  208. '# parentstyle: swimlane;whiteSpace=wrap;html=1;childLayout=stackLayout;horizontal=1;horizontalStack=0;resizeParent=1;resizeLast=0;collapsible=1;\n' +
  209. '#\n' +
  210. '## Optional column name that contains a reference to a named style in styles.\n' +
  211. '## Default is the current style for nodes.\n' +
  212. '#\n' +
  213. '# stylename: -\n' +
  214. '#\n' +
  215. '## JSON for named styles of the form {"name": "style", "name": "style"} where style is a cell style with\n' +
  216. '## placeholders that are replaced once.\n' +
  217. '#\n' +
  218. '# styles: -\n' +
  219. '#\n' +
  220. '## Optional column name that contains a reference to a named label in labels.\n' +
  221. '## Default is the current label.\n' +
  222. '#\n' +
  223. '# labelname: -\n' +
  224. '#\n' +
  225. '## JSON for named labels of the form {"name": "label", "name": "label"} where label is a cell label with\n' +
  226. '## placeholders.\n' +
  227. '#\n' +
  228. '# labels: -\n' +
  229. '#\n' +
  230. '## Uses the given column name as the identity for cells (updates existing cells).\n' +
  231. '## Default is no identity (empty value or -).\n' +
  232. '#\n' +
  233. '# identity: -\n' +
  234. '#\n' +
  235. '## Uses the given column name as the parent reference for cells. Default is no parent (empty or -).\n' +
  236. '## The identity above is used for resolving the reference so it must be specified.\n' +
  237. '#\n' +
  238. '# parent: -\n' +
  239. '#\n' +
  240. '## Adds a prefix to the identity of cells to make sure they do not collide with existing cells (whose\n' +
  241. '## IDs are numbers from 0..n, sometimes with a GUID prefix in the context of realtime collaboration).\n' +
  242. '## Default is csvimport-.\n' +
  243. '#\n' +
  244. '# namespace: csvimport-\n' +
  245. '#\n' +
  246. '## Connections between rows ("from": source colum, "to": target column).\n' +
  247. '## Label, style and invert are optional. Defaults are \'\', current style and false.\n' +
  248. '## In addition to label, an optional fromlabel and tolabel can be used to name the column\n' +
  249. '## that contains the text for the label in the edges source or target (invert ignored).\n' +
  250. '## The label is concatenated in the form fromlabel + label + tolabel if all are defined.\n' +
  251. '## The target column may contain a comma-separated list of values.\n' +
  252. '## Multiple connect entries are allowed.\n' +
  253. '#\n' +
  254. '# connect: {"from": "manager", "to": "name", "invert": true, "label": "manages", \\\n' +
  255. '# "style": "curved=1;endArrow=blockThin;endFill=1;fontSize=11;"}\n' +
  256. '# connect: {"from": "refs", "to": "id", "style": "curved=1;fontSize=11;"}\n' +
  257. '#\n' +
  258. '## Node x-coordinate. Possible value is a column name. Default is empty. Layouts will\n' +
  259. '## override this value.\n' +
  260. '#\n' +
  261. '# left: \n' +
  262. '#\n' +
  263. '## Node y-coordinate. Possible value is a column name. Default is empty. Layouts will\n' +
  264. '## override this value.\n' +
  265. '#\n' +
  266. '# top: \n' +
  267. '#\n' +
  268. '## Node width. Possible value is a number (in px), auto or an @ sign followed by a column\n' +
  269. '## name that contains the value for the width. Default is auto.\n' +
  270. '#\n' +
  271. '# width: auto\n' +
  272. '#\n' +
  273. '## Node height. Possible value is a number (in px), auto or an @ sign followed by a column\n' +
  274. '## name that contains the value for the height. Default is auto.\n' +
  275. '#\n' +
  276. '# height: auto\n' +
  277. '#\n' +
  278. '## Padding for autosize. Default is 0.\n' +
  279. '#\n' +
  280. '# padding: -12\n' +
  281. '#\n' +
  282. '## Comma-separated list of ignored columns for metadata. (These can be\n' +
  283. '## used for connections and styles but will not be added as metadata.)\n' +
  284. '#\n' +
  285. '# ignore: id,image,fill,stroke,refs,manager\n' +
  286. '#\n' +
  287. '## Column to be renamed to link attribute (used as link).\n' +
  288. '#\n' +
  289. '# link: url\n' +
  290. '#\n' +
  291. '## Spacing between nodes. Default is 40.\n' +
  292. '#\n' +
  293. '# nodespacing: 40\n' +
  294. '#\n' +
  295. '## Spacing between levels of hierarchical layouts. Default is 100.\n' +
  296. '#\n' +
  297. '# levelspacing: 100\n' +
  298. '#\n' +
  299. '## Spacing between parallel edges. Default is 40. Use 0 to disable.\n' +
  300. '#\n' +
  301. '# edgespacing: 40\n' +
  302. '#\n' +
  303. '## Name or JSON of layout. Possible values are auto, none, verticaltree, horizontaltree,\n' +
  304. '## verticalflow, horizontalflow, organic, circle or a JSON string as used in Layout, Apply.\n' +
  305. '## Default is auto.\n' +
  306. '#\n' +
  307. '# layout: auto\n' +
  308. '#\n' +
  309. '## ---- CSV below this line. First line are column names. ----\n' +
  310. 'name,position,id,location,manager,email,fill,stroke,refs,url,image\n' +
  311. 'Evan Miller,CFO,emi,Office 1,,me@example.com,#dae8fc,#6c8ebf,,https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-9-2-128.png\n' +
  312. 'Edward Morrison,Brand Manager,emo,Office 2,Evan Miller,me@example.com,#d5e8d4,#82b366,,https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-10-3-128.png\n' +
  313. 'Ron Donovan,System Admin,rdo,Office 3,Evan Miller,me@example.com,#d5e8d4,#82b366,"emo,tva",https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-2-128.png\n' +
  314. 'Tessa Valet,HR Director,tva,Office 4,Evan Miller,me@example.com,#d5e8d4,#82b366,,https://www.draw.io,https://cdn3.iconfinder.com/data/icons/user-avatars-1/512/users-3-128.png\n';
  315. /**
  316. * Helper function to extract the graph model XML node.
  317. */
  318. Editor.extractGraphModel = function(node, allowMxFile)
  319. {
  320. if (node != null && typeof(pako) !== 'undefined')
  321. {
  322. var tmp = node.ownerDocument.getElementsByTagName('div');
  323. var divs = [];
  324. if (tmp != null && tmp.length > 0)
  325. {
  326. for (var i = 0; i < tmp.length; i++)
  327. {
  328. if (tmp[i].getAttribute('class') == 'mxgraph')
  329. {
  330. divs.push(tmp[i]);
  331. break;
  332. }
  333. }
  334. }
  335. if (divs.length > 0)
  336. {
  337. var data = divs[0].getAttribute('data-mxgraph');
  338. if (data != null)
  339. {
  340. var config = JSON.parse(data);
  341. if (config != null && config.xml != null)
  342. {
  343. var doc2 = mxUtils.parseXml(config.xml);
  344. node = doc2.documentElement;
  345. }
  346. }
  347. else
  348. {
  349. var divs2 = divs[0].getElementsByTagName('div');
  350. if (divs2.length > 0)
  351. {
  352. var data = mxUtils.getTextContent(divs2[0]);
  353. data = Graph.decompress(data);
  354. if (data.length > 0)
  355. {
  356. var doc2 = mxUtils.parseXml(data);
  357. node = doc2.documentElement;
  358. }
  359. }
  360. }
  361. }
  362. }
  363. if (node != null && node.nodeName == 'svg')
  364. {
  365. var tmp = node.getAttribute('content');
  366. if (tmp != null && tmp.charAt(0) != '<' && tmp.charAt(0) != '%')
  367. {
  368. tmp = unescape((window.atob) ? atob(tmp) : Base64.decode(cont, tmp));
  369. }
  370. if (tmp != null && tmp.charAt(0) == '%')
  371. {
  372. tmp = decodeURIComponent(tmp);
  373. }
  374. if (tmp != null && tmp.length > 0)
  375. {
  376. node = mxUtils.parseXml(tmp).documentElement;
  377. }
  378. else
  379. {
  380. throw {message: mxResources.get('notADiagramFile')};
  381. }
  382. }
  383. if (node != null && !allowMxFile)
  384. {
  385. var diagramNode = null;
  386. if (node.nodeName == 'diagram')
  387. {
  388. diagramNode = node;
  389. }
  390. else if (node.nodeName == 'mxfile')
  391. {
  392. var diagrams = node.getElementsByTagName('diagram');
  393. if (diagrams.length > 0)
  394. {
  395. diagramNode = diagrams[Math.max(0, Math.min(diagrams.length - 1, urlParams['page'] || 0))];
  396. }
  397. }
  398. if (diagramNode != null)
  399. {
  400. node = Editor.parseDiagramNode(diagramNode);
  401. }
  402. }
  403. if (node != null && node.nodeName != 'mxGraphModel' && (!allowMxFile || node.nodeName != 'mxfile'))
  404. {
  405. node = null;
  406. }
  407. return node;
  408. };
  409. /**
  410. * Extracts the XML from the compressed or non-compressed text chunk.
  411. */
  412. Editor.parseDiagramNode = function(diagramNode)
  413. {
  414. var text = mxUtils.trim(mxUtils.getTextContent(diagramNode));
  415. var node = null;
  416. if (text.length > 0)
  417. {
  418. var tmp = Graph.decompress(text);
  419. if (tmp != null && tmp.length > 0)
  420. {
  421. node = mxUtils.parseXml(tmp).documentElement;
  422. }
  423. }
  424. else
  425. {
  426. var temp = mxUtils.getChildNodes(diagramNode);
  427. if (temp.length > 0)
  428. {
  429. // Creates new document for unique IDs within mxGraphModel
  430. var doc = mxUtils.createXmlDocument();
  431. doc.appendChild(doc.importNode(temp[0], true));
  432. node = doc.documentElement;
  433. }
  434. }
  435. return node;
  436. };
  437. /**
  438. * Extracts the XML from the compressed or non-compressed text chunk.
  439. */
  440. Editor.getDiagramNodeXml = function(diagramNode)
  441. {
  442. var text = mxUtils.getTextContent(diagramNode);
  443. var xml = null;
  444. if (text.length > 0)
  445. {
  446. xml = Graph.decompress(text);
  447. }
  448. else if (diagramNode.firstChild != null)
  449. {
  450. xml = mxUtils.getXml(diagramNode.firstChild);
  451. }
  452. return xml;
  453. };
  454. /**
  455. * Extracts the XML from the compressed or non-compressed text chunk.
  456. */
  457. Editor.extractGraphModelFromPng = function(data)
  458. {
  459. var result = null;
  460. try
  461. {
  462. var base64 = data.substring(data.indexOf(',') + 1);
  463. // Workaround for invalid character error in Safari
  464. var binary = (window.atob && !mxClient.IS_SF) ? atob(base64) : Base64.decode(base64, true);
  465. EditorUi.parsePng(binary, mxUtils.bind(this, function(pos, type, length)
  466. {
  467. var value = binary.substring(pos + 8, pos + 8 + length);
  468. if (type == 'zTXt')
  469. {
  470. var idx = value.indexOf(String.fromCharCode(0));
  471. if (value.substring(0, idx) == 'mxGraphModel')
  472. {
  473. // Workaround for Java URL Encoder using + for spaces, which isn't compatible with JS
  474. var xmlData = Graph.bytesToString(pako.inflateRaw(
  475. value.substring(idx + 2))).replace(/\+/g,' ');
  476. if (xmlData != null && xmlData.length > 0)
  477. {
  478. result = xmlData;
  479. }
  480. }
  481. }
  482. // Uncompressed section is normally not used
  483. else if (type == 'tEXt')
  484. {
  485. var vals = value.split(String.fromCharCode(0));
  486. if (vals.length > 1 && (vals[0] == 'mxGraphModel' ||
  487. vals[0] == 'mxfile'))
  488. {
  489. result = vals[1];
  490. }
  491. }
  492. if (result != null || type == 'IDAT')
  493. {
  494. // Stops processing the file as our text chunks
  495. // are always placed before the data section
  496. return true;
  497. }
  498. }));
  499. }
  500. catch (e)
  501. {
  502. // ignores decoding errors
  503. }
  504. if (result != null && result.charAt(0) == '%')
  505. {
  506. result = decodeURIComponent(result);
  507. }
  508. // Workaround for double encoded content
  509. if (result != null && result.charAt(0) == '%')
  510. {
  511. result = decodeURIComponent(result);
  512. }
  513. return result;
  514. };
  515. /**
  516. * Disables the shadow option in the format panel.
  517. */
  518. Editor.shadowOptionEnabled = true;
  519. /**
  520. * Reference to the config object passed to <configure>.
  521. */
  522. Editor.config = null;
  523. /**
  524. * Reference to the version of the last config object in
  525. * <configure>. If this is different to the last version in
  526. * mxSettings.parse, then the settings are reset.
  527. */
  528. Editor.configVersion = null;
  529. /**
  530. * Global configuration of the Editor
  531. * see https://desk.draw.io/solution/articles/16000058316
  532. *
  533. * For defaultVertexStyle, defaultEdgeStyle and defaultLibraries, this must be called before
  534. * mxSettings.load via global config variable window.mxLoadSettings = false.
  535. */
  536. Editor.configure = function(config, untrusted)
  537. {
  538. if (config != null)
  539. {
  540. Editor.config = config;
  541. Editor.configVersion = config.version;
  542. Menus.prototype.defaultFonts = config.defaultFonts || Menus.prototype.defaultFonts;
  543. ColorDialog.prototype.presetColors = config.presetColors || ColorDialog.prototype.presetColors;
  544. ColorDialog.prototype.defaultColors = config.defaultColors || ColorDialog.prototype.defaultColors;
  545. StyleFormatPanel.prototype.defaultColorSchemes = config.defaultColorSchemes || StyleFormatPanel.prototype.defaultColorSchemes;
  546. Graph.prototype.defaultEdgeLength = config.defaultEdgeLength || Graph.prototype.defaultEdgeLength;
  547. DrawioFile.prototype.autosaveDelay = config.autosaveDelay || DrawioFile.prototype.autosaveDelay;
  548. if (config.templateFile != null)
  549. {
  550. EditorUi.templateFile = config.templateFile;
  551. }
  552. if (config.customFonts)
  553. {
  554. Menus.prototype.defaultFonts = config.customFonts.
  555. concat(Menus.prototype.defaultFonts);
  556. }
  557. if (config.customPresetColors)
  558. {
  559. ColorDialog.prototype.presetColors = config.customPresetColors.
  560. concat(ColorDialog.prototype.presetColors);
  561. }
  562. if (config.customColorSchemes != null)
  563. {
  564. StyleFormatPanel.prototype.defaultColorSchemes = config.customColorSchemes.
  565. concat(StyleFormatPanel.prototype.defaultColorSchemes);
  566. }
  567. // Custom CSS injected directly into the page
  568. if (config.css != null)
  569. {
  570. var s = document.createElement('style');
  571. s.setAttribute('type', 'text/css');
  572. s.appendChild(document.createTextNode(config.css));
  573. var t = document.getElementsByTagName('script')[0];
  574. t.parentNode.insertBefore(s, t);
  575. }
  576. // Configures the custom libraries
  577. if (config.libraries != null)
  578. {
  579. Sidebar.prototype.customEntries = config.libraries;
  580. }
  581. // Defines the enabled built-in libraries.
  582. if (config.enabledLibraries != null)
  583. {
  584. Sidebar.prototype.enabledLibraries = config.enabledLibraries;
  585. }
  586. // Overrides default libraries
  587. if (config.defaultLibraries != null)
  588. {
  589. Sidebar.prototype.defaultEntries = config.defaultLibraries;
  590. }
  591. // Overrides default custom libraries
  592. if (config.defaultCustomLibraries != null)
  593. {
  594. Editor.defaultCustomLibraries = config.defaultCustomLibraries;
  595. }
  596. // Disables custom libraries
  597. if (config.enableCustomLibraries != null)
  598. {
  599. Editor.enableCustomLibraries = config.enableCustomLibraries;
  600. }
  601. // Overrides default vertex style
  602. if (config.defaultVertexStyle != null)
  603. {
  604. Graph.prototype.defaultVertexStyle = config.defaultVertexStyle;
  605. }
  606. // Overrides default edge style
  607. if (config.defaultEdgeStyle != null)
  608. {
  609. Graph.prototype.defaultEdgeStyle = config.defaultEdgeStyle;
  610. }
  611. if (config.emptyDiagramXml)
  612. {
  613. EditorUi.prototype.emptyDiagramXml = config.emptyDiagramXml;
  614. }
  615. if (config.thumbWidth)
  616. {
  617. Sidebar.prototype.thumbWidth = config.thumbWidth;
  618. }
  619. if (config.thumbHeight)
  620. {
  621. Sidebar.prototype.thumbHeight = config.thumbHeight;
  622. }
  623. if (config.emptyLibraryXml)
  624. {
  625. EditorUi.prototype.emptyLibraryXml = config.emptyLibraryXml;
  626. }
  627. if (config.sidebarWidth)
  628. {
  629. EditorUi.prototype.hsplitPosition = config.sidebarWidth;
  630. }
  631. if (config.fontCss)
  632. {
  633. var s = document.createElement('style');
  634. s.setAttribute('type', 'text/css');
  635. s.appendChild(document.createTextNode(config.fontCss));
  636. var t = document.getElementsByTagName('script')[0];
  637. t.parentNode.insertBefore(s, t);
  638. Editor.prototype.fontCss = config.fontCss;
  639. }
  640. if (config.plugins != null && !untrusted)
  641. {
  642. // Required for callback
  643. App.initPluginCallback();
  644. for (var i = 0; i < config.plugins.length; i++)
  645. {
  646. mxscript(config.plugins[i]);
  647. }
  648. }
  649. }
  650. };
  651. /**
  652. * Generates a unique ID of the given length
  653. */
  654. Editor.GUID_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_';
  655. /**
  656. * Generates a unique ID of the given length
  657. */
  658. Editor.GUID_LENGTH = 20;
  659. /**
  660. * Generates a unique ID of the given length
  661. */
  662. Editor.guid = function(length)
  663. {
  664. var len = (length != null) ? length : Editor.GUID_LENGTH;
  665. var rtn = [];
  666. for (var i = 0; i < len; i++)
  667. {
  668. rtn.push(Editor.GUID_ALPHABET.charAt(Math.floor(Math.random() * Editor.GUID_ALPHABET.length)));
  669. }
  670. return rtn.join('');
  671. };
  672. /**
  673. * General timeout is 25 seconds.
  674. */
  675. Editor.prototype.timeout = 25000;
  676. /**
  677. * This should not be enabled if reflows are required for math rendering.
  678. */
  679. Editor.prototype.useForeignObjectForMath = false;
  680. /**
  681. * Executes the first step for connecting to Google Drive.
  682. */
  683. Editor.prototype.editButtonLink = (urlParams['edit'] != null) ? decodeURIComponent(urlParams['edit']) : null;
  684. /**
  685. * Adds support for old stylesheets and compressed files
  686. */
  687. var editorSetGraphXml = Editor.prototype.setGraphXml;
  688. Editor.prototype.setGraphXml = function(node)
  689. {
  690. node = (node != null && node.nodeName != 'mxlibrary') ? this.extractGraphModel(node) : null;
  691. if (node != null)
  692. {
  693. // Checks input for parser errors
  694. var errs = node.getElementsByTagName('parsererror');
  695. if (errs != null && errs.length > 0)
  696. {
  697. var elt = errs[0];
  698. var divs = elt.getElementsByTagName('div');
  699. if (divs != null && divs.length > 0)
  700. {
  701. elt = divs[0];
  702. }
  703. throw {message: mxUtils.getTextContent(elt)};
  704. }
  705. else if (node.nodeName == 'mxGraphModel')
  706. {
  707. var style = node.getAttribute('style') || 'default-style2';
  708. // Decodes the style if required
  709. if (urlParams['embed'] != '1' && (style == null || style == ''))
  710. {
  711. var node2 = (this.graph.themes != null) ?
  712. this.graph.themes['default-old'] :
  713. mxUtils.load(STYLE_PATH + '/default-old.xml').getDocumentElement();
  714. if (node2 != null)
  715. {
  716. var dec2 = new mxCodec(node2.ownerDocument);
  717. dec2.decode(node2, this.graph.getStylesheet());
  718. }
  719. }
  720. else if (style != this.graph.currentStyle)
  721. {
  722. var node2 = (this.graph.themes != null) ?
  723. this.graph.themes[style] :
  724. mxUtils.load(STYLE_PATH + '/' + style + '.xml').getDocumentElement()
  725. if (node2 != null)
  726. {
  727. var dec2 = new mxCodec(node2.ownerDocument);
  728. dec2.decode(node2, this.graph.getStylesheet());
  729. }
  730. }
  731. this.graph.currentStyle = style;
  732. this.graph.mathEnabled = (urlParams['math'] == '1' || node.getAttribute('math') == '1');
  733. var bgImg = node.getAttribute('backgroundImage');
  734. if (bgImg != null)
  735. {
  736. bgImg = JSON.parse(bgImg);
  737. this.graph.setBackgroundImage(new mxImage(bgImg.src, bgImg.width, bgImg.height));
  738. }
  739. else
  740. {
  741. this.graph.setBackgroundImage(null);
  742. }
  743. mxClient.NO_FO = ((this.graph.mathEnabled && !this.useForeignObjectForMath)) ?
  744. true : this.originalNoForeignObject;
  745. this.graph.useCssTransforms = !mxClient.NO_FO &&
  746. this.isChromelessView() &&
  747. this.graph.isCssTransformsSupported();
  748. this.graph.updateCssTransform();
  749. this.graph.setShadowVisible(node.getAttribute('shadow') == '1', false);
  750. }
  751. // Calls updateGraphComponents
  752. editorSetGraphXml.apply(this, arguments);
  753. }
  754. else
  755. {
  756. throw {
  757. message: mxResources.get('notADiagramFile') || 'Invalid data',
  758. toString: function() { return this.message; }
  759. };
  760. }
  761. };
  762. /**
  763. * Adds persistent style to file
  764. */
  765. var editorGetGraphXml = Editor.prototype.getGraphXml;
  766. Editor.prototype.getGraphXml = function(ignoreSelection)
  767. {
  768. ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
  769. var node = editorGetGraphXml.apply(this, arguments);
  770. // Adds the current style
  771. if (this.graph.currentStyle != null && this.graph.currentStyle != 'default-style2')
  772. {
  773. node.setAttribute('style', this.graph.currentStyle);
  774. }
  775. // Adds the background image
  776. if (this.graph.backgroundImage != null)
  777. {
  778. node.setAttribute('backgroundImage', JSON.stringify(this.graph.backgroundImage));
  779. }
  780. node.setAttribute('math', (this.graph.mathEnabled) ? '1' : '0');
  781. node.setAttribute('shadow', (this.graph.shadowVisible) ? '1' : '0');
  782. return node;
  783. };
  784. /**
  785. * Helper function to extract the graph model XML node.
  786. */
  787. Editor.prototype.isDataSvg = function(svg)
  788. {
  789. try
  790. {
  791. var svgRoot = mxUtils.parseXml(svg).documentElement;
  792. var tmp = svgRoot.getAttribute('content');
  793. if (tmp != null)
  794. {
  795. if (tmp != null && tmp.charAt(0) != '<' && tmp.charAt(0) != '%')
  796. {
  797. tmp = unescape((window.atob) ? atob(tmp) : Base64.decode(cont, tmp));
  798. }
  799. if (tmp != null && tmp.charAt(0) == '%')
  800. {
  801. tmp = decodeURIComponent(tmp);
  802. }
  803. if (tmp != null && tmp.length > 0)
  804. {
  805. var node = mxUtils.parseXml(tmp).documentElement;
  806. return node.nodeName == 'mxfile' || node.nodeName == 'mxGraphModel';
  807. }
  808. }
  809. }
  810. catch (e)
  811. {
  812. // ignore
  813. }
  814. return false;
  815. };
  816. /**
  817. * Helper function to extract the graph model XML node.
  818. */
  819. Editor.prototype.extractGraphModel = function(node, allowMxFile)
  820. {
  821. return Editor.extractGraphModel.apply(this, arguments);
  822. };
  823. /**
  824. * Overrides reset graph.
  825. */
  826. var editorResetGraph = Editor.prototype.resetGraph;
  827. Editor.prototype.resetGraph = function()
  828. {
  829. this.graph.mathEnabled = (urlParams['math'] == '1');
  830. this.graph.view.x0 = null;
  831. this.graph.view.y0 = null;
  832. mxClient.NO_FO = ((this.graph.mathEnabled && !this.useForeignObjectForMath)) ?
  833. true : this.originalNoForeignObject;
  834. this.graph.useCssTransforms = !mxClient.NO_FO &&
  835. this.isChromelessView() &&
  836. this.graph.isCssTransformsSupported();
  837. this.graph.updateCssTransform();
  838. editorResetGraph.apply(this, arguments);
  839. };
  840. /**
  841. * Math support.
  842. */
  843. var editorUpdateGraphComponents = Editor.prototype.updateGraphComponents;
  844. Editor.prototype.updateGraphComponents = function()
  845. {
  846. editorUpdateGraphComponents.apply(this, arguments);
  847. mxClient.NO_FO = ((this.graph.mathEnabled && !this.useForeignObjectForMath) &&
  848. Editor.MathJaxRender != null) ? true : this.originalNoForeignObject;
  849. this.graph.useCssTransforms = !mxClient.NO_FO &&
  850. this.isChromelessView() &&
  851. this.graph.isCssTransformsSupported();
  852. this.graph.updateCssTransform();
  853. };
  854. /**
  855. * Initializes math typesetting and loads respective code.
  856. */
  857. Editor.initMath = function(src, config)
  858. {
  859. src = (src != null) ? src : DRAW_MATH_URL + '/MathJax.js?config=TeX-MML-AM_HTMLorMML';
  860. Editor.mathJaxQueue = [];
  861. Editor.doMathJaxRender = function(container)
  862. {
  863. window.setTimeout(function()
  864. {
  865. if (container.style.visibility != 'hidden')
  866. {
  867. MathJax.Hub.Queue(['Typeset', MathJax.Hub, container]);
  868. }
  869. }, 0);
  870. };
  871. // Disables global typesetting and messages on startup, adds queue for
  872. // asynchronous rendering while MathJax is loading
  873. window.MathJax =
  874. {
  875. skipStartupTypeset: true,
  876. showMathMenu: false,
  877. messageStyle: 'none',
  878. AuthorInit: function ()
  879. {
  880. // Specification recommends using SVG over HTML-CSS if browser is known
  881. // Check if too inconsistent with image export and print output
  882. MathJax.Hub.Config(config || {
  883. jax: ['input/TeX', 'input/MathML', 'input/AsciiMath', 'output/HTML-CSS'],
  884. extensions: ['tex2jax.js', 'mml2jax.js', 'asciimath2jax.js'],
  885. 'HTML-CSS': {
  886. imageFont: null
  887. },
  888. TeX: {
  889. extensions: ['AMSmath.js', 'AMSsymbols.js', 'noErrors.js', 'noUndefined.js']
  890. },
  891. // Ignores math in in-place editor
  892. tex2jax: {
  893. ignoreClass: 'mxCellEditor'
  894. },
  895. asciimath2jax: {
  896. ignoreClass: 'mxCellEditor'
  897. }
  898. });
  899. MathJax.Hub.Register.StartupHook('Begin', function()
  900. {
  901. for (var i = 0; i < Editor.mathJaxQueue.length; i++)
  902. {
  903. Editor.doMathJaxRender(Editor.mathJaxQueue[i]);
  904. }
  905. });
  906. }
  907. };
  908. // Adds global enqueue method for async rendering
  909. Editor.MathJaxRender = function(container)
  910. {
  911. // Initial rendering when MathJax finished loading
  912. if (typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined')
  913. {
  914. Editor.doMathJaxRender(container);
  915. }
  916. else
  917. {
  918. Editor.mathJaxQueue.push(container);
  919. }
  920. };
  921. // Adds global clear queue method
  922. Editor.MathJaxClear = function()
  923. {
  924. Editor.mathJaxQueue = [];
  925. };
  926. // Updates math typesetting after changes
  927. var editorInit = Editor.prototype.init;
  928. Editor.prototype.init = function()
  929. {
  930. editorInit.apply(this, arguments);
  931. this.graph.addListener(mxEvent.SIZE, mxUtils.bind(this, function(sender, evt)
  932. {
  933. if (this.graph.container != null && this.graph.mathEnabled && !this.graph.blockMathRender)
  934. {
  935. Editor.MathJaxRender(this.graph.container);
  936. }
  937. }));
  938. };
  939. var tags = document.getElementsByTagName('script');
  940. if (tags != null && tags.length > 0)
  941. {
  942. var script = document.createElement('script');
  943. script.type = 'text/javascript';
  944. script.src = src;
  945. tags[0].parentNode.appendChild(script);
  946. }
  947. };
  948. /**
  949. * Return array of string values, or NULL if CSV string not well formed.
  950. */
  951. Editor.prototype.csvToArray = function(text)
  952. {
  953. var re_valid = /^\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*(?:,\s*(?:'[^'\\]*(?:\\[\S\s][^'\\]*)*'|"[^"\\]*(?:\\[\S\s][^"\\]*)*"|[^,'"\s\\]*(?:\s+[^,'"\s\\]+)*)\s*)*$/;
  954. var re_value = /(?!\s*$)\s*(?:'([^'\\]*(?:\\[\S\s][^'\\]*)*)'|"([^"\\]*(?:\\[\S\s][^"\\]*)*)"|([^,'"\s\\]*(?:\s+[^,'"\s\\]+)*))\s*(?:,|$)/g;
  955. // Return NULL if input string is not well formed CSV string.
  956. if (!re_valid.test(text)) return null;
  957. var a = []; // Initialize array to receive values.
  958. text.replace(re_value, // "Walk" the string using replace with callback.
  959. function(m0, m1, m2, m3) {
  960. // Remove backslash from \' in single quoted values.
  961. if (m1 !== undefined) a.push(m1.replace(/\\'/g, "'"));
  962. // Remove backslash from \" in double quoted values.
  963. else if (m2 !== undefined) a.push(m2.replace(/\\"/g, '"'));
  964. else if (m3 !== undefined) a.push(m3);
  965. return ''; // Return empty string.
  966. });
  967. // Handle special case of empty last value.
  968. if (/,\s*$/.test(text)) a.push('');
  969. return a;
  970. };
  971. /**
  972. * Returns true if the given URL is known to have CORS headers.
  973. */
  974. Editor.prototype.isCorsEnabledForUrl = function(url)
  975. {
  976. if (urlParams['cors'] != null && this.corsRegExp == null)
  977. {
  978. this.corsRegExp = new RegExp(decodeURIComponent(urlParams['cors']));
  979. }
  980. return (this.corsRegExp != null && this.corsRegExp.test(url)) ||
  981. url.substring(0, 34) === 'https://raw.githubusercontent.com/' ||
  982. url.substring(0, 23) === 'https://cdn.rawgit.com/' ||
  983. url.substring(0, 19) === 'https://rawgit.com/' ||
  984. /^https?:\/\/[^\/]*\.blob.core.windows.net\//.test(url) ||
  985. /^https?:\/\/[^\/]*\.iconfinder.com\//.test(url) ||
  986. /^https?:\/\/[^\/]*\.draw\.io\/proxy/.test(url) ||
  987. /^https?:\/\/[^\/]*\.github\.io\//.test(url);
  988. };
  989. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  990. /**
  991. * Converts all images in the SVG output to data URIs for immediate rendering
  992. */
  993. Editor.prototype.createImageUrlConverter = function()
  994. {
  995. var converter = new mxUrlConverter();
  996. converter.updateBaseUrl();
  997. // Extends convert to avoid CORS using an image proxy server where needed
  998. var convert = converter.convert;
  999. var self = this;
  1000. converter.convert = function(src)
  1001. {
  1002. if (src != null)
  1003. {
  1004. var remote = src.substring(0, 7) == 'http://' || src.substring(0, 8) == 'https://';
  1005. if (remote && !navigator.onLine)
  1006. {
  1007. src = EditorUi.prototype.svgBrokenImage.src; //TODO move it to Editor?
  1008. }
  1009. else if (remote && src.substring(0, converter.baseUrl.length) != converter.baseUrl &&
  1010. (!EditorUi.prototype.crossOriginImages || !self.isCorsEnabledForUrl(src))) //TODO move it to Editor?
  1011. {
  1012. src = PROXY_URL + '?url=' + encodeURIComponent(src);
  1013. }
  1014. else if (src.substring(0, 19) != 'chrome-extension://')
  1015. {
  1016. src = convert.apply(this, arguments);
  1017. }
  1018. }
  1019. return src;
  1020. };
  1021. return converter;
  1022. };
  1023. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1024. /**
  1025. *
  1026. */
  1027. Editor.prototype.createSvgDataUri = function(svg)
  1028. {
  1029. return 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg)));
  1030. };
  1031. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1032. /**
  1033. *
  1034. */
  1035. Editor.prototype.convertImageToDataUri = function(url, callback)
  1036. {
  1037. if (/(\.svg)$/i.test(url))
  1038. {
  1039. mxUtils.get(url, mxUtils.bind(this, function(req)
  1040. {
  1041. callback(this.createSvgDataUri(req.getText()));
  1042. }),
  1043. function()
  1044. {
  1045. callback(EditorUi.prototype.svgBrokenImage.src);
  1046. });
  1047. }
  1048. else
  1049. {
  1050. var img = new Image();
  1051. var self = this;
  1052. if (EditorUi.prototype.crossOriginImages)
  1053. {
  1054. img.crossOrigin = 'anonymous';
  1055. }
  1056. img.onload = function()
  1057. {
  1058. var canvas = document.createElement('canvas');
  1059. var ctx = canvas.getContext('2d');
  1060. canvas.height = img.height;
  1061. canvas.width = img.width;
  1062. ctx.drawImage(img, 0, 0);
  1063. try
  1064. {
  1065. callback(canvas.toDataURL());
  1066. }
  1067. catch (e)
  1068. {
  1069. callback(EditorUi.prototype.svgBrokenImage.src);
  1070. }
  1071. };
  1072. img.onerror = function()
  1073. {
  1074. callback(EditorUi.prototype.svgBrokenImage.src);
  1075. };
  1076. img.src = url;
  1077. }
  1078. };
  1079. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1080. /**
  1081. * Converts all images in the SVG output to data URIs for immediate rendering
  1082. */
  1083. Editor.prototype.convertImages = function(svgRoot, callback, imageCache, converter)
  1084. {
  1085. // Converts images to data URLs for immediate painting
  1086. if (converter == null)
  1087. {
  1088. converter = this.createImageUrlConverter();
  1089. }
  1090. // Barrier for asynchronous image loading
  1091. var counter = 0;
  1092. function inc()
  1093. {
  1094. counter++;
  1095. };
  1096. function dec()
  1097. {
  1098. counter--;
  1099. if (counter == 0)
  1100. {
  1101. callback(svgRoot);
  1102. }
  1103. };
  1104. var cache = imageCache || new Object();
  1105. var convertImages = mxUtils.bind(this, function(tagName, srcAttr)
  1106. {
  1107. var images = svgRoot.getElementsByTagName(tagName);
  1108. for (var i = 0; i < images.length; i++)
  1109. {
  1110. (mxUtils.bind(this, function(img)
  1111. {
  1112. var src = converter.convert(img.getAttribute(srcAttr));
  1113. // Data URIs are pass-through
  1114. if (src != null && src.substring(0, 5) != 'data:')
  1115. {
  1116. var tmp = cache[src];
  1117. if (tmp == null)
  1118. {
  1119. inc();
  1120. this.convertImageToDataUri(src, function(uri)
  1121. {
  1122. if (uri != null)
  1123. {
  1124. cache[src] = uri;
  1125. img.setAttribute(srcAttr, uri);
  1126. }
  1127. dec();
  1128. });
  1129. }
  1130. else
  1131. {
  1132. img.setAttribute(srcAttr, tmp);
  1133. }
  1134. }
  1135. else if (src != null)
  1136. {
  1137. img.setAttribute(srcAttr, src);
  1138. }
  1139. }))(images[i]);
  1140. }
  1141. });
  1142. // Converts all known image tags in output
  1143. // LATER: Add support for images in CSS
  1144. convertImages('image', 'xlink:href');
  1145. convertImages('img', 'src');
  1146. // All from cache or no images
  1147. if (counter == 0)
  1148. {
  1149. callback(svgRoot);
  1150. }
  1151. };
  1152. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1153. /**
  1154. * Base64 encodes the given string. This method seems to be more
  1155. * robust for encoding PNG from binary AJAX responses.
  1156. */
  1157. Editor.prototype.base64Encode = function(str)
  1158. {
  1159. var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  1160. var out = "", i = 0, len = str.length, c1, c2, c3;
  1161. while (i < len)
  1162. {
  1163. c1 = str.charCodeAt(i++) & 0xff;
  1164. if (i == len)
  1165. {
  1166. out += CHARS.charAt(c1 >> 2);
  1167. out += CHARS.charAt((c1 & 0x3) << 4);
  1168. out += "==";
  1169. break;
  1170. }
  1171. c2 = str.charCodeAt(i++);
  1172. if (i == len)
  1173. {
  1174. out += CHARS.charAt(c1 >> 2);
  1175. out += CHARS.charAt(((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4));
  1176. out += CHARS.charAt((c2 & 0xF) << 2);
  1177. out += "=";
  1178. break;
  1179. }
  1180. c3 = str.charCodeAt(i++);
  1181. out += CHARS.charAt(c1 >> 2);
  1182. out += CHARS.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
  1183. out += CHARS.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
  1184. out += CHARS.charAt(c3 & 0x3F);
  1185. }
  1186. return out;
  1187. };
  1188. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1189. /**
  1190. * Checks if the client is authorized and calls the next step.
  1191. */
  1192. Editor.prototype.loadUrl = function(url, success, error, forceBinary, retry, dataUriPrefix)
  1193. {
  1194. try
  1195. {
  1196. var binary = forceBinary || /(\.png)($|\?)/i.test(url) ||
  1197. /(\.jpe?g)($|\?)/i.test(url) || /(\.gif)($|\?)/i.test(url);
  1198. retry = (retry != null) ? retry : true;
  1199. var fn = mxUtils.bind(this, function()
  1200. {
  1201. mxUtils.get(url, mxUtils.bind(this, function(req)
  1202. {
  1203. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  1204. {
  1205. if (success != null)
  1206. {
  1207. var data = req.getText();
  1208. // Returns PNG as base64 encoded data URI
  1209. if (binary)
  1210. {
  1211. // NOTE: This requires BinaryToArray VB script in the page
  1212. if ((document.documentMode == 9 || document.documentMode == 10) &&
  1213. typeof window.mxUtilsBinaryToArray !== 'undefined')
  1214. {
  1215. var bin = mxUtilsBinaryToArray(req.request.responseBody).toArray();
  1216. var tmp = new Array(bin.length);
  1217. for (var i = 0; i < bin.length; i++)
  1218. {
  1219. tmp[i] = String.fromCharCode(bin[i]);
  1220. }
  1221. data = tmp.join('');
  1222. }
  1223. // LATER: Could be JPG but modern browsers
  1224. // ignore the mime type in the data URI
  1225. dataUriPrefix = (dataUriPrefix != null) ? dataUriPrefix : 'data:image/png;base64,';
  1226. data = dataUriPrefix + this.base64Encode(data);
  1227. }
  1228. success(data);
  1229. }
  1230. }
  1231. else if (error != null)
  1232. {
  1233. error({code: App.ERROR_UNKNOWN}, req);
  1234. }
  1235. }), function()
  1236. {
  1237. if (error != null)
  1238. {
  1239. error({code: App.ERROR_UNKNOWN});
  1240. }
  1241. }, binary, this.timeout, function()
  1242. {
  1243. if (retry && error != null)
  1244. {
  1245. error({code: App.ERROR_TIMEOUT, retry: fn});
  1246. }
  1247. });
  1248. });
  1249. fn();
  1250. }
  1251. catch (e)
  1252. {
  1253. if (error != null)
  1254. {
  1255. error(e);
  1256. }
  1257. }
  1258. };
  1259. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1260. /**
  1261. * For the fontCSS to be applied when rendering images on canvas, the actual
  1262. * font data must be made available via a data URI encoding of the file.
  1263. */
  1264. Editor.prototype.loadFonts = function(then)
  1265. {
  1266. if (this.fontCss != null && this.resolvedFontCss == null)
  1267. {
  1268. var parts = this.fontCss.split('url(');
  1269. var waiting = 0;
  1270. var fonts = {};
  1271. // Strips leading and trailing quotes and spaces
  1272. function trimString(str)
  1273. {
  1274. return str.replace(new RegExp("^[\\s\"']+", "g"), "").replace(new RegExp("[\\s\"']+$", "g"), "");
  1275. };
  1276. var finish = mxUtils.bind(this, function()
  1277. {
  1278. if (waiting == 0)
  1279. {
  1280. // Constructs string
  1281. var result = [parts[0]];
  1282. for (var j = 1; j < parts.length; j++)
  1283. {
  1284. var idx = parts[j].indexOf(')');
  1285. result.push('url("');
  1286. result.push(fonts[trimString(parts[j].substring(0, idx))]);
  1287. result.push('"' + parts[j].substring(idx));
  1288. }
  1289. this.resolvedFontCss = result.join('');
  1290. then();
  1291. }
  1292. });
  1293. if (parts.length > 0)
  1294. {
  1295. for (var i = 1; i < parts.length; i++)
  1296. {
  1297. var idx = parts[i].indexOf(')');
  1298. var format = null;
  1299. // Checks if there is a format directive
  1300. var fmtIdx = parts[i].indexOf('format(', idx);
  1301. if (fmtIdx > 0)
  1302. {
  1303. format = trimString(parts[i].substring(fmtIdx + 7, parts[i].indexOf(')', fmtIdx)));
  1304. }
  1305. (mxUtils.bind(this, function(url)
  1306. {
  1307. if (fonts[url] == null)
  1308. {
  1309. // Mark font es being fetched and fetch it
  1310. fonts[url] = url;
  1311. waiting++;
  1312. var mime = 'application/x-font-ttf';
  1313. // See https://stackoverflow.com/questions/2871655/proper-mime-type-for-fonts
  1314. if (format == 'svg' || /(\.svg)($|\?)/i.test(url))
  1315. {
  1316. mime = 'image/svg+xml';
  1317. }
  1318. else if (format == 'otf' || format == 'embedded-opentype' || /(\.otf)($|\?)/i.test(url))
  1319. {
  1320. mime = 'application/x-font-opentype';
  1321. }
  1322. else if (format == 'woff' || /(\.woff)($|\?)/i.test(url))
  1323. {
  1324. mime = 'application/font-woff';
  1325. }
  1326. else if (format == 'woff2' || /(\.woff2)($|\?)/i.test(url))
  1327. {
  1328. mime = 'application/font-woff2';
  1329. }
  1330. else if (format == 'eot' || /(\.eot)($|\?)/i.test(url))
  1331. {
  1332. mime = 'application/vnd.ms-fontobject';
  1333. }
  1334. else if (format == 'sfnt' || /(\.sfnt)($|\?)/i.test(url))
  1335. {
  1336. mime = 'application/font-sfnt';
  1337. }
  1338. var realUrl = url;
  1339. if ((/^https?:\/\//.test(realUrl)) && !this.isCorsEnabledForUrl(realUrl))
  1340. {
  1341. realUrl = PROXY_URL + '?url=' + encodeURIComponent(url);
  1342. }
  1343. // LATER: Remove cache-control header
  1344. this.loadUrl(realUrl, mxUtils.bind(this, function(uri)
  1345. {
  1346. fonts[url] = uri;
  1347. waiting--;
  1348. finish();
  1349. }), mxUtils.bind(this, function(err)
  1350. {
  1351. // LATER: handle error
  1352. waiting--;
  1353. finish();
  1354. }), true, null, 'data:' + mime + ';charset=utf-8;base64,');
  1355. }
  1356. }))(trimString(parts[i].substring(0, idx)), format);
  1357. }
  1358. }
  1359. }
  1360. else
  1361. {
  1362. then();
  1363. }
  1364. };
  1365. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1366. /**
  1367. * Converts math in the given SVG
  1368. */
  1369. Editor.prototype.convertMath = function(graph, svgRoot, fixPosition, callback)
  1370. {
  1371. if (graph.mathEnabled && typeof(MathJax) !== 'undefined' && typeof(MathJax.Hub) !== 'undefined')
  1372. {
  1373. // Temporarily attaches to DOM for rendering
  1374. // FIXME: If adding svgRoot to body, the text
  1375. // value of the math is appended, if not
  1376. // added to DOM then LaTeX does not work.
  1377. // This must be fixed to enable client-side export
  1378. // if math is enabled.
  1379. // document.body.appendChild(svgRoot);
  1380. Editor.MathJaxRender(svgRoot);
  1381. window.setTimeout(mxUtils.bind(this, function()
  1382. {
  1383. MathJax.Hub.Queue(mxUtils.bind(this, function ()
  1384. {
  1385. // Removes from DOM
  1386. // svgRoot.parentNode.removeChild(svgRoot);
  1387. callback();
  1388. }));
  1389. }), 0);
  1390. }
  1391. else
  1392. {
  1393. callback();
  1394. }
  1395. };
  1396. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1397. /**
  1398. * See fixme in convertMath for client-side image generation with math.
  1399. */
  1400. Editor.prototype.isExportToCanvas = function()
  1401. {
  1402. return mxClient.IS_CHROMEAPP || (!this.graph.mathEnabled && this.useCanvasForExport);
  1403. };
  1404. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1405. /**
  1406. *
  1407. */
  1408. Editor.prototype.exportToCanvas = function(callback, width, imageCache, background, error, limitHeight,
  1409. ignoreSelection, scale, transparentBackground, addShadow, converter, graph, border, noCrop)
  1410. {
  1411. limitHeight = (limitHeight != null) ? limitHeight : true;
  1412. ignoreSelection = (ignoreSelection != null) ? ignoreSelection : true;
  1413. graph = (graph != null) ? graph : this.graph;
  1414. border = (border != null) ? border : 0;
  1415. var bg = (transparentBackground) ? null : graph.background;
  1416. if (bg == mxConstants.NONE)
  1417. {
  1418. bg = null;
  1419. }
  1420. if (bg == null)
  1421. {
  1422. bg = background;
  1423. }
  1424. // Handles special case where background is null but transparent is false
  1425. if (bg == null && transparentBackground == false)
  1426. {
  1427. bg = this.graph.defaultPageBackgroundColor;
  1428. }
  1429. this.convertImages(graph.getSvg(bg, null, null, noCrop, null, ignoreSelection, null, null, null, addShadow),
  1430. mxUtils.bind(this, function(svgRoot)
  1431. {
  1432. var img = new Image();
  1433. img.onload = mxUtils.bind(this, function()
  1434. {
  1435. try
  1436. {
  1437. var canvas = document.createElement('canvas');
  1438. var w = parseInt(svgRoot.getAttribute('width'));
  1439. var h = parseInt(svgRoot.getAttribute('height'));
  1440. scale = (scale != null) ? scale : 1;
  1441. if (width != null)
  1442. {
  1443. scale = (!limitHeight) ? width / w : Math.min(1, Math.min((width * 3) / (h * 4), width / w));
  1444. }
  1445. w = Math.ceil(scale * w) + 2 * border;
  1446. h = Math.ceil(scale * h) + 2 * border;
  1447. canvas.setAttribute('width', w);
  1448. canvas.setAttribute('height', h);
  1449. var ctx = canvas.getContext('2d');
  1450. if (bg != null)
  1451. {
  1452. ctx.beginPath();
  1453. ctx.rect(0, 0, w, h);
  1454. ctx.fillStyle = bg;
  1455. ctx.fill();
  1456. }
  1457. ctx.scale(scale, scale);
  1458. // Workaround for broken data URI images in Safari on first export
  1459. if (mxClient.IS_SF)
  1460. {
  1461. window.setTimeout(function()
  1462. {
  1463. ctx.drawImage(img, border / scale, border / scale);
  1464. callback(canvas);
  1465. }, 0);
  1466. }
  1467. else
  1468. {
  1469. ctx.drawImage(img, border / scale, border / scale);
  1470. callback(canvas);
  1471. }
  1472. }
  1473. catch (e)
  1474. {
  1475. if (error != null)
  1476. {
  1477. error(e);
  1478. }
  1479. }
  1480. });
  1481. img.onerror = function(e)
  1482. {
  1483. //console.log('img', e, img.src);
  1484. if (error != null)
  1485. {
  1486. error(e);
  1487. }
  1488. };
  1489. try
  1490. {
  1491. if (addShadow)
  1492. {
  1493. this.graph.addSvgShadow(svgRoot);
  1494. }
  1495. var done = mxUtils.bind(this, function()
  1496. {
  1497. if (this.resolvedFontCss != null)
  1498. {
  1499. var st = document.createElement('style');
  1500. st.setAttribute('type', 'text/css');
  1501. st.innerHTML = this.resolvedFontCss;
  1502. // Must be in defs section for FF to work
  1503. var defs = svgRoot.getElementsByTagName('defs');
  1504. defs[0].appendChild(st);
  1505. }
  1506. this.convertMath(graph, svgRoot, true, mxUtils.bind(this, function()
  1507. {
  1508. img.src = this.createSvgDataUri(mxUtils.getXml(svgRoot));
  1509. }));
  1510. });
  1511. this.loadFonts(done);
  1512. }
  1513. catch (e)
  1514. {
  1515. //console.log('src', e, img.src);
  1516. if (error != null)
  1517. {
  1518. error(e);
  1519. }
  1520. }
  1521. }), imageCache, converter);
  1522. };
  1523. //TODO This function is a replica of EditorUi one, it is planned to replace all calls to EditorUi one to point to this one
  1524. /**
  1525. * Adds the given text to the compressed or non-compressed text chunk.
  1526. */
  1527. Editor.prototype.writeGraphModelToPng = function(data, type, key, value, error)
  1528. {
  1529. var base64 = data.substring(data.indexOf(',') + 1);
  1530. var f = (window.atob) ? atob(base64) : Base64.decode(base64, true);
  1531. var pos = 0;
  1532. function fread(d, count)
  1533. {
  1534. var start = pos;
  1535. pos += count;
  1536. return d.substring(start, pos);
  1537. };
  1538. // Reads unsigned long 32 bit big endian
  1539. function _freadint(d)
  1540. {
  1541. var bytes = fread(d, 4);
  1542. return bytes.charCodeAt(3) + (bytes.charCodeAt(2) << 8) +
  1543. (bytes.charCodeAt(1) << 16) + (bytes.charCodeAt(0) << 24);
  1544. };
  1545. function writeInt(num)
  1546. {
  1547. return String.fromCharCode((num >> 24) & 0x000000ff, (num >> 16) & 0x000000ff,
  1548. (num >> 8) & 0x000000ff, num & 0x000000ff);
  1549. };
  1550. // Checks signature
  1551. if (fread(f,8) != String.fromCharCode(137) + 'PNG' + String.fromCharCode(13, 10, 26, 10))
  1552. {
  1553. if (error != null)
  1554. {
  1555. error();
  1556. }
  1557. return;
  1558. }
  1559. // Reads header chunk
  1560. fread(f,4);
  1561. if (fread(f,4) != 'IHDR')
  1562. {
  1563. if (error != null)
  1564. {
  1565. error();
  1566. }
  1567. return;
  1568. }
  1569. fread(f, 17);
  1570. var result = f.substring(0, pos);
  1571. do
  1572. {
  1573. var n = _freadint(f);
  1574. var chunk = fread(f,4);
  1575. if (chunk == 'IDAT')
  1576. {
  1577. result = f.substring(0, pos - 8);
  1578. var chunkData = key + String.fromCharCode(0) +
  1579. ((type == 'zTXt') ? String.fromCharCode(0) : '') +
  1580. value;
  1581. var crc = 0xffffffff;
  1582. crc = EditorUi.prototype.updateCRC(crc, type, 0, 4); //TODO move code to Editor?
  1583. crc = EditorUi.prototype.updateCRC(crc, chunkData, 0, chunkData.length);
  1584. result += writeInt(chunkData.length) + type + chunkData + writeInt(crc ^ 0xffffffff);
  1585. result += f.substring(pos - 8, f.length);
  1586. break;
  1587. }
  1588. result += f.substring(pos - 8, pos - 4 + n);
  1589. fread(f,n);
  1590. fread(f,4);
  1591. }
  1592. while (n);
  1593. return 'data:image/png;base64,' + ((window.btoa) ? btoa(result) : Base64.encode(result, true));
  1594. }
  1595. /**
  1596. * Adds persistence for recent colors
  1597. */
  1598. if (window.ColorDialog)
  1599. {
  1600. FilenameDialog.filenameHelpLink = 'https://desk.draw.io/support/solutions/articles/16000091426';
  1601. var colorDialogAddRecentColor = ColorDialog.addRecentColor;
  1602. ColorDialog.addRecentColor = function(color, max)
  1603. {
  1604. colorDialogAddRecentColor.apply(this, arguments);
  1605. mxSettings.setRecentColors(ColorDialog.recentColors);
  1606. mxSettings.save();
  1607. };
  1608. var colorDialogResetRecentColors = ColorDialog.resetRecentColors;
  1609. ColorDialog.resetRecentColors = function()
  1610. {
  1611. colorDialogResetRecentColors.apply(this, arguments);
  1612. mxSettings.setRecentColors(ColorDialog.recentColors);
  1613. mxSettings.save();
  1614. };
  1615. }
  1616. // Overrides ID for pages
  1617. if (window.EditDataDialog)
  1618. {
  1619. EditDataDialog.getDisplayIdForCell = function(ui, cell)
  1620. {
  1621. var id = null;
  1622. if (ui.editor.graph.getModel().getParent(cell) != null)
  1623. {
  1624. id = cell.getId();
  1625. }
  1626. else if (ui.currentPage != null)
  1627. {
  1628. id = ui.currentPage.getId();
  1629. }
  1630. return id;
  1631. };
  1632. }
  1633. var AddCustomPropertyDialog = function(editorUi, callback)
  1634. {
  1635. var row, td;
  1636. var table = document.createElement('table');
  1637. var tbody = document.createElement('tbody');
  1638. table.setAttribute('cellpadding', (mxClient.IS_SF) ? '0' : '2');
  1639. row = document.createElement('tr');
  1640. td = document.createElement('td');
  1641. td.style.fontSize = '10pt';
  1642. td.style.width = '100px';
  1643. mxUtils.write(td, mxResources.get('name', null, 'Name') + ':');
  1644. row.appendChild(td);
  1645. var nameInput = document.createElement('input');
  1646. nameInput.style.width = '180px';
  1647. td = document.createElement('td');
  1648. td.appendChild(nameInput);
  1649. row.appendChild(td);
  1650. tbody.appendChild(row);
  1651. row = document.createElement('tr');
  1652. td = document.createElement('td');
  1653. td.style.fontSize = '10pt';
  1654. mxUtils.write(td, mxResources.get('type', null, 'Type') + ':');
  1655. row.appendChild(td);
  1656. var typeSelect = document.createElement('select');
  1657. typeSelect.style.width = '180px';
  1658. var boolOption = document.createElement('option');
  1659. boolOption.setAttribute('value', 'bool');
  1660. mxUtils.write(boolOption, mxResources.get('bool', null, 'Boolean'));
  1661. typeSelect.appendChild(boolOption);
  1662. var clrOption = document.createElement('option');
  1663. clrOption.setAttribute('value', 'color');
  1664. mxUtils.write(clrOption, mxResources.get('color', null, 'Color'));
  1665. typeSelect.appendChild(clrOption);
  1666. var enumOption = document.createElement('option');
  1667. enumOption.setAttribute('value', 'enum');
  1668. mxUtils.write(enumOption, mxResources.get('enum', null, 'Enumeration'));
  1669. typeSelect.appendChild(enumOption);
  1670. var floatOption = document.createElement('option');
  1671. floatOption.setAttribute('value', 'float');
  1672. mxUtils.write(floatOption, mxResources.get('float', null, 'Float'));
  1673. typeSelect.appendChild(floatOption);
  1674. var intOption = document.createElement('option');
  1675. intOption.setAttribute('value', 'int');
  1676. mxUtils.write(intOption, mxResources.get('int', null, 'Int'));
  1677. typeSelect.appendChild(intOption);
  1678. var strOption = document.createElement('option');
  1679. strOption.setAttribute('value', 'string');
  1680. mxUtils.write(strOption, mxResources.get('string', null, 'String'));
  1681. typeSelect.appendChild(strOption);
  1682. td = document.createElement('td');
  1683. td.appendChild(typeSelect);
  1684. row.appendChild(td);
  1685. tbody.appendChild(row);
  1686. row = document.createElement('tr');
  1687. td = document.createElement('td');
  1688. td.style.fontSize = '10pt';
  1689. mxUtils.write(td, mxResources.get('dispName', null, 'Display Name') + ':');
  1690. row.appendChild(td);
  1691. var dispNameInput = document.createElement('input');
  1692. dispNameInput.style.width = '180px';
  1693. td = document.createElement('td');
  1694. td.appendChild(dispNameInput);
  1695. row.appendChild(td);
  1696. tbody.appendChild(row);
  1697. var listRow = document.createElement('tr');
  1698. td = document.createElement('td');
  1699. td.style.fontSize = '10pt';
  1700. mxUtils.write(td, mxResources.get('enumList', null, 'Enum List') + ' (csv):');
  1701. listRow.appendChild(td);
  1702. var enumListInput = document.createElement('input');
  1703. enumListInput.style.width = '180px';
  1704. td = document.createElement('td');
  1705. td.appendChild(enumListInput);
  1706. listRow.appendChild(td);
  1707. listRow.style.display = 'none';
  1708. tbody.appendChild(listRow);
  1709. table.appendChild(tbody);
  1710. function typeChanged()
  1711. {
  1712. if (typeSelect.value === 'enum')
  1713. {
  1714. listRow.style.display = '';
  1715. this.container.parentNode.style.height = "150px";
  1716. }
  1717. else
  1718. {
  1719. listRow.style.display = 'none';
  1720. this.container.parentNode.style.height = "130px";
  1721. }
  1722. };
  1723. mxEvent.addListener(typeSelect, 'change', mxUtils.bind(this, typeChanged));
  1724. row = document.createElement('tr');
  1725. td = document.createElement('td');
  1726. td.setAttribute('align', 'right');
  1727. td.style.paddingTop = '22px';
  1728. td.colSpan = 2;
  1729. var addBtn = mxUtils.button(mxResources.get('add', null, 'Add'), mxUtils.bind(this, function()
  1730. {
  1731. var name = nameInput.value;
  1732. if (name == "")
  1733. {
  1734. nameInput.style.border = "1px solid red";
  1735. return;
  1736. }
  1737. var type = typeSelect.value;
  1738. var dispName = dispNameInput.value;
  1739. if (dispName == "")
  1740. {
  1741. dispNameInput.style.border = "1px solid red";
  1742. return;
  1743. }
  1744. var enumList = enumListInput.value;
  1745. if (enumList == "" && type == "enum")
  1746. {
  1747. enumListInput.style.border = "1px solid red";
  1748. return;
  1749. }
  1750. if (enumList != null)
  1751. {
  1752. enumList = enumList.split(',');
  1753. for (var i = 0; i < enumList.length; i++)
  1754. {
  1755. enumList[i] = enumList[i].trim();
  1756. }
  1757. }
  1758. if (callback)
  1759. {
  1760. callback(editorUi, name, type, dispName, enumList);
  1761. editorUi.hideDialog();
  1762. }
  1763. }));
  1764. addBtn.className = 'geBtn gePrimaryBtn';
  1765. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1766. {
  1767. editorUi.hideDialog();
  1768. });
  1769. cancelBtn.className = 'geBtn';
  1770. if (editorUi.editor.cancelFirst)
  1771. {
  1772. td.appendChild(cancelBtn);
  1773. td.appendChild(addBtn);
  1774. }
  1775. else
  1776. {
  1777. td.appendChild(addBtn);
  1778. td.appendChild(cancelBtn);
  1779. }
  1780. row.appendChild(td);
  1781. tbody.appendChild(row);
  1782. table.appendChild(tbody);
  1783. this.container = table;
  1784. };
  1785. if (window.StyleFormatPanel != null)
  1786. {
  1787. var formatInit = Format.prototype.init;
  1788. Format.prototype.init = function()
  1789. {
  1790. formatInit.apply(this, arguments);
  1791. this.editorUi.editor.addListener('fileLoaded', this.update);
  1792. };
  1793. var formatRefresh = Format.prototype.refresh;
  1794. Format.prototype.refresh = function()
  1795. {
  1796. if (this.editorUi.getCurrentFile() != null || urlParams['embed'] == '1' ||
  1797. this.editorUi.editor.chromeless)
  1798. {
  1799. formatRefresh.apply(this, arguments);
  1800. }
  1801. else
  1802. {
  1803. this.clear();
  1804. }
  1805. };
  1806. /**
  1807. * Hook for subclassers.
  1808. */
  1809. DiagramFormatPanel.prototype.isShadowOptionVisible = function()
  1810. {
  1811. var file = this.editorUi.getCurrentFile();
  1812. return urlParams['embed'] == '1' || (file != null && file.isEditable());
  1813. };
  1814. /**
  1815. * Option is not visible in default theme.
  1816. */
  1817. DiagramFormatPanel.prototype.isMathOptionVisible = function(div)
  1818. {
  1819. return false;
  1820. };
  1821. /**
  1822. * Add global shadow option.
  1823. */
  1824. var diagramFormatPanelAddView = DiagramFormatPanel.prototype.addView;
  1825. DiagramFormatPanel.prototype.addView = function(div)
  1826. {
  1827. var div = diagramFormatPanelAddView.apply(this, arguments);
  1828. var file = this.editorUi.getCurrentFile();
  1829. if (mxClient.IS_SVG && this.isShadowOptionVisible())
  1830. {
  1831. var ui = this.editorUi;
  1832. var editor = ui.editor;
  1833. var graph = editor.graph;
  1834. var option = this.createOption(mxResources.get('shadow'), function()
  1835. {
  1836. return graph.shadowVisible;
  1837. }, function(checked)
  1838. {
  1839. var change = new ChangePageSetup(ui);
  1840. change.ignoreColor = true;
  1841. change.ignoreImage = true;
  1842. change.shadowVisible = checked;
  1843. graph.model.execute(change);
  1844. },
  1845. {
  1846. install: function(apply)
  1847. {
  1848. this.listener = function()
  1849. {
  1850. apply(graph.shadowVisible);
  1851. };
  1852. ui.addListener('shadowVisibleChanged', this.listener);
  1853. },
  1854. destroy: function()
  1855. {
  1856. ui.removeListener(this.listener);
  1857. }
  1858. });
  1859. if (!Editor.shadowOptionEnabled)
  1860. {
  1861. option.getElementsByTagName('input')[0].setAttribute('disabled', 'disabled');
  1862. mxUtils.setOpacity(option, 60);
  1863. }
  1864. div.appendChild(option);
  1865. }
  1866. return div;
  1867. };
  1868. /**
  1869. * Adds autosave and math typesetting options.
  1870. */
  1871. var diagramFormatPanelAddOptions = DiagramFormatPanel.prototype.addOptions;
  1872. DiagramFormatPanel.prototype.addOptions = function(div)
  1873. {
  1874. div = diagramFormatPanelAddOptions.apply(this, arguments);
  1875. var ui = this.editorUi;
  1876. var editor = ui.editor;
  1877. var graph = editor.graph;
  1878. if (graph.isEnabled())
  1879. {
  1880. var file = ui.getCurrentFile();
  1881. if (file != null && file.isAutosaveOptional())
  1882. {
  1883. var opt = this.createOption(mxResources.get('autosave'), function()
  1884. {
  1885. return ui.editor.autosave;
  1886. }, function(checked)
  1887. {
  1888. ui.editor.setAutosave(checked);
  1889. if (ui.editor.autosave && file.isModified())
  1890. {
  1891. file.fileChanged();
  1892. }
  1893. },
  1894. {
  1895. install: function(apply)
  1896. {
  1897. this.listener = function()
  1898. {
  1899. apply(ui.editor.autosave);
  1900. };
  1901. ui.editor.addListener('autosaveChanged', this.listener);
  1902. },
  1903. destroy: function()
  1904. {
  1905. ui.editor.removeListener(this.listener);
  1906. }
  1907. });
  1908. div.appendChild(opt);
  1909. }
  1910. }
  1911. if (this.isMathOptionVisible() && graph.isEnabled() && typeof(MathJax) !== 'undefined')
  1912. {
  1913. // Math
  1914. var option = this.createOption(mxResources.get('mathematicalTypesetting'), function()
  1915. {
  1916. return graph.mathEnabled;
  1917. }, function(checked)
  1918. {
  1919. ui.actions.get('mathematicalTypesetting').funct();
  1920. },
  1921. {
  1922. install: function(apply)
  1923. {
  1924. this.listener = function()
  1925. {
  1926. apply(graph.mathEnabled);
  1927. };
  1928. ui.addListener('mathEnabledChanged', this.listener);
  1929. },
  1930. destroy: function()
  1931. {
  1932. ui.removeListener(this.listener);
  1933. }
  1934. });
  1935. option.style.paddingTop = '5px';
  1936. div.appendChild(option);
  1937. var help = ui.menus.createHelpLink('https://desk.draw.io/support/solutions/articles/16000032875');
  1938. help.style.position = 'relative';
  1939. help.style.marginLeft = '6px';
  1940. help.style.top = '2px';
  1941. option.appendChild(help);
  1942. }
  1943. return div;
  1944. };
  1945. mxCellRenderer.prototype.defaultVertexShape.prototype.customProperties = [
  1946. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  1947. {name: 'absoluteArcSize', dispName: 'Abs. Arc Size', type: 'bool', defVal: false}
  1948. ];
  1949. mxCellRenderer.defaultShapes['link'].prototype.customProperties = [
  1950. {name: 'width', dispName: 'Width', type: 'float', min:0, defVal: 4}
  1951. ];
  1952. mxCellRenderer.defaultShapes['flexArrow'].prototype.customProperties = [
  1953. {name: 'width', dispName: 'Width', type: 'float', min:0, defVal: 10},
  1954. {name: 'startWidth', dispName: 'Start Width', type: 'float', min:0, defVal: 20},
  1955. {name: 'endWidth', dispName: 'End Width', type: 'float', min:0, defVal: 20}
  1956. ];
  1957. mxCellRenderer.defaultShapes['process'].prototype.customProperties = [
  1958. {name: 'size', dispName: 'Indent', type: 'float', min: 0, max: 0.5, defVal: 0.1}
  1959. ];
  1960. mxCellRenderer.defaultShapes['rhombus'].prototype.customProperties = [
  1961. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, max: 50, defVal: mxConstants.LINE_ARCSIZE},
  1962. {name: 'double', dispName: 'Double', type: 'bool', defVal: false}
  1963. ];
  1964. mxCellRenderer.defaultShapes['partialRectangle'].prototype.customProperties = [
  1965. {name: 'top', dispName: 'Top Line', type: 'bool', defVal: true},
  1966. {name: 'bottom', dispName: 'Bottom Line', type: 'bool', defVal: true},
  1967. {name: 'left', dispName: 'Left Line', type: 'bool', defVal: true},
  1968. {name: 'right', dispName: 'Right Line', type: 'bool', defVal: true}
  1969. ];
  1970. mxCellRenderer.defaultShapes['parallelogram'].prototype.customProperties = [
  1971. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  1972. {name: 'size', dispName: 'Slope Angle', type: 'float', min:0, max: 1, defVal: 0.2}
  1973. ];
  1974. mxCellRenderer.defaultShapes['hexagon'].prototype.customProperties = [
  1975. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  1976. {name: 'size', dispName: 'Slope Angle', type: 'float', min:0, max: 1, defVal: 0.25}
  1977. ];
  1978. mxCellRenderer.defaultShapes['triangle'].prototype.customProperties = [
  1979. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE}
  1980. ];
  1981. mxCellRenderer.defaultShapes['document'].prototype.customProperties = [
  1982. {name: 'size', dispName: 'Size', type: 'float', defVal: 0.3, min:0, max:1}
  1983. ];
  1984. mxCellRenderer.defaultShapes['internalStorage'].prototype.customProperties = [
  1985. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  1986. {name: 'dx', dispName: 'Left Line', type: 'float', min:0, defVal: 20},
  1987. {name: 'dy', dispName: 'Top Line', type: 'float', min:0, defVal: 20}
  1988. ];
  1989. mxCellRenderer.defaultShapes['cube'].prototype.customProperties = [
  1990. {name: 'size', dispName: 'Size', type: 'float', min:0, defVal:20 },
  1991. {name: 'darkOpacity', dispName: 'Dark Opacity', type: 'float', min:-1, max:1, defVal:0 },
  1992. {name: 'darkOpacity2', dispName: 'Dark Opacity 2', type: 'float', min:-1, max:1, defVal:0 }
  1993. ];
  1994. mxCellRenderer.defaultShapes['step'].prototype.customProperties = [
  1995. {name: 'size', dispName: 'Notch Size', type: 'float', min:0, defVal:20},
  1996. {name: 'fixedSize', dispName: 'Fixed Size', type: 'bool', defVal:true}
  1997. ];
  1998. mxCellRenderer.defaultShapes['trapezoid'].prototype.customProperties = [
  1999. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  2000. {name: 'size', dispName: 'Slope Angle', type: 'float', min:0, max: 1, defVal: 0.2}
  2001. ];
  2002. mxCellRenderer.defaultShapes['tape'].prototype.customProperties = [
  2003. {name: 'size', dispName: 'Size', type: 'float', min:0, max:1, defVal:0.4 }
  2004. ];
  2005. mxCellRenderer.defaultShapes['note'].prototype.customProperties = [
  2006. {name: 'size', dispName: 'Fold Size', type: 'float', min:0, defVal: 30},
  2007. {name: 'darkOpacity', dispName: 'Dark Opacity', type: 'float', min:-1, max:1, defVal:0 },
  2008. ];
  2009. mxCellRenderer.defaultShapes['card'].prototype.customProperties = [
  2010. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  2011. {name: 'size', dispName: 'Cutoff Size', type: 'float', min:0, defVal: 30}
  2012. ];
  2013. mxCellRenderer.defaultShapes['callout'].prototype.customProperties = [
  2014. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: mxConstants.LINE_ARCSIZE},
  2015. {name: 'base', dispName: 'Callout Width', type: 'float', min:0, defVal: 20},
  2016. {name: 'size', dispName: 'Callout Length', type: 'float', min:0, defVal: 30},
  2017. {name: 'position', dispName: 'Callout Position', type: 'float', min:0, max:1, defVal: 0.5},
  2018. {name: 'position2', dispName: 'Callout Tip Position', type: 'float', min:0, max:1, defVal: 0.5}
  2019. ];
  2020. mxCellRenderer.defaultShapes['folder'].prototype.customProperties = [
  2021. {name: 'tabWidth', dispName: 'Tab Width', type: 'float'},
  2022. {name: 'tabHeight', dispName: 'Tab Height', type: 'float'},
  2023. {name: 'tabPosition', dispName: 'Tap Position', type: 'enum',
  2024. enumList: [{val: 'left', dispName: 'Left'}, {val: 'right', dispName: 'Right'}]
  2025. }
  2026. ];
  2027. mxCellRenderer.defaultShapes['swimlane'].prototype.customProperties = [
  2028. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 15},
  2029. {name: 'startSize', dispName: 'Header Size', type: 'float'},
  2030. {name: 'horizontal', dispName: 'Horizontal', type: 'bool', defVal: true},
  2031. {name: 'separatorColor', dispName: 'Separator Color', type: 'color', defVal: null},
  2032. ];
  2033. mxCellRenderer.defaultShapes['doubleEllipse'].prototype.customProperties = [
  2034. {name: 'margin', dispName: 'Indent', type: 'float', min:0, defVal:4}
  2035. ];
  2036. mxCellRenderer.defaultShapes['ext'].prototype.customProperties = [
  2037. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 15},
  2038. {name: 'double', dispName: 'Double', type: 'bool', defVal: false},
  2039. {name: 'margin', dispName: 'Indent', type: 'float', min: 0, defVal:0}
  2040. ];
  2041. mxCellRenderer.defaultShapes['curlyBracket'].prototype.customProperties = [
  2042. {name: 'rounded', dispName: 'Rounded', type: 'bool', defVal: true},
  2043. {name: 'size', dispName: 'Size', type: 'float', min:0, max: 1, defVal: 0.5}
  2044. ];
  2045. mxCellRenderer.defaultShapes['image'].prototype.customProperties = [
  2046. {name: 'imageAspect', dispName: 'Fixed Image Aspect', type: 'bool', defVal:true}
  2047. ];
  2048. mxCellRenderer.defaultShapes['label'].prototype.customProperties = [
  2049. {name: 'imageAspect', dispName: 'Fixed Image Aspect', type: 'bool', defVal:true},
  2050. {name: 'imageAlign', dispName: 'Image Align', type: 'enum',
  2051. enumList: [{val: 'left', dispName: 'Left'},
  2052. {val: 'center', dispName: 'Center'},
  2053. {val: 'right', dispName: 'Right'}], defVal: 'left'},
  2054. {name: 'imageVerticalAlign', dispName: 'Image Vertical Align', type: 'enum',
  2055. enumList: [{val: 'top', dispName: 'Top'},
  2056. {val: 'middle', dispName: 'Middle'},
  2057. {val: 'bottom', dispName: 'Bottom'}], defVal: 'middle'},
  2058. {name: 'imageWidth', dispName: 'Image Width', type: 'float', min:0, defVal: 24},
  2059. {name: 'imageHeight', dispName: 'Image Height', type: 'float', min:0, defVal: 24},
  2060. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 12},
  2061. {name: 'absoluteArcSize', dispName: 'Abs. Arc Size', type: 'bool', defVal: false}
  2062. ];
  2063. mxCellRenderer.defaultShapes['dataStorage'].prototype.customProperties = [
  2064. {name: 'size', dispName: 'Size', type: 'float', min:0, max:1, defVal:0.1 }
  2065. ];
  2066. mxCellRenderer.defaultShapes['manualInput'].prototype.customProperties = [
  2067. {name: 'size', dispName: 'Size', type: 'float', min:0, defVal:30 },
  2068. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 20}
  2069. ];
  2070. mxCellRenderer.defaultShapes['loopLimit'].prototype.customProperties = [
  2071. {name: 'size', dispName: 'Size', type: 'float', min:0, defVal:20 },
  2072. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 20}
  2073. ];
  2074. mxCellRenderer.defaultShapes['offPageConnector'].prototype.customProperties = [
  2075. {name: 'size', dispName: 'Size', type: 'float', min:0, defVal:38 },
  2076. {name: 'arcSize', dispName: 'Arc Size', type: 'float', min:0, defVal: 20}
  2077. ];
  2078. mxCellRenderer.defaultShapes['display'].prototype.customProperties = [
  2079. {name: 'size', dispName: 'Size', type: 'float', min: 0, max: 1, defVal: 0.25 }
  2080. ];
  2081. mxCellRenderer.defaultShapes['singleArrow'].prototype.customProperties = [
  2082. {name: 'arrowWidth', dispName: 'Arrow Width', type: 'float', min: 0, max: 1, defVal: 0.3 },
  2083. {name: 'arrowSize', dispName: 'Arrowhead Length', type: 'float', min: 0, max: 1, defVal: 0.2 }
  2084. ];
  2085. mxCellRenderer.defaultShapes['doubleArrow'].prototype.customProperties = [
  2086. {name: 'arrowWidth', dispName: 'Arrow Width', type: 'float', min: 0, max: 1, defVal: 0.3 },
  2087. {name: 'arrowSize', dispName: 'Arrowhead Length', type: 'float', min: 0, max: 1, defVal: 0.2 }
  2088. ];
  2089. mxCellRenderer.defaultShapes['cross'].prototype.customProperties = [
  2090. {name: 'size', dispName: 'Size', type: 'float', min: 0, max: 1, defVal: 0.2 }
  2091. ];
  2092. mxCellRenderer.defaultShapes['corner'].prototype.customProperties = [
  2093. {name: 'dx', dispName: 'Width1', type: 'float', min: 0, defVal: 20 },
  2094. {name: 'dy', dispName: 'Width2', type: 'float', min: 0, defVal: 20 }
  2095. ];
  2096. mxCellRenderer.defaultShapes['tee'].prototype.customProperties = [
  2097. {name: 'dx', dispName: 'Width1', type: 'float', min: 0, defVal: 20 },
  2098. {name: 'dy', dispName: 'Width2', type: 'float', min: 0, defVal: 20 }
  2099. ];
  2100. mxCellRenderer.defaultShapes['umlLifeline'].prototype.customProperties = [
  2101. {name: 'participant', dispName:'Participant', type:'enum', defVal:'none', enumList:[
  2102. {val:'none', dispName: 'Default'},
  2103. {val:'umlActor', dispName: 'Actor'},
  2104. {val:'umlBoundary', dispName: 'Boundary'},
  2105. {val:'umlEntity', dispName: 'Entity'},
  2106. {val:'umlControl', dispName: 'Control'},
  2107. ]},
  2108. {name: 'size', dispName:'Height', type:'float', defVal:40, min:0}
  2109. ];
  2110. mxCellRenderer.defaultShapes['umlFrame'].prototype.customProperties = [
  2111. {name: 'width', dispName:'Title Width', type:'float', defVal:60, min:0},
  2112. {name: 'height', dispName:'Title Height', type:'float', defVal:30, min:0}
  2113. ];
  2114. /**
  2115. * Configures global color schemes.
  2116. */
  2117. StyleFormatPanel.prototype.defaultColorSchemes = [[{fill: '', stroke: ''}, {fill: '#f5f5f5', stroke: '#666666', font: '#333333'},
  2118. {fill: '#dae8fc', stroke: '#6c8ebf'}, {fill: '#d5e8d4', stroke: '#82b366'},
  2119. {fill: '#ffe6cc', stroke: '#d79b00'}, {fill: '#fff2cc', stroke: '#d6b656'},
  2120. {fill: '#f8cecc', stroke: '#b85450'}, {fill: '#e1d5e7', stroke: '#9673a6'}],
  2121. [{fill: '#60a917', stroke: '#2D7600', font: '#ffffff'}, {fill: '#008a00', stroke: '#005700', font: '#ffffff'},
  2122. {fill: '#1ba1e2', stroke: '#006EAF', font: '#ffffff'}, {fill: '#0050ef', stroke: '#001DBC', font: '#ffffff'},
  2123. {fill: '#6a00ff', stroke: '#3700CC', font: '#ffffff'}, {fill: '#aa00ff', stroke: '#7700CC', font: '#ffffff'},
  2124. {fill: '#d80073', stroke: '#A50040', font: '#ffffff'}, {fill: '#a20025', stroke: '#6F0000', font: '#ffffff'}],
  2125. [{fill: '#e51400', stroke: '#B20000', font: '#ffffff'}, {fill: '#fa6800', stroke: '#C73500', font: '#ffffff'},
  2126. {fill: '#f0a30a', stroke: '#BD7000', font: '#ffffff'}, {fill: '#e3c800', stroke: '#B09500', font: '#ffffff'},
  2127. {fill: '#6d8764', stroke: '#3A5431', font: '#ffffff'}, {fill: '#647687', stroke: '#314354', font: '#ffffff'},
  2128. {fill: '#76608a', stroke: '#432D57', font: '#ffffff'}, {fill: '#a0522d', stroke: '#6D1F00', font: '#ffffff'}],
  2129. [{fill: '', stroke: ''}, {fill: mxConstants.NONE, stroke: ''},
  2130. {fill: '#fad7ac', stroke: '#b46504'}, {fill: '#fad9d5', stroke: '#ae4132'},
  2131. {fill: '#b0e3e6', stroke: '#0e8088'}, {fill: '#b1ddf0', stroke: '#10739e'},
  2132. {fill: '#d0cee2', stroke: '#56517e'}, {fill: '#bac8d3', stroke: '#23445d'}],
  2133. [{fill: '', stroke: ''},
  2134. {fill: '#f5f5f5', stroke: '#666666', gradient: '#b3b3b3'},
  2135. {fill: '#dae8fc', stroke: '#6c8ebf', gradient: '#7ea6e0'},
  2136. {fill: '#d5e8d4', stroke: '#82b366', gradient: '#97d077'},
  2137. {fill: '#ffcd28', stroke: '#d79b00', gradient: '#ffa500'},
  2138. {fill: '#fff2cc', stroke: '#d6b656', gradient: '#ffd966'},
  2139. {fill: '#f8cecc', stroke: '#b85450', gradient: '#ea6b66'},
  2140. {fill: '#e6d0de', stroke: '#996185', gradient: '#d5739d'}],
  2141. [{fill: '', stroke: ''}, {fill: '#eeeeee', stroke: '#36393d'},
  2142. {fill: '#f9f7ed', stroke: '#36393d'}, {fill: '#ffcc99', stroke: '#36393d'},
  2143. {fill: '#cce5ff', stroke: '#36393d'}, {fill: '#ffff88', stroke: '#36393d'},
  2144. {fill: '#cdeb8b', stroke: '#36393d'}, {fill: '#ffcccc', stroke: '#36393d'}]];
  2145. /**
  2146. * Configures custom color schemes.
  2147. */
  2148. StyleFormatPanel.prototype.customColorSchemes = null;
  2149. StyleFormatPanel.prototype.findCommonProperties = function(cell, properties, addAll)
  2150. {
  2151. if (properties == null) return;
  2152. var handleCustomProp = function(custProperties)
  2153. {
  2154. if (custProperties != null)
  2155. {
  2156. if (addAll)
  2157. {
  2158. for (var i = 0; i < custProperties.length; i++)
  2159. {
  2160. properties[custProperties[i].name] = custProperties[i];
  2161. }
  2162. }
  2163. else
  2164. {
  2165. for (var key in properties)
  2166. {
  2167. var found = false;
  2168. for (var i = 0; i < custProperties.length; i++)
  2169. {
  2170. if (custProperties[i].name == key && custProperties[i].type == properties[key].type)
  2171. {
  2172. found = true;
  2173. break;
  2174. }
  2175. }
  2176. if (!found)
  2177. {
  2178. delete properties[key];
  2179. }
  2180. }
  2181. }
  2182. }
  2183. };
  2184. var view = this.editorUi.editor.graph.view;
  2185. var state = view.getState(cell);
  2186. if (state != null && state.shape != null)
  2187. {
  2188. //Add common properties to all shapes
  2189. if (!state.shape.commonCustomPropAdded)
  2190. {
  2191. state.shape.commonCustomPropAdded = true;
  2192. state.shape.customProperties = state.shape.customProperties || [];
  2193. if (state.cell.vertex)
  2194. {
  2195. Array.prototype.push.apply(state.shape.customProperties, Editor.commonVertexProperties);
  2196. }
  2197. else
  2198. {
  2199. Array.prototype.push.apply(state.shape.customProperties, Editor.commonEdgeProperties);
  2200. }
  2201. }
  2202. handleCustomProp(state.shape.customProperties);
  2203. }
  2204. //This currently is not needed but let's keep it in case we needed in the future
  2205. var userCustomProp = cell.getAttribute('customProperties');
  2206. if (userCustomProp != null)
  2207. {
  2208. try
  2209. {
  2210. handleCustomProp(JSON.parse(userCustomProp));
  2211. }
  2212. catch(e){}
  2213. }
  2214. };
  2215. /**
  2216. * Adds predefiend styles.
  2217. */
  2218. var styleFormatPanelInit = StyleFormatPanel.prototype.init;
  2219. StyleFormatPanel.prototype.init = function()
  2220. {
  2221. // TODO: Update sstate in Format
  2222. var sstate = this.format.createSelectionState();
  2223. if (sstate.style.shape != 'image' && !sstate.containsLabel)
  2224. {
  2225. this.container.appendChild(this.addStyles(this.createPanel()));
  2226. }
  2227. styleFormatPanelInit.apply(this, arguments);
  2228. if (Editor.enableCustomProperties)
  2229. {
  2230. var properties = {};
  2231. var vertices = sstate.vertices;
  2232. var edges = sstate.edges;
  2233. for (var i = 0; i < vertices.length; i++)
  2234. {
  2235. this.findCommonProperties(vertices[i], properties, i == 0);
  2236. }
  2237. for (var i = 0; i < edges.length; i++)
  2238. {
  2239. this.findCommonProperties(edges[i], properties, vertices.length == 0 && i == 0);
  2240. }
  2241. if (Object.getOwnPropertyNames != null && Object.getOwnPropertyNames(properties).length > 0)
  2242. {
  2243. this.container.appendChild(this.addProperties(this.createPanel(), properties, sstate));
  2244. }
  2245. }
  2246. };
  2247. /**
  2248. * Overridden to add copy and paste style.
  2249. */
  2250. var styleFormatPanelAddStyleOps = StyleFormatPanel.prototype.addStyleOps;
  2251. StyleFormatPanel.prototype.addStyleOps = function(div)
  2252. {
  2253. var graph = this.editorUi.editor.graph;
  2254. var btn = mxUtils.button(mxResources.get('copyStyle'), mxUtils.bind(this, function(evt)
  2255. {
  2256. this.editorUi.actions.get('copyStyle').funct();
  2257. }));
  2258. btn.setAttribute('title', mxResources.get('copyStyle') + ' (' + this.editorUi.actions.get('copyStyle').shortcut + ')');
  2259. btn.style.marginBottom = '2px';
  2260. btn.style.width = '100px';
  2261. btn.style.marginRight = '2px';
  2262. div.appendChild(btn);
  2263. var btn = mxUtils.button(mxResources.get('pasteStyle'), mxUtils.bind(this, function(evt)
  2264. {
  2265. this.editorUi.actions.get('pasteStyle').funct();
  2266. }));
  2267. btn.setAttribute('title', mxResources.get('pasteStyle') + ' (' + this.editorUi.actions.get('pasteStyle').shortcut + ')');
  2268. btn.style.marginBottom = '2px';
  2269. btn.style.width = '100px';
  2270. div.appendChild(btn);
  2271. mxUtils.br(div);
  2272. return styleFormatPanelAddStyleOps.apply(this, arguments);
  2273. };
  2274. /**
  2275. * Initial collapsed state of the properties panel.
  2276. */
  2277. EditorUi.prototype.propertiesCollapsed = true;
  2278. /**
  2279. * Create Properties Panel
  2280. */
  2281. StyleFormatPanel.prototype.addProperties = function(div, properties, state)
  2282. {
  2283. var that = this;
  2284. var graph = this.editorUi.editor.graph;
  2285. var secondLevel = [];
  2286. function insertAfter(newElem, curElem)
  2287. {
  2288. curElem.parentNode.insertBefore(newElem, curElem.nextSibling);
  2289. };
  2290. function applyStyleVal(pName, newVal, prop, delIndex)
  2291. {
  2292. graph.getModel().beginUpdate();
  2293. try
  2294. {
  2295. var changedProps = [];
  2296. var changedVals = [];
  2297. if (prop.index != null)
  2298. {
  2299. var allVals = [];
  2300. var curVal = prop.parentRow.nextSibling;
  2301. while(curVal && curVal.getAttribute('data-pName') == pName)
  2302. {
  2303. allVals.push(curVal.getAttribute('data-pValue'));
  2304. curVal = curVal.nextSibling;
  2305. }
  2306. if (prop.index < allVals.length)
  2307. {
  2308. if (delIndex != null)
  2309. {
  2310. allVals.splice(delIndex, 1);
  2311. }
  2312. else
  2313. {
  2314. allVals[prop.index] = newVal;
  2315. }
  2316. }
  2317. else
  2318. {
  2319. allVals.push(newVal);
  2320. }
  2321. if (prop.size != null && allVals.length > prop.size) //trim the array to the specifies size
  2322. {
  2323. allVals = allVals.slice(0, prop.size);
  2324. }
  2325. newVal = allVals.join(',');
  2326. if (prop.countProperty != null)
  2327. {
  2328. graph.setCellStyles(prop.countProperty, allVals.length, graph.getSelectionCells());
  2329. changedProps.push(prop.countProperty);
  2330. changedVals.push(allVals.length);
  2331. }
  2332. }
  2333. graph.setCellStyles(pName, newVal, graph.getSelectionCells());
  2334. changedProps.push(pName);
  2335. changedVals.push(newVal);
  2336. if (prop.dependentProps != null)
  2337. {
  2338. for (var i = 0; i < prop.dependentProps.length; i++)
  2339. {
  2340. var defVal = prop.dependentPropsDefVal[i];
  2341. var vals = prop.dependentPropsVals[i];
  2342. if (vals.length > newVal)
  2343. {
  2344. vals = vals.slice(0, newVal);
  2345. }
  2346. else
  2347. {
  2348. for (var j = vals.length; j < newVal; j++)
  2349. {
  2350. vals.push(defVal);
  2351. }
  2352. }
  2353. vals = vals.join(',');
  2354. graph.setCellStyles(prop.dependentProps[i], vals, graph.getSelectionCells());
  2355. changedProps.push(prop.dependentProps[i]);
  2356. changedVals.push(vals);
  2357. }
  2358. }
  2359. if (typeof(prop.onChange) == 'function')
  2360. {
  2361. prop.onChange(graph, newVal);
  2362. }
  2363. that.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', changedProps,
  2364. 'values', changedVals, 'cells', graph.getSelectionCells()));
  2365. }
  2366. finally
  2367. {
  2368. graph.getModel().endUpdate();
  2369. }
  2370. }
  2371. function setElementPos(td, elem, adjustHeight)
  2372. {
  2373. var divPos = mxUtils.getOffset(div, true);
  2374. var pos = mxUtils.getOffset(td, true);
  2375. elem.style.position = 'absolute';
  2376. elem.style.left = (pos.x - divPos.x) + 'px';
  2377. elem.style.top = (pos.y - divPos.y) + 'px';
  2378. elem.style.width = td.offsetWidth + 'px';
  2379. elem.style.height = (td.offsetHeight - (adjustHeight? 4 : 0)) + 'px';
  2380. elem.style.zIndex = 5;
  2381. };
  2382. function createColorBtn(pName, pValue, prop)
  2383. {
  2384. var clrDiv = document.createElement('div');
  2385. clrDiv.style.width = '32px';
  2386. clrDiv.style.height = '4px';
  2387. clrDiv.style.margin = '2px';
  2388. clrDiv.style.border = '1px solid black';
  2389. clrDiv.style.background = !pValue || pValue == 'none'? 'url(\'' + Dialog.prototype.noColorImage + '\')' : pValue;
  2390. btn = mxUtils.button('', mxUtils.bind(that, function(evt)
  2391. {
  2392. this.editorUi.pickColor(pValue, function(color)
  2393. {
  2394. clrDiv.style.background = color == 'none'? 'url(\'' + Dialog.prototype.noColorImage + '\')' : color;
  2395. applyStyleVal(pName, color, prop);
  2396. });
  2397. mxEvent.consume(evt);
  2398. }));
  2399. btn.style.height = '12px';
  2400. btn.style.width = '40px';
  2401. btn.className = 'geColorBtn';
  2402. btn.appendChild(clrDiv);
  2403. return btn;
  2404. };
  2405. function createDynArrList(pName, pValue, subType, defVal, countProperty, myRow, flipBkg)
  2406. {
  2407. if (pValue != null)
  2408. {
  2409. var vals = pValue.split(',');
  2410. secondLevel.push({name: pName, values: vals, type: subType, defVal: defVal, countProperty: countProperty, parentRow: myRow, isDeletable: true, flipBkg: flipBkg});
  2411. }
  2412. btn = mxUtils.button('+', mxUtils.bind(that, function(evt)
  2413. {
  2414. var beforeElem = myRow;
  2415. var index = 0;
  2416. while (beforeElem.nextSibling != null)
  2417. {
  2418. var cur = beforeElem.nextSibling;
  2419. var elemPName = cur.getAttribute('data-pName');
  2420. if (elemPName == pName)
  2421. {
  2422. beforeElem = beforeElem.nextSibling;
  2423. index++;
  2424. }
  2425. else
  2426. {
  2427. break;
  2428. }
  2429. }
  2430. var newProp = {type: subType, parentRow: myRow, index: index, isDeletable: true, defVal: defVal, countProperty: countProperty};
  2431. var arrItem = createPropertyRow(pName, '', newProp, index % 2 == 0, flipBkg);
  2432. applyStyleVal(pName, defVal, newProp);
  2433. insertAfter(arrItem, beforeElem);
  2434. mxEvent.consume(evt);
  2435. }));
  2436. btn.style.height = '16px';
  2437. btn.style.width = '25px';
  2438. btn.className = 'geColorBtn';
  2439. return btn;
  2440. };
  2441. function createStaticArrList(pName, pValue, subType, defVal, size, myRow, flipBkg)
  2442. {
  2443. if (size > 0)
  2444. {
  2445. var vals = new Array(size);
  2446. var curVals = pValue != null? pValue.split(',') : [];
  2447. for (var i = 0; i < size; i++)
  2448. {
  2449. vals[i] = curVals[i] != null? curVals[i] : (defVal != null? defVal : '');
  2450. }
  2451. secondLevel.push({name: pName, values: vals, type: subType, defVal: defVal, parentRow: myRow, flipBkg: flipBkg, size: size});
  2452. }
  2453. return document.createElement('div'); //empty cell
  2454. };
  2455. function createCheckbox(pName, pValue, prop)
  2456. {
  2457. var input = document.createElement('input');
  2458. input.type = 'checkbox';
  2459. input.checked = pValue == '1';
  2460. mxEvent.addListener(input, 'change', function()
  2461. {
  2462. applyStyleVal(pName, input.checked? '1' : '0', prop);
  2463. });
  2464. return input;
  2465. };
  2466. function createPropertyRow(pName, pValue, prop, isOdd, flipBkg)
  2467. {
  2468. var pDiplayName = prop.dispName;
  2469. var pType = prop.type;
  2470. var row = document.createElement('tr');
  2471. row.className = 'gePropRow' + (flipBkg? 'Dark' : '') + (isOdd? 'Alt' : '') + ' gePropNonHeaderRow';
  2472. row.setAttribute('data-pName', pName);
  2473. row.setAttribute('data-pValue', pValue);
  2474. var rightAlig = false;
  2475. if (prop.index != null)
  2476. {
  2477. row.setAttribute('data-index', prop.index);
  2478. pDiplayName = (pDiplayName != null? pDiplayName : '') + '[' + prop.index + ']';
  2479. rightAlig = true;
  2480. }
  2481. var td = document.createElement('td');
  2482. td.className = 'gePropRowCell';
  2483. td.innerHTML = mxUtils.htmlEntities(mxResources.get(pDiplayName, null, pDiplayName));
  2484. if (rightAlig)
  2485. {
  2486. td.style.textAlign = 'right';
  2487. }
  2488. row.appendChild(td);
  2489. td = document.createElement('td');
  2490. td.className = 'gePropRowCell';
  2491. if (pType == 'color')
  2492. {
  2493. td.appendChild(createColorBtn(pName, pValue, prop));
  2494. }
  2495. else if (pType == 'bool' || pType == 'boolean')
  2496. {
  2497. td.appendChild(createCheckbox(pName, pValue, prop));
  2498. }
  2499. else if (pType == 'enum')
  2500. {
  2501. var pEnumList = prop.enumList;
  2502. for (var i = 0; i < pEnumList.length; i++)
  2503. {
  2504. var op = pEnumList[i];
  2505. if (op.val == pValue)
  2506. {
  2507. td.innerHTML = mxUtils.htmlEntities(mxResources.get(op.dispName, null, op.dispName));
  2508. break;
  2509. }
  2510. }
  2511. mxEvent.addListener(td, 'click', mxUtils.bind(that, function()
  2512. {
  2513. var select = document.createElement('select');
  2514. setElementPos(td, select);
  2515. for (var i = 0; i < pEnumList.length; i++)
  2516. {
  2517. var op = pEnumList[i];
  2518. var opElem = document.createElement('option');
  2519. opElem.value = mxUtils.htmlEntities(op.val);
  2520. opElem.innerHTML = mxUtils.htmlEntities(mxResources.get(op.dispName, null, op.dispName));
  2521. select.appendChild(opElem);
  2522. }
  2523. select.value = pValue;
  2524. div.appendChild(select);
  2525. mxEvent.addListener(select, 'change', function()
  2526. {
  2527. var newVal = mxUtils.htmlEntities(select.value);
  2528. applyStyleVal(pName, newVal, prop);
  2529. //set value triggers a redraw of the panel which removes the select and updates the row
  2530. });
  2531. select.focus();
  2532. //FF calls blur on focus! so set the event after focusing (not with selects but to be safe)
  2533. mxEvent.addListener(select, 'blur', function()
  2534. {
  2535. div.removeChild(select);
  2536. });
  2537. }));
  2538. }
  2539. else if (pType == 'dynamicArr')
  2540. {
  2541. td.appendChild(createDynArrList(pName, pValue, prop.subType, prop.subDefVal, prop.countProperty, row, flipBkg));
  2542. }
  2543. else if (pType == 'staticArr')
  2544. {
  2545. td.appendChild(createStaticArrList(pName, pValue, prop.subType, prop.subDefVal, prop.size, row, flipBkg));
  2546. }
  2547. else
  2548. {
  2549. td.innerHTML = pValue;
  2550. mxEvent.addListener(td, 'click', mxUtils.bind(that, function()
  2551. {
  2552. var input = document.createElement('input');
  2553. setElementPos(td, input, true);
  2554. input.value = pValue;
  2555. input.className = 'gePropEditor';
  2556. if ((pType == 'int' || pType == 'float') && !prop.allowAuto)
  2557. {
  2558. input.type = 'number';
  2559. input.step = pType == 'int'? '1' : 'any';
  2560. if (prop.min != null)
  2561. {
  2562. input.min = parseFloat(prop.min);
  2563. }
  2564. if (prop.max != null)
  2565. {
  2566. input.max = parseFloat(prop.max);
  2567. }
  2568. }
  2569. div.appendChild(input);
  2570. function setInputVal()
  2571. {
  2572. var inputVal = input.value;
  2573. inputVal = inputVal.length == 0 && pType != 'string'? 0 : inputVal;
  2574. if (prop.allowAuto)
  2575. {
  2576. if (inputVal.trim().toLowerCase() == 'auto')
  2577. {
  2578. inputVal = 'auto';
  2579. pType = 'string';
  2580. }
  2581. else
  2582. {
  2583. inputVal = parseFloat(inputVal);
  2584. inputVal = isNaN(inputVal)? 0 : inputVal;
  2585. }
  2586. }
  2587. if (prop.min != null && inputVal < prop.min)
  2588. {
  2589. inputVal = prop.min;
  2590. }
  2591. else if (prop.max != null && inputVal > prop.max)
  2592. {
  2593. inputVal = prop.max;
  2594. }
  2595. var newVal = mxUtils.htmlEntities((pType == 'int'? parseInt(inputVal) : inputVal) + '');
  2596. applyStyleVal(pName, newVal, prop);
  2597. }
  2598. mxEvent.addListener(input, 'keypress', function(e)
  2599. {
  2600. if (e.keyCode == 13)
  2601. {
  2602. setInputVal();
  2603. //set value triggers a redraw of the panel which removes the input
  2604. }
  2605. });
  2606. input.focus();
  2607. //FF calls blur on focus! so set the event after focusing
  2608. mxEvent.addListener(input, 'blur', function()
  2609. {
  2610. setInputVal();
  2611. });
  2612. }));
  2613. }
  2614. if (prop.isDeletable)
  2615. {
  2616. var delBtn = mxUtils.button('-', mxUtils.bind(that, function(evt)
  2617. {
  2618. //delete the node by refreshing the properties
  2619. applyStyleVal(pName, '', prop, prop.index);
  2620. mxEvent.consume(evt);
  2621. }));
  2622. delBtn.style.height = '16px';
  2623. delBtn.style.width = '25px';
  2624. delBtn.style.float = 'right';
  2625. delBtn.className = 'geColorBtn';
  2626. td.appendChild(delBtn);
  2627. }
  2628. row.appendChild(td);
  2629. return row;
  2630. };
  2631. div.style.position = 'relative';
  2632. div.style.padding = '0';
  2633. var grid = document.createElement('table');
  2634. grid.style.whiteSpace = 'nowrap';
  2635. grid.style.width = '100%';
  2636. //create header row
  2637. var hrow = document.createElement('tr');
  2638. hrow.className = 'gePropHeader';
  2639. var th = document.createElement('th');
  2640. th.className = 'gePropHeaderCell';
  2641. var collapseImg = document.createElement('img');
  2642. collapseImg.src = Sidebar.prototype.expandedImage;
  2643. th.appendChild(collapseImg);
  2644. mxUtils.write(th, mxResources.get('property'));
  2645. hrow.style.cursor = 'pointer';
  2646. var onFold = function()
  2647. {
  2648. var rows = grid.querySelectorAll('.gePropNonHeaderRow');
  2649. var display;
  2650. if (!that.editorUi.propertiesCollapsed)
  2651. {
  2652. collapseImg.src = Sidebar.prototype.expandedImage;
  2653. display = '';
  2654. }
  2655. else
  2656. {
  2657. collapseImg.src = Sidebar.prototype.collapsedImage;
  2658. display = 'none';
  2659. for (var e = div.childNodes.length - 1; e >= 0 ; e--)
  2660. {
  2661. //Blur can be executed concurrently with this method and the element is removed before removing it here
  2662. try
  2663. {
  2664. var child = div.childNodes[e];
  2665. var nodeName = child.nodeName.toUpperCase();
  2666. if (nodeName == 'INPUT' || nodeName == 'SELECT')
  2667. {
  2668. div.removeChild(child);
  2669. }
  2670. }
  2671. catch(ex){}
  2672. }
  2673. }
  2674. for (var r = 0; r < rows.length; r++)
  2675. {
  2676. rows[r].style.display = display;
  2677. }
  2678. };
  2679. mxEvent.addListener(hrow, 'click', function()
  2680. {
  2681. that.editorUi.propertiesCollapsed = !that.editorUi.propertiesCollapsed;
  2682. onFold();
  2683. });
  2684. hrow.appendChild(th);
  2685. th = document.createElement('th');
  2686. th.className = 'gePropHeaderCell';
  2687. th.innerHTML = mxResources.get('value');
  2688. hrow.appendChild(th);
  2689. grid.appendChild(hrow);
  2690. var isOdd = false;
  2691. var flipBkg = false;
  2692. for (var key in properties)
  2693. {
  2694. var prop = properties[key];
  2695. if (typeof(prop.isVisible) == 'function')
  2696. {
  2697. if (!prop.isVisible(state)) continue;
  2698. }
  2699. var pValue = state.style[key] != null? mxUtils.htmlEntities(state.style[key] + '') : prop.defVal; //or undefined if defVal is undefined
  2700. if (prop.type == 'separator')
  2701. {
  2702. flipBkg = !flipBkg;
  2703. continue;
  2704. }
  2705. else if (prop.type == 'staticArr') //if dynamic values are needed, a more elegant technique is needed to replace such values
  2706. {
  2707. prop.size = parseInt(state.style[prop.sizeProperty] || properties[prop.sizeProperty].defVal) || 0;
  2708. }
  2709. else if (prop.dependentProps != null)
  2710. {
  2711. var dependentProps = prop.dependentProps;
  2712. var dependentPropsVals = [];
  2713. var dependentPropsDefVal = [];
  2714. for (var i = 0; i < dependentProps.length; i++)
  2715. {
  2716. var propVal = state.style[dependentProps[i]];
  2717. dependentPropsDefVal.push(properties[dependentProps[i]].subDefVal);
  2718. dependentPropsVals.push(propVal != null? propVal.split(',') : []);
  2719. }
  2720. prop.dependentPropsDefVal = dependentPropsDefVal;
  2721. prop.dependentPropsVals = dependentPropsVals;
  2722. }
  2723. grid.appendChild(createPropertyRow(key, pValue, prop, isOdd, flipBkg));
  2724. isOdd = !isOdd;
  2725. }
  2726. for (var i = 0; i < secondLevel.length; i++)
  2727. {
  2728. var prop = secondLevel[i];
  2729. var insertElem = prop.parentRow;
  2730. for (var j = 0; j < prop.values.length; j++)
  2731. {
  2732. //mxUtils.clone failed because of the HTM element, so manual cloning is used
  2733. var iProp = {type: prop.type, parentRow: prop.parentRow, isDeletable: prop.isDeletable, index: j, defVal: prop.defVal, countProperty: prop.countProperty, size: prop.size};
  2734. var arrItem = createPropertyRow(prop.name, prop.values[j], iProp, j % 2 == 0, prop.flipBkg);
  2735. insertAfter(arrItem, insertElem);
  2736. insertElem = arrItem;
  2737. }
  2738. }
  2739. div.appendChild(grid);
  2740. onFold();
  2741. return div;
  2742. };
  2743. /**
  2744. * Creates the buttons for the predefined styles.
  2745. */
  2746. StyleFormatPanel.prototype.addStyles = function(div)
  2747. {
  2748. var graph = this.editorUi.editor.graph;
  2749. var picker = document.createElement('div');
  2750. picker.style.whiteSpace = 'nowrap';
  2751. picker.style.paddingLeft = '24px';
  2752. picker.style.paddingRight = '20px';
  2753. div.style.paddingLeft = '16px';
  2754. div.style.paddingBottom = '6px';
  2755. div.style.position = 'relative';
  2756. div.appendChild(picker);
  2757. var stylenames = ['plain-gray', 'plain-blue', 'plain-green', 'plain-turquoise',
  2758. 'plain-orange', 'plain-yellow', 'plain-red', 'plain-pink', 'plain-purple', 'gray',
  2759. 'blue', 'green', 'turquoise', 'orange', 'yellow', 'red', 'pink', 'purple'];
  2760. function updateScheme(colorsets)
  2761. {
  2762. function addButton(colorset)
  2763. {
  2764. var btn = mxUtils.button('', function(evt)
  2765. {
  2766. graph.getModel().beginUpdate();
  2767. try
  2768. {
  2769. var cells = graph.getSelectionCells();
  2770. for (var i = 0; i < cells.length; i++)
  2771. {
  2772. var style = graph.getModel().getStyle(cells[i]);
  2773. for (var j = 0; j < stylenames.length; j++)
  2774. {
  2775. style = mxUtils.removeStylename(style, stylenames[j]);
  2776. }
  2777. var defaults = (graph.getModel().isVertex(cells[i])) ? graph.defaultVertexStyle : graph.defaultEdgeStyle;
  2778. if (colorset != null)
  2779. {
  2780. style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR, colorset['gradient'] ||
  2781. mxUtils.getValue(defaults, mxConstants.STYLE_GRADIENTCOLOR, null));
  2782. if (colorset['fill'] == '')
  2783. {
  2784. style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR,null);
  2785. }
  2786. else
  2787. {
  2788. style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR, colorset['fill'] ||
  2789. mxUtils.getValue(defaults, mxConstants.STYLE_FILLCOLOR, null));
  2790. }
  2791. if (colorset['stroke'] == '')
  2792. {
  2793. style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, null);
  2794. }
  2795. else
  2796. {
  2797. style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR, colorset['stroke'] ||
  2798. mxUtils.getValue(defaults, mxConstants.STYLE_STROKECOLOR, null));
  2799. }
  2800. if (graph.getModel().isVertex(cells[i]))
  2801. {
  2802. style = mxUtils.setStyle(style, mxConstants.STYLE_FONTCOLOR, colorset['font'] ||
  2803. mxUtils.getValue(defaults, mxConstants.STYLE_FONTCOLOR, null));
  2804. }
  2805. }
  2806. else
  2807. {
  2808. style = mxUtils.setStyle(style, mxConstants.STYLE_FILLCOLOR,
  2809. mxUtils.getValue(defaults, mxConstants.STYLE_FILLCOLOR, '#ffffff'));
  2810. style = mxUtils.setStyle(style, mxConstants.STYLE_STROKECOLOR,
  2811. mxUtils.getValue(defaults, mxConstants.STYLE_STROKECOLOR, '#000000'));
  2812. style = mxUtils.setStyle(style, mxConstants.STYLE_GRADIENTCOLOR,
  2813. mxUtils.getValue(defaults, mxConstants.STYLE_GRADIENTCOLOR, null));
  2814. if (graph.getModel().isVertex(cells[i]))
  2815. {
  2816. style = mxUtils.setStyle(style, mxConstants.STYLE_FONTCOLOR,
  2817. mxUtils.getValue(defaults, mxConstants.STYLE_FONTCOLOR, null));
  2818. }
  2819. }
  2820. graph.getModel().setStyle(cells[i], style);
  2821. }
  2822. }
  2823. finally
  2824. {
  2825. graph.getModel().endUpdate();
  2826. }
  2827. })
  2828. btn.className = 'geStyleButton';
  2829. btn.style.width = '36px';
  2830. btn.style.height = '30px';
  2831. btn.style.margin = '0px 6px 6px 0px';
  2832. if (colorset != null)
  2833. {
  2834. if (colorset['gradient'] != null)
  2835. {
  2836. if (mxClient.IS_IE && (mxClient.IS_QUIRKS || document.documentMode < 10))
  2837. {
  2838. btn.style.filter = 'progid:DXImageTransform.Microsoft.Gradient('+
  2839. 'StartColorStr=\'' + colorset['fill'] +
  2840. '\', EndColorStr=\'' + colorset['gradient'] + '\', GradientType=0)';
  2841. }
  2842. else
  2843. {
  2844. btn.style.backgroundImage = 'linear-gradient(' + colorset['fill'] + ' 0px,' +
  2845. colorset['gradient'] + ' 100%)';
  2846. }
  2847. }
  2848. else if (colorset['fill'] == mxConstants.NONE)
  2849. {
  2850. btn.style.background = 'url(\'' + Dialog.prototype.noColorImage + '\')';
  2851. }
  2852. else if (colorset['fill'] == '')
  2853. {
  2854. btn.style.backgroundColor = mxUtils.getValue(graph.defaultVertexStyle,
  2855. mxConstants.STYLE_FILLCOLOR, (uiTheme == 'dark') ?'#000000' : '#ffffff');
  2856. }
  2857. else
  2858. {
  2859. btn.style.backgroundColor = colorset['fill'] || mxUtils.getValue(graph.defaultVertexStyle,
  2860. mxConstants.STYLE_FILLCOLOR, (uiTheme == 'dark') ?'#000000' : '#ffffff');
  2861. }
  2862. if (colorset['stroke'] == mxConstants.NONE)
  2863. {
  2864. btn.style.border = '1px solid transparent';
  2865. }
  2866. else if (colorset['stroke'] == '')
  2867. {
  2868. btn.style.border = '1px solid ' + mxUtils.getValue(graph.defaultVertexStyle,
  2869. mxConstants.STYLE_STROKECOLOR, (uiTheme != 'dark') ?'#000000' : '#ffffff');
  2870. }
  2871. else
  2872. {
  2873. btn.style.border = '1px solid ' + (colorset['stroke'] || mxUtils.getValue(graph.defaultVertexStyle,
  2874. mxConstants.STYLE_STROKECOLOR, (uiTheme != 'dark') ?'#000000' : '#ffffff'));
  2875. }
  2876. }
  2877. else
  2878. {
  2879. var bg = mxUtils.getValue(graph.defaultVertexStyle, mxConstants.STYLE_FILLCOLOR, '#ffffff');
  2880. var bd = mxUtils.getValue(graph.defaultVertexStyle, mxConstants.STYLE_STROKECOLOR, '#000000');
  2881. btn.style.backgroundColor = bg;
  2882. btn.style.border = '1px solid ' + bd;
  2883. }
  2884. picker.appendChild(btn);
  2885. };
  2886. picker.innerHTML = '';
  2887. for (var i = 0; i < colorsets.length; i++)
  2888. {
  2889. if (i > 0 && mxUtils.mod(i, 4) == 0)
  2890. {
  2891. mxUtils.br(picker);
  2892. }
  2893. addButton(colorsets[i]);
  2894. }
  2895. };
  2896. if (this.editorUi.currentScheme == null)
  2897. {
  2898. this.editorUi.currentScheme = 0;
  2899. }
  2900. var left = document.createElement('div');
  2901. left.style.cssText = 'position:absolute;left:10px;top:8px;bottom:8px;width:20px;margin:4px;opacity:0.5;' +
  2902. 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ4eHh3d3d1dXVxcXF2dnZ2dnZ2dnZxcXF2dnYmb3w1AAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADRJREFUCNdjwACMAmBKaiGYs2oJmLPKAZ3DabU8AMRTXpUKopislqFyVzCAuUZgikkBZjoAcMYLnp53P/UAAAAASUVORK5CYII=);';
  2903. mxEvent.addListener(left, 'click', mxUtils.bind(this, function()
  2904. {
  2905. this.editorUi.currentScheme = mxUtils.mod(this.editorUi.currentScheme - 1, this.defaultColorSchemes.length);
  2906. updateScheme(this.defaultColorSchemes[this.editorUi.currentScheme]);
  2907. }));
  2908. var right = document.createElement('div');
  2909. right.style.cssText = 'position:absolute;left:202px;top:8px;bottom:8px;width:20px;margin:4px;opacity:0.5;' +
  2910. 'background-repeat:no-repeat;background-position:center center;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnYBuwCcAAAACnRSTlMAfCTkhhvb7cQSPH2JPgAAADZJREFUCNdjQAOMAmBKaiGY8loF5rKswsZlrVo8AUiFrTICcbIWK8A5DF1gDoMymMPApIAwHwCS0Qx/U7qCBQAAAABJRU5ErkJggg==);';
  2911. if (this.defaultColorSchemes.length > 1)
  2912. {
  2913. div.appendChild(left);
  2914. div.appendChild(right);
  2915. }
  2916. mxEvent.addListener(right, 'click', mxUtils.bind(this, function()
  2917. {
  2918. this.editorUi.currentScheme = mxUtils.mod(this.editorUi.currentScheme + 1, this.defaultColorSchemes.length);
  2919. updateScheme(this.defaultColorSchemes[this.editorUi.currentScheme]);
  2920. }));
  2921. // Hover state
  2922. function addHoverState(elt)
  2923. {
  2924. mxEvent.addListener(elt, 'mouseenter', function()
  2925. {
  2926. elt.style.opacity = '1';
  2927. });
  2928. mxEvent.addListener(elt, 'mouseleave', function()
  2929. {
  2930. elt.style.opacity = '0.5';
  2931. });
  2932. };
  2933. addHoverState(left);
  2934. addHoverState(right);
  2935. updateScheme(this.defaultColorSchemes[this.editorUi.currentScheme]);
  2936. return div;
  2937. };
  2938. StyleFormatPanel.prototype.addEditOps = function(div)
  2939. {
  2940. var ss = this.format.getSelectionState();
  2941. var btn = null;
  2942. if (this.editorUi.editor.graph.getSelectionCount() == 1)
  2943. {
  2944. btn = mxUtils.button(mxResources.get('editStyle'), mxUtils.bind(this, function(evt)
  2945. {
  2946. this.editorUi.actions.get('editStyle').funct();
  2947. }));
  2948. btn.setAttribute('title', mxResources.get('editStyle') + ' (' + this.editorUi.actions.get('editStyle').shortcut + ')');
  2949. btn.style.width = '202px';
  2950. btn.style.marginBottom = '2px';
  2951. div.appendChild(btn);
  2952. }
  2953. var graph = this.editorUi.editor.graph;
  2954. var state = graph.view.getState(graph.getSelectionCell());
  2955. if (graph.getSelectionCount() == 1 && state != null && state.shape != null && state.shape.stencil != null)
  2956. {
  2957. var btn2 = mxUtils.button(mxResources.get('editShape'), mxUtils.bind(this, function(evt)
  2958. {
  2959. this.editorUi.actions.get('editShape').funct();
  2960. }));
  2961. btn2.setAttribute('title', mxResources.get('editShape'));
  2962. btn2.style.marginBottom = '2px';
  2963. if (btn == null)
  2964. {
  2965. btn2.style.width = '202px';
  2966. }
  2967. else
  2968. {
  2969. btn.style.width = '100px';
  2970. btn2.style.width = '100px';
  2971. btn2.style.marginLeft = '2px';
  2972. }
  2973. div.appendChild(btn2);
  2974. }
  2975. else if (ss.image)
  2976. {
  2977. var btn2 = mxUtils.button(mxResources.get('editImage'), mxUtils.bind(this, function(evt)
  2978. {
  2979. this.editorUi.actions.get('image').funct();
  2980. }));
  2981. btn2.setAttribute('title', mxResources.get('editImage'));
  2982. btn2.style.marginBottom = '2px';
  2983. if (btn == null)
  2984. {
  2985. btn2.style.width = '202px';
  2986. }
  2987. else
  2988. {
  2989. btn.style.width = '100px';
  2990. btn2.style.width = '100px';
  2991. btn2.style.marginLeft = '2px';
  2992. }
  2993. div.appendChild(btn2);
  2994. }
  2995. return div;
  2996. };
  2997. }
  2998. /**
  2999. * Changes the default stylename so that it matches the old named style
  3000. * if one was specified in the XML.
  3001. */
  3002. Graph.prototype.defaultThemeName = 'default-style2';
  3003. /**
  3004. * Contains the last XML that was pasted.
  3005. */
  3006. Graph.prototype.lastPasteXml = null;
  3007. /**
  3008. * Contains the number of times the last XML was pasted.
  3009. */
  3010. Graph.prototype.pasteCounter = 0;
  3011. /**
  3012. * Graph Overrides
  3013. */
  3014. Graph.prototype.defaultScrollbars = urlParams['sb'] != '0';
  3015. /**
  3016. * Specifies if the page should be visible for new files. Default is true.
  3017. */
  3018. Graph.prototype.defaultPageVisible = urlParams['pv'] != '0';
  3019. /**
  3020. * Specifies if the page should be visible for new files. Default is true.
  3021. */
  3022. Graph.prototype.shadowId = 'dropShadow';
  3023. /**
  3024. * Properties for the SVG shadow effect.
  3025. */
  3026. Graph.prototype.svgShadowColor = '#3D4574';
  3027. /**
  3028. * Properties for the SVG shadow effect.
  3029. */
  3030. Graph.prototype.svgShadowOpacity = '0.4';
  3031. /**
  3032. * Properties for the SVG shadow effect.
  3033. */
  3034. Graph.prototype.svgShadowBlur = '1.7';
  3035. /**
  3036. * Properties for the SVG shadow effect.
  3037. */
  3038. Graph.prototype.svgShadowSize = '3';
  3039. /**
  3040. * Enables move of bends/segments without selecting.
  3041. */
  3042. Graph.prototype.edgeMode = urlParams['edge'] != 'move';
  3043. /**
  3044. * Adds rack child layout style.
  3045. */
  3046. var graphInit = Graph.prototype.init;
  3047. Graph.prototype.init = function()
  3048. {
  3049. graphInit.apply(this, arguments);
  3050. //TODO initialize Freehand in the correct location!
  3051. if (window.mxFreehand)
  3052. {
  3053. this.freehand = new mxFreehand(this);
  3054. }
  3055. // Override insert location for current mouse point
  3056. var mouseEvent = null;
  3057. function setMouseEvent(evt)
  3058. {
  3059. mouseEvent = evt;
  3060. // Workaround for member not found in IE8-
  3061. try
  3062. {
  3063. if (mxClient.IS_QUIRKS || document.documentMode == 7 || document.documentMode == 8)
  3064. {
  3065. mouseEvent = document.createEventObject(evt);
  3066. mouseEvent.type = evt.type;
  3067. mouseEvent.canBubble = evt.canBubble;
  3068. mouseEvent.cancelable = evt.cancelable;
  3069. mouseEvent.view = evt.view;
  3070. mouseEvent.detail = evt.detail;
  3071. mouseEvent.screenX = evt.screenX;
  3072. mouseEvent.screenY = evt.screenY;
  3073. mouseEvent.clientX = evt.clientX;
  3074. mouseEvent.clientY = evt.clientY;
  3075. mouseEvent.ctrlKey = evt.ctrlKey;
  3076. mouseEvent.altKey = evt.altKey;
  3077. mouseEvent.shiftKey = evt.shiftKey;
  3078. mouseEvent.metaKey = evt.metaKey;
  3079. mouseEvent.button = evt.button;
  3080. mouseEvent.relatedTarget = evt.relatedTarget;
  3081. }
  3082. }
  3083. catch (e)
  3084. {
  3085. // ignores possible event cloning errors
  3086. }
  3087. };
  3088. mxEvent.addListener(this.container, 'mouseenter', setMouseEvent);
  3089. mxEvent.addListener(this.container, 'mousemove', setMouseEvent);
  3090. mxEvent.addListener(this.container, 'mouseleave', function(evt)
  3091. {
  3092. mouseEvent = null;
  3093. });
  3094. // Extends getInsertPoint to use the current mouse location
  3095. this.isMouseInsertPoint = function()
  3096. {
  3097. return mouseEvent != null;
  3098. };
  3099. var getInsertPoint = this.getInsertPoint;
  3100. this.getInsertPoint = function()
  3101. {
  3102. if (mouseEvent != null)
  3103. {
  3104. return this.getPointForEvent(mouseEvent);
  3105. }
  3106. return getInsertPoint.apply(this, arguments);
  3107. };
  3108. var layoutManagerGetLayout = this.layoutManager.getLayout;
  3109. this.layoutManager.getLayout = function(cell)
  3110. {
  3111. // Workaround for possible invalid style after change and before view validation
  3112. var style = this.graph.getCellStyle(cell);
  3113. // mxRackContainer may be undefined as it is dynamically loaded at render time
  3114. if (style != null)
  3115. {
  3116. if (style['childLayout'] == 'rack')
  3117. {
  3118. var rackLayout = new mxStackLayout(this.graph, false);
  3119. var unitSize = 20;
  3120. if (style['rackUnitSize'] != null)
  3121. {
  3122. rackLayout.gridSize = parseFloat(style['rackUnitSize']);
  3123. }
  3124. else
  3125. {
  3126. rackLayout.gridSize = (typeof mxRackContainer !== 'undefined') ? mxRackContainer.unitSize : unitSize;
  3127. }
  3128. rackLayout.fill = true;
  3129. rackLayout.marginLeft = style['marginLeft'] || 0;
  3130. rackLayout.marginRight = style['marginRight'] || 0;
  3131. rackLayout.marginTop = style['marginTop'] || 0;
  3132. rackLayout.marginBottom = style['marginBottom'] || 0;
  3133. rackLayout.allowGaps = style['allowGaps'] || 0;
  3134. rackLayout.resizeParent = false;
  3135. return rackLayout;
  3136. }
  3137. else if (typeof mxTableLayout !== 'undefined' && style['childLayout'] == 'tableLayout')
  3138. {
  3139. var tableLayout = new mxTableLayout(this.graph);
  3140. tableLayout.rows = style['tableRows'] || 2;
  3141. tableLayout.columns = style['tableColumns'] || 2;
  3142. tableLayout.colPercentages = style['colPercentages'];
  3143. tableLayout.rowPercentages = style['rowPercentages'];
  3144. tableLayout.equalColumns = mxUtils.getValue(style, 'equalColumns', tableLayout.colPercentages? '0' : '1') == '1';
  3145. tableLayout.equalRows = mxUtils.getValue(style, 'equalRows', tableLayout.rowPercentages? '0' : '1') == '1';
  3146. tableLayout.resizeParent = mxUtils.getValue(style, 'resizeParent', '1') == '1';
  3147. tableLayout.border = style['tableBorder'] || tableLayout.border;
  3148. tableLayout.marginLeft = style['marginLeft'] || 0;
  3149. tableLayout.marginRight = style['marginRight'] || 0;
  3150. tableLayout.marginTop = style['marginTop'] || 0;
  3151. tableLayout.marginBottom = style['marginBottom'] || 0;
  3152. tableLayout.autoAddCol = mxUtils.getValue(style, 'autoAddCol', '0') == '1';
  3153. tableLayout.autoAddRow = mxUtils.getValue(style, 'autoAddRow', tableLayout.autoAddCol? '0' : '1') == '1';
  3154. tableLayout.colWidths = style['colWidths'] || "100";
  3155. tableLayout.rowHeights = style['rowHeights'] || "50";
  3156. return tableLayout;
  3157. }
  3158. }
  3159. return layoutManagerGetLayout.apply(this, arguments);
  3160. }
  3161. };
  3162. /**
  3163. * Cached default stylesheet for image export in dark mode.
  3164. */
  3165. Graph.prototype.getDefaultStylesheet = function()
  3166. {
  3167. if (this.defaultStylesheet == null)
  3168. {
  3169. var node = this.themes['default-style2'];
  3170. var dec = new mxCodec(node.ownerDocument);
  3171. this.defaultStylesheet = dec.decode(node);
  3172. }
  3173. return this.defaultStylesheet;
  3174. };
  3175. /**
  3176. * Temporarily overrides stylesheet during image export in dark mode.
  3177. */
  3178. var graphGetSvg = Graph.prototype.getSvg;
  3179. Graph.prototype.getSvg = function()
  3180. {
  3181. var temp = null;
  3182. if (this.themes != null && this.defaultThemeName == 'darkTheme')
  3183. {
  3184. temp = this.stylesheet;
  3185. this.stylesheet = this.getDefaultStylesheet()
  3186. this.refresh();
  3187. }
  3188. var result = graphGetSvg.apply(this, arguments);
  3189. if (temp != null)
  3190. {
  3191. this.stylesheet = temp;
  3192. this.refresh();
  3193. }
  3194. return result;
  3195. };
  3196. /**
  3197. * Safari has problems with math typesetting inside foreignObjects.
  3198. */
  3199. var graphIsCssTransformsSupported = Graph.prototype.isCssTransformsSupported;
  3200. Graph.prototype.isCssTransformsSupported = function()
  3201. {
  3202. // FIXME: Safari only disabled due to mathjax rendering errors
  3203. return graphIsCssTransformsSupported.apply(this, arguments) && !mxClient.IS_SF;
  3204. };
  3205. /**
  3206. * Adds support for vars URL parameter.
  3207. */
  3208. var graphGetGlobalVariable = Graph.prototype.getGlobalVariable;
  3209. Graph.prototype.getGlobalVariable = function(name)
  3210. {
  3211. var val = graphGetGlobalVariable.apply(this, arguments);
  3212. if (val == null)
  3213. {
  3214. if (this.globalUrlVars == null && urlParams['vars'] != null)
  3215. {
  3216. try
  3217. {
  3218. this.globalUrlVars = JSON.parse(decodeURIComponent(urlParams['vars']));
  3219. }
  3220. catch (e)
  3221. {
  3222. if (window.console != null)
  3223. {
  3224. console.log('Error in vars URL parameter: ' + e);
  3225. }
  3226. }
  3227. }
  3228. if (this.globalUrlVars != null)
  3229. {
  3230. val = this.globalUrlVars[name];
  3231. }
  3232. }
  3233. return val;
  3234. };
  3235. /**
  3236. * Adds workaround for math rendering in Chrome.
  3237. *
  3238. * Workaround for https://bugs.webkit.org/show_bug.cgi?id=93358 in WebKit
  3239. *
  3240. * Adding an absolute position DIV before the SVG seems to mitigate the problem.
  3241. */
  3242. var graphViewValidateBackgroundPage = mxGraphView.prototype.validateBackgroundPage;
  3243. mxGraphView.prototype.validateBackgroundPage = function()
  3244. {
  3245. graphViewValidateBackgroundPage.apply(this, arguments);
  3246. if (mxClient.IS_GC && this.getDrawPane() != null)
  3247. {
  3248. var g = this.getDrawPane().parentNode;
  3249. if (this.graph.mathEnabled && !mxClient.NO_FO &&
  3250. (this.webKitForceRepaintNode == null ||
  3251. this.webKitForceRepaintNode.parentNode == null) &&
  3252. this.graph.container.firstChild.nodeName == 'svg')
  3253. {
  3254. this.webKitForceRepaintNode = document.createElement('div');
  3255. this.webKitForceRepaintNode.style.cssText = 'position:absolute;';
  3256. g.ownerSVGElement.parentNode.insertBefore(this.webKitForceRepaintNode, g.ownerSVGElement);
  3257. }
  3258. else if (this.webKitForceRepaintNode != null && (!this.graph.mathEnabled ||
  3259. (this.graph.container.firstChild.nodeName != 'svg' &&
  3260. this.graph.container.firstChild != this.webKitForceRepaintNode)))
  3261. {
  3262. if (this.webKitForceRepaintNode.parentNode != null)
  3263. {
  3264. this.webKitForceRepaintNode.parentNode.removeChild(this.webKitForceRepaintNode);
  3265. }
  3266. this.webKitForceRepaintNode = null;
  3267. }
  3268. }
  3269. };
  3270. /**
  3271. * Sets default style (used in editor.get/setGraphXml below)
  3272. */
  3273. var graphLoadStylesheet = Graph.prototype.loadStylesheet;
  3274. Graph.prototype.loadStylesheet = function()
  3275. {
  3276. graphLoadStylesheet.apply(this, arguments);
  3277. this.currentStyle = 'default-style2';
  3278. };
  3279. /**
  3280. * Adds support for data:action/json,{"actions":[actions]} where actions is
  3281. * a comma-separated list of JSON objects with the following possible keys:
  3282. *
  3283. * "open": string - opens a standard or custom link (including page links)
  3284. * "toggle"/"show"/"hide"/"highlight": cellset - toggles, shows, hides or
  3285. * highlights the given cells
  3286. * "select": cellset - selects the given cells if the graph is editable
  3287. * "scroll": cellset - scrolls to the first cell in the given celllset
  3288. * If no scroll action is specified, then the first cell of the select
  3289. * or highlight action is scrolled to visible (select has precedence).
  3290. * A cellset is an array of cell IDs or tags or both, eg.
  3291. * {"cells": ["id1", "id2"], "tags": ["tag1", "tag2"]}
  3292. * To specify all cells, use "cells": ["*"], to specify all cells with
  3293. * a tag, use "tags": [] (empty array).
  3294. *
  3295. * An example action is:
  3296. *
  3297. * data:action/json,{"actions":[{"toggle": {"cells": ["3", "4"]}}]}
  3298. *
  3299. * This toggles the visible state of the cells with ID 3 and 4.
  3300. */
  3301. Graph.prototype.handleCustomLink = function(href)
  3302. {
  3303. if (href.substring(0, 17) == 'data:action/json,')
  3304. {
  3305. // Some actions are stateless and must be handled before the transaction
  3306. var link = JSON.parse(href.substring(17));
  3307. if (link.actions != null)
  3308. {
  3309. // Executes open actions before starting transaction
  3310. for (var i = 0; i < link.actions.length; i++)
  3311. {
  3312. var action = link.actions[i];
  3313. if (action.open != null)
  3314. {
  3315. if (this.isCustomLink(action.open))
  3316. {
  3317. if (!this.customLinkClicked(action.open))
  3318. {
  3319. return;
  3320. }
  3321. }
  3322. else
  3323. {
  3324. this.openLink(action.open);
  3325. }
  3326. }
  3327. }
  3328. // Executes all actions that change cell states
  3329. this.model.beginUpdate();
  3330. try
  3331. {
  3332. for (var i = 0; i < link.actions.length; i++)
  3333. {
  3334. var action = link.actions[i];
  3335. if (action.toggle != null)
  3336. {
  3337. this.toggleCells(this.getCellsForAction(action.toggle, true));
  3338. }
  3339. if (action.show != null)
  3340. {
  3341. this.setCellsVisible(this.getCellsForAction(action.show, true), true);
  3342. }
  3343. if (action.hide != null)
  3344. {
  3345. this.setCellsVisible(this.getCellsForAction(action.hide, true), false);
  3346. }
  3347. }
  3348. }
  3349. finally
  3350. {
  3351. this.model.endUpdate();
  3352. }
  3353. // Executes stateless actions on cells
  3354. for (var i = 0; i < link.actions.length; i++)
  3355. {
  3356. var action = link.actions[i];
  3357. var cells = [];
  3358. if (action.select != null && this.isEnabled())
  3359. {
  3360. cells = this.getCellsForAction(action.select);
  3361. this.setSelectionCells(cells);
  3362. }
  3363. if (action.highlight != null)
  3364. {
  3365. cells = this.getCellsForAction(action.highlight);
  3366. this.highlightCells(cells, action.highlight.color,
  3367. action.highlight.duration, action.highlight.opacity);
  3368. }
  3369. if (action.scroll != null)
  3370. {
  3371. cells = this.getCellsForAction(action.scroll);
  3372. }
  3373. if (cells.length > 0)
  3374. {
  3375. this.scrollCellToVisible(cells[0]);
  3376. }
  3377. }
  3378. }
  3379. }
  3380. };
  3381. /**
  3382. * Handles each action in the action array of a custom link. This code
  3383. * handles toggle actions for cell IDs.
  3384. */
  3385. Graph.prototype.getCellsForAction = function(action, includeLayers)
  3386. {
  3387. return this.getCellsById(action.cells).concat(
  3388. this.getCellsForTags(action.tags, null, null, includeLayers));
  3389. };
  3390. /**
  3391. * Returns the cells in the model (or given array) that have all of the
  3392. * given tags in their tags property.
  3393. */
  3394. Graph.prototype.getCellsById = function(ids)
  3395. {
  3396. var result = [];
  3397. if (ids != null)
  3398. {
  3399. for (var i = 0; i < ids.length; i++)
  3400. {
  3401. if (ids[i] == '*')
  3402. {
  3403. var parent = this.getDefaultParent();
  3404. result = result.concat(this.model.filterDescendants(function(cell)
  3405. {
  3406. return cell != parent;
  3407. }, parent));
  3408. }
  3409. else
  3410. {
  3411. var cell = this.model.getCell(ids[i]);
  3412. if (cell != null)
  3413. {
  3414. result.push(cell);
  3415. }
  3416. }
  3417. }
  3418. }
  3419. return result;
  3420. };
  3421. /**
  3422. * Returns the cells in the model (or given array) that have all of the
  3423. * given tags in their tags property.
  3424. */
  3425. Graph.prototype.getCellsForTags = function(tagList, cells, propertyName, includeLayers)
  3426. {
  3427. var result = [];
  3428. if (tagList != null)
  3429. {
  3430. cells = (cells != null) ? cells : this.model.getDescendants(this.model.getRoot());
  3431. propertyName = (propertyName != null) ? propertyName : 'tags';
  3432. var tagCount = 0;
  3433. var lookup = {};
  3434. for (var i = 0; i < tagList.length; i++)
  3435. {
  3436. if (tagList[i].length > 0)
  3437. {
  3438. lookup[tagList[i].toLowerCase()] = true;
  3439. tagCount++;
  3440. }
  3441. }
  3442. for (var i = 0; i < cells.length; i++)
  3443. {
  3444. if ((includeLayers && this.model.getParent(cells[i]) == this.model.root) ||
  3445. this.model.isVertex(cells[i]) || this.model.isEdge(cells[i]))
  3446. {
  3447. var tags = (cells[i].value != null && typeof(cells[i].value) == 'object') ?
  3448. mxUtils.trim(cells[i].value.getAttribute(propertyName) || '') : '';
  3449. var match = false;
  3450. if (tags.length > 0)
  3451. {
  3452. var tmp = tags.toLowerCase().split(' ');
  3453. if (tmp.length >= tagList.length)
  3454. {
  3455. var matchCount = 0;
  3456. for (var j = 0; j < tmp.length && (matchCount < tagCount); j++)
  3457. {
  3458. if (lookup[tmp[j]] != null)
  3459. {
  3460. matchCount++;
  3461. }
  3462. }
  3463. match = matchCount == tagCount;
  3464. }
  3465. }
  3466. else
  3467. {
  3468. match = tagList.length == 0;
  3469. }
  3470. if (match)
  3471. {
  3472. result.push(cells[i]);
  3473. }
  3474. }
  3475. }
  3476. }
  3477. return result;
  3478. };
  3479. /**
  3480. * Shows or hides the given cells.
  3481. */
  3482. Graph.prototype.toggleCells = function(cells)
  3483. {
  3484. this.model.beginUpdate();
  3485. try
  3486. {
  3487. for (var i = 0; i < cells.length; i++)
  3488. {
  3489. this.model.setVisible(cells[i], !this.model.isVisible(cells[i]))
  3490. }
  3491. }
  3492. finally
  3493. {
  3494. this.model.endUpdate();
  3495. }
  3496. };
  3497. /**
  3498. * Shows or hides the given cells.
  3499. */
  3500. Graph.prototype.setCellsVisible = function(cells, visible)
  3501. {
  3502. this.model.beginUpdate();
  3503. try
  3504. {
  3505. for (var i = 0; i < cells.length; i++)
  3506. {
  3507. this.model.setVisible(cells[i], visible);
  3508. }
  3509. }
  3510. finally
  3511. {
  3512. this.model.endUpdate();
  3513. }
  3514. };
  3515. /**
  3516. * Highlights the given cell.
  3517. */
  3518. Graph.prototype.highlightCells = function(cells, color, duration, opacity)
  3519. {
  3520. for (var i = 0; i < cells.length; i++)
  3521. {
  3522. this.highlightCell(cells[i], color, duration, opacity);
  3523. }
  3524. };
  3525. /**
  3526. * Highlights the given cell.
  3527. */
  3528. Graph.prototype.highlightCell = function(cell, color, duration, opacity)
  3529. {
  3530. color = (color != null) ? color : mxConstants.DEFAULT_VALID_COLOR;
  3531. duration = (duration != null) ? duration : 1000;
  3532. var state = this.view.getState(cell);
  3533. if (state != null)
  3534. {
  3535. var sw = Math.max(5, mxUtils.getValue(state.style, mxConstants.STYLE_STROKEWIDTH, 1) + 4);
  3536. var hl = new mxCellHighlight(this, color, sw, false);
  3537. if (opacity != null)
  3538. {
  3539. hl.opacity = opacity;
  3540. }
  3541. hl.highlight(state);
  3542. // Fades out the highlight after a duration
  3543. window.setTimeout(function()
  3544. {
  3545. if (hl.shape != null)
  3546. {
  3547. mxUtils.setPrefixedStyle(hl.shape.node.style, 'transition', 'all 1200ms ease-in-out');
  3548. hl.shape.node.style.opacity = 0;
  3549. }
  3550. // Destroys the highlight after the fade
  3551. window.setTimeout(function()
  3552. {
  3553. hl.destroy();
  3554. }, 1200);
  3555. }, duration);
  3556. }
  3557. };
  3558. /**
  3559. * Adds a shadow filter to the given svg root.
  3560. */
  3561. Graph.prototype.addSvgShadow = function(svgRoot, group, createOnly)
  3562. {
  3563. createOnly = (createOnly != null) ? createOnly : false;
  3564. var svgDoc = svgRoot.ownerDocument;
  3565. var filter = (svgDoc.createElementNS != null) ?
  3566. svgDoc.createElementNS(mxConstants.NS_SVG, 'filter') : svgDoc.createElement('filter');
  3567. filter.setAttribute('id', this.shadowId);
  3568. var blur = (svgDoc.createElementNS != null) ?
  3569. svgDoc.createElementNS(mxConstants.NS_SVG, 'feGaussianBlur') : svgDoc.createElement('feGaussianBlur');
  3570. blur.setAttribute('in', 'SourceAlpha');
  3571. blur.setAttribute('stdDeviation', this.svgShadowBlur);
  3572. blur.setAttribute('result', 'blur');
  3573. filter.appendChild(blur);
  3574. var offset = (svgDoc.createElementNS != null) ?
  3575. svgDoc.createElementNS(mxConstants.NS_SVG, 'feOffset') : svgDoc.createElement('feOffset');
  3576. offset.setAttribute('in', 'blur');
  3577. offset.setAttribute('dx', this.svgShadowSize);
  3578. offset.setAttribute('dy', this.svgShadowSize);
  3579. offset.setAttribute('result', 'offsetBlur');
  3580. filter.appendChild(offset);
  3581. var flood = (svgDoc.createElementNS != null) ?
  3582. svgDoc.createElementNS(mxConstants.NS_SVG, 'feFlood') : svgDoc.createElement('feFlood');
  3583. flood.setAttribute('flood-color', this.svgShadowColor);
  3584. flood.setAttribute('flood-opacity', this.svgShadowOpacity);
  3585. flood.setAttribute('result', 'offsetColor');
  3586. filter.appendChild(flood);
  3587. var composite = (svgDoc.createElementNS != null) ?
  3588. svgDoc.createElementNS(mxConstants.NS_SVG, 'feComposite') : svgDoc.createElement('feComposite');
  3589. composite.setAttribute('in', 'offsetColor');
  3590. composite.setAttribute('in2', 'offsetBlur');
  3591. composite.setAttribute('operator', 'in');
  3592. composite.setAttribute('result', 'offsetBlur');
  3593. filter.appendChild(composite);
  3594. var feBlend = (svgDoc.createElementNS != null) ?
  3595. svgDoc.createElementNS(mxConstants.NS_SVG, 'feBlend') : svgDoc.createElement('feBlend');
  3596. feBlend.setAttribute('in', 'SourceGraphic');
  3597. feBlend.setAttribute('in2', 'offsetBlur');
  3598. filter.appendChild(feBlend);
  3599. // Creates defs element if not available
  3600. var defs = svgRoot.getElementsByTagName('defs');
  3601. var defsElt = null;
  3602. if (defs.length == 0)
  3603. {
  3604. defsElt = (svgDoc.createElementNS != null) ?
  3605. svgDoc.createElementNS(mxConstants.NS_SVG, 'defs') : svgDoc.createElement('defs');
  3606. if (svgRoot.firstChild != null)
  3607. {
  3608. svgRoot.insertBefore(defsElt, svgRoot.firstChild);
  3609. }
  3610. else
  3611. {
  3612. svgRoot.appendChild(defsElt);
  3613. }
  3614. }
  3615. else
  3616. {
  3617. defsElt = defs[0];
  3618. }
  3619. defsElt.appendChild(filter);
  3620. if (!createOnly)
  3621. {
  3622. group = (group != null) ? group : svgRoot.getElementsByTagName('g')[0];
  3623. if (group != null)
  3624. {
  3625. group.setAttribute('filter', 'url(#' + this.shadowId + ')');
  3626. if (!isNaN(parseInt(svgRoot.getAttribute('width'))))
  3627. {
  3628. svgRoot.setAttribute('width', parseInt(svgRoot.getAttribute('width')) + 6);
  3629. svgRoot.setAttribute('height', parseInt(svgRoot.getAttribute('height')) + 6);
  3630. // Updates viewbox if one exists
  3631. var vb = svgRoot.getAttribute('viewBox');
  3632. if (vb != null && vb.length > 0)
  3633. {
  3634. var tokens = vb.split(' ');
  3635. if (tokens.length > 3)
  3636. {
  3637. w = parseFloat(tokens[2]) + 6;
  3638. h = parseFloat(tokens[3]) + 6;
  3639. svgRoot.setAttribute('viewBox', tokens[0] + ' ' + tokens[1] + ' ' + w + ' ' + h);
  3640. }
  3641. }
  3642. }
  3643. }
  3644. }
  3645. return filter;
  3646. };
  3647. /**
  3648. * Loads the stylesheet for this graph.
  3649. */
  3650. Graph.prototype.setShadowVisible = function(value, fireEvent)
  3651. {
  3652. if (mxClient.IS_SVG)
  3653. {
  3654. fireEvent = (fireEvent != null) ? fireEvent : true;
  3655. this.shadowVisible = value;
  3656. if (this.shadowVisible)
  3657. {
  3658. this.view.getDrawPane().setAttribute('filter', 'url(#' + this.shadowId + ')');
  3659. }
  3660. else
  3661. {
  3662. this.view.getDrawPane().removeAttribute('filter');
  3663. }
  3664. if (fireEvent)
  3665. {
  3666. this.fireEvent(new mxEventObject('shadowVisibleChanged'));
  3667. }
  3668. }
  3669. };
  3670. /**
  3671. * Selects first unlocked layer if one exists
  3672. */
  3673. Graph.prototype.selectUnlockedLayer = function()
  3674. {
  3675. if (this.defaultParent == null)
  3676. {
  3677. var childCount = this.model.getChildCount(this.model.root);
  3678. var cell = null;
  3679. var index = 0;
  3680. do
  3681. {
  3682. cell = this.model.getChildAt(this.model.root, index);
  3683. } while (index++ < childCount && mxUtils.getValue(this.getCellStyle(cell), 'locked', '0') == '1')
  3684. if (cell != null)
  3685. {
  3686. this.setDefaultParent(cell);
  3687. }
  3688. }
  3689. };
  3690. /**
  3691. * Specifies special libraries that are loaded via dynamic JS. Add cases
  3692. * where the filename cannot be worked out from the package name. The
  3693. * standard scheme for this mapping is stencils/packagename.xml. If there
  3694. * are multiple XML files, any JS files or any anomalies in the filename or
  3695. * directory that contains the file, then an entry must be added here and
  3696. * in EmbedServlet2 for the loading of the shapes to work.
  3697. */
  3698. // Required to avoid 404 for mockup.xml since naming of mxgraph.mockup.anchor does not contain
  3699. // buttons even though it is defined in the mxMockupButtons.js file. This could only be fixed
  3700. // with aliases for existing shapes or aliases for basenames, but this is essentially the same.
  3701. mxStencilRegistry.libraries['mockup'] = [SHAPES_PATH + '/mockup/mxMockupButtons.js'];
  3702. mxStencilRegistry.libraries['arrows2'] = [SHAPES_PATH + '/mxArrows.js'];
  3703. mxStencilRegistry.libraries['atlassian'] = [STENCIL_PATH + '/atlassian.xml', SHAPES_PATH + '/mxAtlassian.js'];
  3704. mxStencilRegistry.libraries['bpmn'] = [SHAPES_PATH + '/bpmn/mxBpmnShape2.js', STENCIL_PATH + '/bpmn.xml'];
  3705. mxStencilRegistry.libraries['dfd'] = [SHAPES_PATH + '/mxDFD.js'];
  3706. mxStencilRegistry.libraries['er'] = [SHAPES_PATH + '/er/mxER.js'];
  3707. mxStencilRegistry.libraries['flowchart'] = [SHAPES_PATH + '/mxFlowchart.js', STENCIL_PATH + '/flowchart.xml'];
  3708. mxStencilRegistry.libraries['ios'] = [SHAPES_PATH + '/mockup/mxMockupiOS.js'];
  3709. mxStencilRegistry.libraries['rackGeneral'] = [SHAPES_PATH + '/rack/mxRack.js', STENCIL_PATH + '/rack/general.xml'];
  3710. mxStencilRegistry.libraries['rackF5'] = [STENCIL_PATH + '/rack/f5.xml'];
  3711. mxStencilRegistry.libraries['lean_mapping'] = [SHAPES_PATH + '/mxLeanMap.js', STENCIL_PATH + '/lean_mapping.xml'];
  3712. mxStencilRegistry.libraries['basic'] = [SHAPES_PATH + '/mxBasic.js', STENCIL_PATH + '/basic.xml'];
  3713. mxStencilRegistry.libraries['ios7icons'] = [STENCIL_PATH + '/ios7/icons.xml'];
  3714. mxStencilRegistry.libraries['ios7ui'] = [SHAPES_PATH + '/ios7/mxIOS7Ui.js', STENCIL_PATH + '/ios7/misc.xml'];
  3715. mxStencilRegistry.libraries['android'] = [SHAPES_PATH + '/mxAndroid.js', STENCIL_PATH + '/android/android.xml'];
  3716. mxStencilRegistry.libraries['electrical/miscellaneous'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/miscellaneous.xml'];
  3717. mxStencilRegistry.libraries['electrical/transmission'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/transmission.xml'];
  3718. mxStencilRegistry.libraries['electrical/logic_gates'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/logic_gates.xml'];
  3719. mxStencilRegistry.libraries['electrical/abstract'] = [SHAPES_PATH + '/mxElectrical.js', STENCIL_PATH + '/electrical/abstract.xml'];
  3720. mxStencilRegistry.libraries['infographic'] = [SHAPES_PATH + '/mxInfographic.js'];
  3721. mxStencilRegistry.libraries['mockup/buttons'] = [SHAPES_PATH + '/mockup/mxMockupButtons.js'];
  3722. mxStencilRegistry.libraries['mockup/containers'] = [SHAPES_PATH + '/mockup/mxMockupContainers.js'];
  3723. mxStencilRegistry.libraries['mockup/forms'] = [SHAPES_PATH + '/mockup/mxMockupForms.js'];
  3724. mxStencilRegistry.libraries['mockup/graphics'] = [SHAPES_PATH + '/mockup/mxMockupGraphics.js', STENCIL_PATH + '/mockup/misc.xml'];
  3725. mxStencilRegistry.libraries['mockup/markup'] = [SHAPES_PATH + '/mockup/mxMockupMarkup.js'];
  3726. mxStencilRegistry.libraries['mockup/misc'] = [SHAPES_PATH + '/mockup/mxMockupMisc.js', STENCIL_PATH + '/mockup/misc.xml'];
  3727. mxStencilRegistry.libraries['mockup/navigation'] = [SHAPES_PATH + '/mockup/mxMockupNavigation.js', STENCIL_PATH + '/mockup/misc.xml'];
  3728. mxStencilRegistry.libraries['mockup/text'] = [SHAPES_PATH + '/mockup/mxMockupText.js'];
  3729. mxStencilRegistry.libraries['floorplan'] = [SHAPES_PATH + '/mxFloorplan.js', STENCIL_PATH + '/floorplan.xml'];
  3730. mxStencilRegistry.libraries['bootstrap'] = [SHAPES_PATH + '/mxBootstrap.js', STENCIL_PATH + '/bootstrap.xml'];
  3731. mxStencilRegistry.libraries['gmdl'] = [SHAPES_PATH + '/mxGmdl.js', STENCIL_PATH + '/gmdl.xml'];
  3732. mxStencilRegistry.libraries['gcp2'] = [SHAPES_PATH + '/mxGCP2.js', STENCIL_PATH + '/gcp2.xml'];
  3733. mxStencilRegistry.libraries['cabinets'] = [SHAPES_PATH + '/mxCabinets.js', STENCIL_PATH + '/cabinets.xml'];
  3734. mxStencilRegistry.libraries['archimate'] = [SHAPES_PATH + '/mxArchiMate.js'];
  3735. mxStencilRegistry.libraries['archimate3'] = [SHAPES_PATH + '/mxArchiMate3.js'];
  3736. mxStencilRegistry.libraries['sysml'] = [SHAPES_PATH + '/mxSysML.js'];
  3737. mxStencilRegistry.libraries['eip'] = [SHAPES_PATH + '/mxEip.js', STENCIL_PATH + '/eip.xml'];
  3738. mxStencilRegistry.libraries['networks'] = [SHAPES_PATH + '/mxNetworks.js', STENCIL_PATH + '/networks.xml'];
  3739. mxStencilRegistry.libraries['aws3d'] = [SHAPES_PATH + '/mxAWS3D.js', STENCIL_PATH + '/aws3d.xml'];
  3740. mxStencilRegistry.libraries['aws4'] = [SHAPES_PATH + '/mxAWS4.js', STENCIL_PATH + '/aws4.xml'];
  3741. mxStencilRegistry.libraries['aws4b'] = [SHAPES_PATH + '/mxAWS4.js', STENCIL_PATH + '/aws4.xml'];
  3742. mxStencilRegistry.libraries['veeam'] = [STENCIL_PATH + '/veeam/2d.xml', STENCIL_PATH + '/veeam/3d.xml', STENCIL_PATH + '/veeam/veeam.xml'];
  3743. mxStencilRegistry.libraries['pid2inst'] = [SHAPES_PATH + '/pid2/mxPidInstruments.js'];
  3744. mxStencilRegistry.libraries['pid2misc'] = [SHAPES_PATH + '/pid2/mxPidMisc.js', STENCIL_PATH + '/pid/misc.xml'];
  3745. mxStencilRegistry.libraries['pid2valves'] = [SHAPES_PATH + '/pid2/mxPidValves.js'];
  3746. mxStencilRegistry.libraries['pidFlowSensors'] = [STENCIL_PATH + '/pid/flow_sensors.xml'];
  3747. // Triggers dynamic loading for markers
  3748. mxMarker.getPackageForType = function(type)
  3749. {
  3750. var name = null;
  3751. if (type != null && type.length > 0)
  3752. {
  3753. if (type.substring(0, 2) == 'ER')
  3754. {
  3755. name = 'mxgraph.er';
  3756. }
  3757. else if (type.substring(0, 5) == 'sysML')
  3758. {
  3759. name = 'mxgraph.sysml';
  3760. }
  3761. }
  3762. return name;
  3763. };
  3764. var mxMarkerCreateMarker = mxMarker.createMarker;
  3765. mxMarker.createMarker = function(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
  3766. {
  3767. if (type != null)
  3768. {
  3769. var f = mxMarker.markers[type];
  3770. if (f == null)
  3771. {
  3772. var name = this.getPackageForType(type);
  3773. if (name != null)
  3774. {
  3775. mxStencilRegistry.getStencil(name);
  3776. }
  3777. }
  3778. }
  3779. return mxMarkerCreateMarker.apply(this, arguments);
  3780. };
  3781. /**
  3782. * Constructs a new print dialog.
  3783. */
  3784. PrintDialog.prototype.create = function(editorUi, titleText)
  3785. {
  3786. var graph = editorUi.editor.graph;
  3787. var div = document.createElement('div');
  3788. var title = document.createElement('h3');
  3789. title.style.width = '100%';
  3790. title.style.textAlign = 'center';
  3791. title.style.marginTop = '0px';
  3792. mxUtils.write(title, titleText || mxResources.get('print'));
  3793. div.appendChild(title);
  3794. var pageCount = 1;
  3795. var currentPage = 1;
  3796. // Pages
  3797. var pagesSection = document.createElement('div');
  3798. pagesSection.style.cssText = 'border-bottom:1px solid lightGray;padding-bottom:12px;margin-bottom:12px;';
  3799. var allPagesRadio = document.createElement('input');
  3800. allPagesRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  3801. allPagesRadio.setAttribute('value', 'all');
  3802. allPagesRadio.setAttribute('type', 'radio');
  3803. allPagesRadio.setAttribute('name', 'pages-printdialog');
  3804. pagesSection.appendChild(allPagesRadio);
  3805. var span = document.createElement('span');
  3806. mxUtils.write(span, mxResources.get('printAllPages'));
  3807. pagesSection.appendChild(span);
  3808. mxUtils.br(pagesSection);
  3809. // Pages ... to ...
  3810. var pagesRadio = allPagesRadio.cloneNode(true);
  3811. allPagesRadio.setAttribute('checked', 'checked');
  3812. pagesRadio.setAttribute('value', 'range');
  3813. pagesSection.appendChild(pagesRadio);
  3814. var span = document.createElement('span');
  3815. mxUtils.write(span, mxResources.get('pages') + ':');
  3816. pagesSection.appendChild(span);
  3817. var pagesFromInput = document.createElement('input');
  3818. pagesFromInput.style.cssText = 'margin:0 8px 0 8px;'
  3819. pagesFromInput.setAttribute('value', '1');
  3820. pagesFromInput.setAttribute('type', 'number');
  3821. pagesFromInput.setAttribute('min', '1');
  3822. pagesFromInput.style.width = '50px';
  3823. pagesSection.appendChild(pagesFromInput);
  3824. var span = document.createElement('span');
  3825. mxUtils.write(span, mxResources.get('to'));
  3826. pagesSection.appendChild(span);
  3827. var pagesToInput = pagesFromInput.cloneNode(true);
  3828. pagesSection.appendChild(pagesToInput);
  3829. mxEvent.addListener(pagesFromInput, 'focus', function()
  3830. {
  3831. pagesRadio.checked = true;
  3832. });
  3833. mxEvent.addListener(pagesToInput, 'focus', function()
  3834. {
  3835. pagesRadio.checked = true;
  3836. });
  3837. function validatePageRange()
  3838. {
  3839. pagesToInput.value = Math.max(1, Math.min(pageCount, Math.max(parseInt(pagesToInput.value), parseInt(pagesFromInput.value))));
  3840. pagesFromInput.value = Math.max(1, Math.min(pageCount, Math.min(parseInt(pagesToInput.value), parseInt(pagesFromInput.value))));
  3841. };
  3842. mxEvent.addListener(pagesFromInput, 'change', validatePageRange);
  3843. mxEvent.addListener(pagesToInput, 'change', validatePageRange);
  3844. if (editorUi.pages != null)
  3845. {
  3846. pageCount = editorUi.pages.length;
  3847. if (editorUi.currentPage != null)
  3848. {
  3849. for (var i = 0; i < editorUi.pages.length; i++)
  3850. {
  3851. if (editorUi.currentPage == editorUi.pages[i])
  3852. {
  3853. currentPage = i + 1;
  3854. pagesFromInput.value = currentPage;
  3855. pagesToInput.value = currentPage;
  3856. break;
  3857. }
  3858. }
  3859. }
  3860. }
  3861. pagesFromInput.setAttribute('max', pageCount);
  3862. pagesToInput.setAttribute('max', pageCount);
  3863. if (pageCount > 1)
  3864. {
  3865. div.appendChild(pagesSection);
  3866. }
  3867. // Adjust to ...
  3868. var adjustSection = document.createElement('div');
  3869. adjustSection.style.marginBottom = '10px';
  3870. var adjustRadio = document.createElement('input');
  3871. adjustRadio.style.marginRight = '8px';
  3872. adjustRadio.setAttribute('value', 'adjust');
  3873. adjustRadio.setAttribute('type', 'radio');
  3874. adjustRadio.setAttribute('name', 'printZoom');
  3875. adjustSection.appendChild(adjustRadio);
  3876. var span = document.createElement('span');
  3877. mxUtils.write(span, mxResources.get('adjustTo'));
  3878. adjustSection.appendChild(span);
  3879. var zoomInput = document.createElement('input');
  3880. zoomInput.style.cssText = 'margin:0 8px 0 8px;';
  3881. zoomInput.setAttribute('value', '100 %');
  3882. zoomInput.style.width = '50px';
  3883. adjustSection.appendChild(zoomInput);
  3884. mxEvent.addListener(zoomInput, 'focus', function()
  3885. {
  3886. adjustRadio.checked = true;
  3887. });
  3888. div.appendChild(adjustSection);
  3889. // Fit to ...
  3890. var fitSection = pagesSection.cloneNode(false);
  3891. var fitRadio = adjustRadio.cloneNode(true);
  3892. fitRadio.setAttribute('value', 'fit');
  3893. adjustRadio.setAttribute('checked', 'checked');
  3894. var spanFitRadio = document.createElement('div');
  3895. spanFitRadio.style.cssText = 'display:inline-block;height:100%;vertical-align:top;padding-top:2px;';
  3896. spanFitRadio.appendChild(fitRadio);
  3897. fitSection.appendChild(spanFitRadio);
  3898. var table = document.createElement('table');
  3899. table.style.display = 'inline-block';
  3900. var tbody = document.createElement('tbody');
  3901. var row1 = document.createElement('tr');
  3902. var row2 = row1.cloneNode(true);
  3903. var td1 = document.createElement('td');
  3904. var td2 = td1.cloneNode(true);
  3905. var td3 = td1.cloneNode(true);
  3906. var td4 = td1.cloneNode(true);
  3907. var td5 = td1.cloneNode(true);
  3908. var td6 = td1.cloneNode(true);
  3909. td1.style.textAlign = 'right';
  3910. td4.style.textAlign = 'right';
  3911. mxUtils.write(td1, mxResources.get('fitTo'));
  3912. var sheetsAcrossInput = document.createElement('input');
  3913. sheetsAcrossInput.style.cssText = 'margin:0 8px 0 8px;';
  3914. sheetsAcrossInput.setAttribute('value', '1');
  3915. sheetsAcrossInput.setAttribute('min', '1');
  3916. sheetsAcrossInput.setAttribute('type', 'number');
  3917. sheetsAcrossInput.style.width = '40px';
  3918. td2.appendChild(sheetsAcrossInput);
  3919. var span = document.createElement('span');
  3920. mxUtils.write(span, mxResources.get('fitToSheetsAcross'));
  3921. td3.appendChild(span);
  3922. mxUtils.write(td4, mxResources.get('fitToBy'));
  3923. var sheetsDownInput = sheetsAcrossInput.cloneNode(true);
  3924. td5.appendChild(sheetsDownInput);
  3925. mxEvent.addListener(sheetsAcrossInput, 'focus', function()
  3926. {
  3927. fitRadio.checked = true;
  3928. });
  3929. mxEvent.addListener(sheetsDownInput, 'focus', function()
  3930. {
  3931. fitRadio.checked = true;
  3932. });
  3933. var span = document.createElement('span');
  3934. mxUtils.write(span, mxResources.get('fitToSheetsDown'));
  3935. td6.appendChild(span);
  3936. row1.appendChild(td1);
  3937. row1.appendChild(td2);
  3938. row1.appendChild(td3);
  3939. row2.appendChild(td4);
  3940. row2.appendChild(td5);
  3941. row2.appendChild(td6);
  3942. tbody.appendChild(row1);
  3943. tbody.appendChild(row2);
  3944. table.appendChild(tbody);
  3945. fitSection.appendChild(table);
  3946. div.appendChild(fitSection);
  3947. // Page scale ...
  3948. var pageScaleSection = document.createElement('div');
  3949. var span = document.createElement('div');
  3950. span.style.fontWeight = 'bold';
  3951. span.style.marginBottom = '12px';
  3952. mxUtils.write(span, mxResources.get('paperSize'));
  3953. pageScaleSection.appendChild(span);
  3954. var span = document.createElement('div');
  3955. span.style.marginBottom = '12px';
  3956. var accessor = PageSetupDialog.addPageFormatPanel(span, 'printdialog',
  3957. editorUi.editor.graph.pageFormat || mxConstants.PAGE_FORMAT_A4_PORTRAIT);
  3958. pageScaleSection.appendChild(span);
  3959. var span = document.createElement('span');
  3960. mxUtils.write(span, mxResources.get('pageScale'));
  3961. pageScaleSection.appendChild(span);
  3962. var pageScaleInput = document.createElement('input');
  3963. pageScaleInput.style.cssText = 'margin:0 8px 0 8px;';
  3964. pageScaleInput.setAttribute('value', '100 %');
  3965. pageScaleInput.style.width = '60px';
  3966. pageScaleSection.appendChild(pageScaleInput);
  3967. div.appendChild(pageScaleSection);
  3968. // Buttons
  3969. var buttons = document.createElement('div');
  3970. buttons.style.cssText = 'text-align:right;margin:48px 0 0 0;';
  3971. // Overall scale for print-out to account for print borders in dialogs etc
  3972. function preview(print)
  3973. {
  3974. var printScale = parseInt(pageScaleInput.value) / 100;
  3975. if (isNaN(printScale))
  3976. {
  3977. printScale = 1;
  3978. pageScaleInput.value = '100 %';
  3979. }
  3980. // Workaround to match available paper size in actual print output
  3981. printScale *= 0.75;
  3982. function printGraph(thisGraph, pv, forcePageBreaks)
  3983. {
  3984. // Negative coordinates are cropped or shifted if page visible
  3985. var gb = thisGraph.getGraphBounds();
  3986. var border = 0;
  3987. var x0 = 0;
  3988. var y0 = 0;
  3989. var pf = accessor.get();
  3990. var scale = 1 / thisGraph.pageScale;
  3991. var autoOrigin = fitRadio.checked;
  3992. if (autoOrigin)
  3993. {
  3994. var h = parseInt(sheetsAcrossInput.value);
  3995. var v = parseInt(sheetsDownInput.value);
  3996. scale = Math.min((pf.height * v) / (gb.height / thisGraph.view.scale),
  3997. (pf.width * h) / (gb.width / thisGraph.view.scale));
  3998. }
  3999. else
  4000. {
  4001. scale = parseInt(zoomInput.value) / (100 * thisGraph.pageScale);
  4002. if (isNaN(scale))
  4003. {
  4004. printScale = 1 / thisGraph.pageScale;
  4005. zoomInput.value = '100 %';
  4006. }
  4007. }
  4008. // Applies print scale
  4009. pf = mxRectangle.fromRectangle(pf);
  4010. pf.width = Math.ceil(pf.width * printScale);
  4011. pf.height = Math.ceil(pf.height * printScale);
  4012. scale *= printScale;
  4013. // Starts at first visible page
  4014. if (!autoOrigin && thisGraph.pageVisible)
  4015. {
  4016. var layout = thisGraph.getPageLayout();
  4017. x0 -= layout.x * pf.width;
  4018. y0 -= layout.y * pf.height;
  4019. }
  4020. else
  4021. {
  4022. autoOrigin = true;
  4023. }
  4024. if (pv == null)
  4025. {
  4026. pv = PrintDialog.createPrintPreview(thisGraph, scale, pf, border, x0, y0, autoOrigin);
  4027. pv.pageSelector = false;
  4028. pv.mathEnabled = false;
  4029. var file = editorUi.getCurrentFile();
  4030. if (file != null)
  4031. {
  4032. pv.title = file.getTitle();
  4033. }
  4034. var writeHead = pv.writeHead;
  4035. // Overridden to add custom fonts
  4036. pv.writeHead = function(doc)
  4037. {
  4038. writeHead.apply(this, arguments);
  4039. if (editorUi.editor.fontCss != null)
  4040. {
  4041. doc.writeln('<style type="text/css">');
  4042. doc.writeln(editorUi.editor.fontCss);
  4043. doc.writeln('</style>');
  4044. }
  4045. };
  4046. if (typeof(MathJax) !== 'undefined')
  4047. {
  4048. // Adds class to ignore if math is disabled
  4049. var printPreviewRenderPage = pv.renderPage;
  4050. pv.renderPage = function(w, h, dx, dy, content, pageNumber)
  4051. {
  4052. var prev = mxClient.NO_FO;
  4053. mxClient.NO_FO = (this.graph.mathEnabled && !this.useForeignObjectForMath) ?
  4054. true : this.originalNoForeignObject;
  4055. var result = printPreviewRenderPage.apply(this, arguments);
  4056. mxClient.NO_FO = prev;
  4057. if (this.graph.mathEnabled)
  4058. {
  4059. this.mathEnabled = this.mathEnabled || true;
  4060. }
  4061. else
  4062. {
  4063. result.className = 'geDisableMathJax';
  4064. }
  4065. return result;
  4066. };
  4067. }
  4068. pv.open(null, null, forcePageBreaks, true);
  4069. }
  4070. else
  4071. {
  4072. var bg = thisGraph.background;
  4073. if (bg == null || bg == '' || bg == mxConstants.NONE)
  4074. {
  4075. bg = '#ffffff';
  4076. }
  4077. pv.backgroundColor = bg;
  4078. pv.autoOrigin = autoOrigin;
  4079. pv.appendGraph(thisGraph, scale, x0, y0, forcePageBreaks, true);
  4080. }
  4081. return pv;
  4082. };
  4083. var pagesFrom = pagesFromInput.value;
  4084. var pagesTo = pagesToInput.value;
  4085. var ignorePages = !allPagesRadio.checked;
  4086. var pv = null;
  4087. if (ignorePages)
  4088. {
  4089. ignorePages = pagesFrom == currentPage && pagesTo == currentPage;
  4090. }
  4091. if (!ignorePages && editorUi.pages != null && editorUi.pages.length)
  4092. {
  4093. var i0 = 0;
  4094. var imax = editorUi.pages.length - 1;
  4095. if (!allPagesRadio.checked)
  4096. {
  4097. i0 = parseInt(pagesFrom) - 1;
  4098. imax = parseInt(pagesTo) - 1;
  4099. }
  4100. for (var i = i0; i <= imax; i++)
  4101. {
  4102. var page = editorUi.pages[i];
  4103. var tempGraph = (page == editorUi.currentPage) ? graph : null;
  4104. if (tempGraph == null)
  4105. {
  4106. tempGraph = editorUi.createTemporaryGraph(graph.getStylesheet());
  4107. // Restores graph settings that are relevant for printing
  4108. var pageVisible = true;
  4109. var mathEnabled = false;
  4110. var bg = null;
  4111. var bgImage = null;
  4112. if (page.viewState == null)
  4113. {
  4114. // Workaround to extract view state from XML node
  4115. // This changes the state of the page and parses
  4116. // the XML for the graph model even if not needed.
  4117. if (page.root == null)
  4118. {
  4119. editorUi.updatePageRoot(page);
  4120. }
  4121. }
  4122. if (page.viewState != null)
  4123. {
  4124. pageVisible = page.viewState.pageVisible;
  4125. mathEnabled = page.viewState.mathEnabled;
  4126. bg = page.viewState.background;
  4127. bgImage = page.viewState.backgroundImage;
  4128. }
  4129. tempGraph.background = bg;
  4130. tempGraph.backgroundImage = (bgImage != null) ? new mxImage(bgImage.src, bgImage.width, bgImage.height) : null;
  4131. tempGraph.pageVisible = pageVisible;
  4132. tempGraph.mathEnabled = mathEnabled;
  4133. // Redirects placeholders to current page
  4134. var graphGetGlobalVariable = tempGraph.getGlobalVariable;
  4135. tempGraph.getGlobalVariable = function(name)
  4136. {
  4137. if (name == 'page')
  4138. {
  4139. return page.getName();
  4140. }
  4141. else if (name == 'pagenumber')
  4142. {
  4143. return i + 1;
  4144. }
  4145. return graphGetGlobalVariable.apply(this, arguments);
  4146. };
  4147. document.body.appendChild(tempGraph.container);
  4148. editorUi.updatePageRoot(page);
  4149. tempGraph.model.setRoot(page.root);
  4150. }
  4151. pv = printGraph(tempGraph, pv, i != imax);
  4152. if (tempGraph != graph)
  4153. {
  4154. tempGraph.container.parentNode.removeChild(tempGraph.container);
  4155. }
  4156. }
  4157. }
  4158. else
  4159. {
  4160. pv = printGraph(graph);
  4161. }
  4162. if (pv == null)
  4163. {
  4164. editorUi.handleError({message: mxResources.get('errorUpdatingPreview')});
  4165. }
  4166. else
  4167. {
  4168. if (pv.mathEnabled)
  4169. {
  4170. var doc = pv.wnd.document;
  4171. doc.writeln('<script type="text/x-mathjax-config">');
  4172. doc.writeln('MathJax.Hub.Config({');
  4173. doc.writeln('showMathMenu: false,');
  4174. doc.writeln('messageStyle: "none",');
  4175. doc.writeln('jax: ["input/TeX", "input/MathML", "input/AsciiMath", "output/HTML-CSS"],');
  4176. doc.writeln('extensions: ["tex2jax.js", "mml2jax.js", "asciimath2jax.js"],');
  4177. doc.writeln('"HTML-CSS": {');
  4178. doc.writeln('imageFont: null');
  4179. doc.writeln('},');
  4180. doc.writeln('TeX: {');
  4181. doc.writeln('extensions: ["AMSmath.js", "AMSsymbols.js", "noErrors.js", "noUndefined.js"]');
  4182. doc.writeln('},');
  4183. doc.writeln('tex2jax: {');
  4184. doc.writeln(' ignoreClass: "geDisableMathJax"');
  4185. doc.writeln('},');
  4186. doc.writeln('asciimath2jax: {');
  4187. doc.writeln(' ignoreClass: "geDisableMathJax"');
  4188. doc.writeln('}');
  4189. doc.writeln('});');
  4190. // Adds asynchronous printing when MathJax finished rendering
  4191. if (print)
  4192. {
  4193. doc.writeln('MathJax.Hub.Queue(function () {');
  4194. doc.writeln('window.print();');
  4195. doc.writeln('});');
  4196. }
  4197. doc.writeln('</script>');
  4198. doc.writeln('<script type="text/javascript" src="' + DRAW_MATH_URL + '/MathJax.js"></script>');
  4199. }
  4200. pv.closeDocument();
  4201. if (!pv.mathEnabled && print)
  4202. {
  4203. PrintDialog.printPreview(pv);
  4204. }
  4205. }
  4206. };
  4207. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  4208. {
  4209. editorUi.hideDialog();
  4210. });
  4211. cancelBtn.className = 'geBtn';
  4212. if (editorUi.editor.cancelFirst)
  4213. {
  4214. buttons.appendChild(cancelBtn);
  4215. }
  4216. if (!editorUi.isOffline())
  4217. {
  4218. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  4219. {
  4220. graph.openLink('https://desk.draw.io/support/solutions/articles/16000048947');
  4221. });
  4222. helpBtn.className = 'geBtn';
  4223. buttons.appendChild(helpBtn);
  4224. }
  4225. if (PrintDialog.previewEnabled)
  4226. {
  4227. var previewBtn = mxUtils.button(mxResources.get('preview'), function()
  4228. {
  4229. editorUi.hideDialog();
  4230. preview(false);
  4231. });
  4232. previewBtn.className = 'geBtn';
  4233. buttons.appendChild(previewBtn);
  4234. }
  4235. var printBtn = mxUtils.button(mxResources.get((!PrintDialog.previewEnabled) ? 'ok' : 'print'), function()
  4236. {
  4237. editorUi.hideDialog();
  4238. preview(true);
  4239. });
  4240. printBtn.className = 'geBtn gePrimaryBtn';
  4241. buttons.appendChild(printBtn);
  4242. if (!editorUi.editor.cancelFirst)
  4243. {
  4244. buttons.appendChild(cancelBtn);
  4245. }
  4246. div.appendChild(buttons);
  4247. this.container = div;
  4248. };
  4249. // Execute fit page on page setup changes
  4250. var changePageSetupExecute = ChangePageSetup.prototype.execute;
  4251. ChangePageSetup.prototype.execute = function()
  4252. {
  4253. if (this.page == null)
  4254. {
  4255. this.page = this.ui.currentPage;
  4256. }
  4257. // Workaround for redo existing change with different current page
  4258. if (this.page != this.ui.currentPage)
  4259. {
  4260. if (this.page.viewState != null)
  4261. {
  4262. if (!this.ignoreColor)
  4263. {
  4264. this.page.viewState.background = this.color;
  4265. }
  4266. if (!this.ignoreImage)
  4267. {
  4268. this.page.viewState.backgroundImage = this.image;
  4269. }
  4270. if (this.format != null)
  4271. {
  4272. this.page.viewState.pageFormat = this.format;
  4273. }
  4274. if (this.mathEnabled != null)
  4275. {
  4276. this.page.viewState.mathEnabled = this.mathEnabled;
  4277. }
  4278. if (this.shadowVisible != null)
  4279. {
  4280. this.page.viewState.shadowVisible = this.shadowVisible;
  4281. }
  4282. }
  4283. }
  4284. else
  4285. {
  4286. changePageSetupExecute.apply(this, arguments);
  4287. if (this.mathEnabled != null && this.mathEnabled != this.ui.isMathEnabled())
  4288. {
  4289. this.ui.setMathEnabled(this.mathEnabled);
  4290. this.mathEnabled = !this.mathEnabled;
  4291. }
  4292. if (this.shadowVisible != null && this.shadowVisible != this.ui.editor.graph.shadowVisible)
  4293. {
  4294. this.ui.editor.graph.setShadowVisible(this.shadowVisible);
  4295. this.shadowVisible = !this.shadowVisible;
  4296. }
  4297. }
  4298. };
  4299. /**
  4300. * Capability check for canvas export
  4301. */
  4302. Editor.prototype.useCanvasForExport = false;
  4303. try
  4304. {
  4305. var canvas = document.createElement('canvas');
  4306. var img = new Image();
  4307. // LATER: Capability check should not be async
  4308. img.onload = function()
  4309. {
  4310. try
  4311. {
  4312. var ctx = canvas.getContext('2d');
  4313. ctx.drawImage(img, 0, 0);
  4314. // Works in Chrome, Firefox, Edge, Safari and Opera
  4315. var result = canvas.toDataURL('image/png');
  4316. Editor.prototype.useCanvasForExport = result != null && result.length > 6;
  4317. }
  4318. catch (e)
  4319. {
  4320. // ignore
  4321. }
  4322. };
  4323. // Checks if SVG with foreignObject can be exported
  4324. var svg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1px" height="1px" version="1.1"><foreignObject pointer-events="all" width="1" height="1"><div xmlns="http://www.w3.org/1999/xhtml"></div></foreignObject></svg>';
  4325. img.src = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(svg)));
  4326. }
  4327. catch (e)
  4328. {
  4329. // ignore
  4330. }
  4331. })();
  4332. // Extends codec for ChangePageSetup
  4333. (function()
  4334. {
  4335. var codec = new mxObjectCodec(new ChangePageSetup(), ['ui', 'previousColor', 'previousImage', 'previousFormat']);
  4336. codec.beforeDecode = function(dec, node, obj)
  4337. {
  4338. obj.ui = dec.ui;
  4339. return node;
  4340. };
  4341. codec.afterDecode = function(dec, node, obj)
  4342. {
  4343. obj.previousColor = obj.color;
  4344. obj.previousImage = obj.image;
  4345. obj.previousFormat = obj.format;
  4346. if (obj.foldingEnabled != null)
  4347. {
  4348. obj.foldingEnabled = !obj.foldingEnabled;
  4349. }
  4350. if (obj.mathEnabled != null)
  4351. {
  4352. obj.mathEnabled = !obj.mathEnabled;
  4353. }
  4354. if (obj.shadowVisible != null)
  4355. {
  4356. obj.shadowVisible = !obj.shadowVisible;
  4357. }
  4358. return obj;
  4359. };
  4360. mxCodecRegistry.register(codec);
  4361. })();