Dialogs.js 354 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529
  1. /**
  2. * Copyright (c) 2006-2020, JGraph Ltd
  3. * Copyright (c) 2006-2020, draw.io AG
  4. */
  5. var StorageDialog = function(editorUi, fn, rowLimit)
  6. {
  7. rowLimit = (rowLimit != null) ? rowLimit : 2;
  8. var div = document.createElement('div');
  9. div.style.textAlign = 'center';
  10. div.style.whiteSpace = 'nowrap';
  11. div.style.paddingTop = '0px';
  12. div.style.paddingBottom = '20px';
  13. var buttons = document.createElement('div');
  14. buttons.style.border = '1px solid #d3d3d3';
  15. buttons.style.borderWidth = '1px 0px 1px 0px';
  16. buttons.style.padding = '10px 0px 20px 0px';
  17. var count = 0, totalBtns = 0;
  18. var container = document.createElement('div');
  19. container.style.paddingTop = '2px';
  20. buttons.appendChild(container);
  21. var p3 = document.createElement('p');
  22. function addLogo(img, title, mode, clientName, labels, clientFn)
  23. {
  24. totalBtns++;
  25. if (++count > rowLimit)
  26. {
  27. mxUtils.br(container);
  28. count = 1;
  29. }
  30. var button = document.createElement('a');
  31. button.style.overflow = 'hidden';
  32. button.style.display = 'inline-block';
  33. button.className = 'geBaseButton';
  34. button.style.boxSizing = 'border-box';
  35. button.style.fontSize = '11px';
  36. button.style.position = 'relative';
  37. button.style.margin = '4px';
  38. button.style.marginTop = '8px';
  39. button.style.marginBottom = '0px';
  40. button.style.padding = '8px 10px 8px 10px';
  41. button.style.width = '88px';
  42. button.style.height = '100px';
  43. button.style.whiteSpace = 'nowrap';
  44. button.setAttribute('title', title);
  45. var label = document.createElement('div');
  46. label.style.textOverflow = 'ellipsis';
  47. label.style.overflow = 'hidden';
  48. label.style.position = 'absolute';
  49. label.style.bottom = '8px';
  50. label.style.left = '0px';
  51. label.style.right = '0px';
  52. mxUtils.write(label, title);
  53. button.appendChild(label);
  54. if (img != null)
  55. {
  56. var logo = document.createElement('img');
  57. logo.setAttribute('src', img);
  58. logo.setAttribute('border', '0');
  59. logo.setAttribute('align', 'absmiddle');
  60. logo.style.width = '60px';
  61. logo.style.height = '60px';
  62. logo.style.paddingBottom = '6px';
  63. button.appendChild(logo);
  64. }
  65. else
  66. {
  67. label.style.paddingTop = '5px';
  68. label.style.whiteSpace = 'normal';
  69. // Handles special case
  70. if (mxClient.IS_IOS)
  71. {
  72. button.style.padding = '0px 10px 20px 10px';
  73. button.style.top = '6px';
  74. }
  75. else if (mxClient.IS_FF)
  76. {
  77. label.style.paddingTop = '0px';
  78. label.style.marginTop = '-2px';
  79. }
  80. }
  81. if (labels != null)
  82. {
  83. for (var i = 0; i < labels.length; i++)
  84. {
  85. mxUtils.br(label);
  86. mxUtils.write(label, labels[i]);
  87. }
  88. }
  89. function initButton()
  90. {
  91. mxEvent.addListener(button, 'click', (clientFn != null) ? clientFn : function()
  92. {
  93. if (mode == App.MODE_GOOGLE && editorUi.spinner.spin(document.body, mxResources.get('authorizing')))
  94. {
  95. // Tries immediate authentication
  96. editorUi.drive.checkToken(mxUtils.bind(this, function()
  97. {
  98. editorUi.spinner.stop();
  99. editorUi.setMode(mode, true);
  100. fn();
  101. }));
  102. }
  103. else if (mode == App.MODE_ONEDRIVE && editorUi.spinner.spin(document.body, mxResources.get('authorizing')))
  104. {
  105. // Tries immediate authentication
  106. editorUi.oneDrive.checkToken(mxUtils.bind(this, function()
  107. {
  108. editorUi.spinner.stop();
  109. editorUi.setMode(mode, true);
  110. fn();
  111. }), function(err)
  112. {
  113. editorUi.spinner.stop();
  114. editorUi.handleError(err);
  115. });
  116. }
  117. else
  118. {
  119. editorUi.setMode(mode, true);
  120. fn();
  121. }
  122. });
  123. };
  124. // Supports lazy loading
  125. if (clientName != null && editorUi[clientName] == null)
  126. {
  127. logo.style.visibility = 'hidden';
  128. mxUtils.setOpacity(label, 10);
  129. var size = 12;
  130. var spinner = new Spinner({
  131. lines: 12, // The number of lines to draw
  132. length: size, // The length of each line
  133. width: 5, // The line thickness
  134. radius: 10, // The radius of the inner circle
  135. rotate: 0, // The rotation offset
  136. color: Editor.isDarkMode() ? '#c0c0c0' : '#000', // #rgb or #rrggbb
  137. speed: 1.5, // Rounds per second
  138. trail: 60, // Afterglow percentage
  139. shadow: false, // Whether to render a shadow
  140. hwaccel: false, // Whether to use hardware acceleration
  141. top: '40%',
  142. zIndex: 2e9 // The z-index (defaults to 2000000000)
  143. });
  144. spinner.spin(button);
  145. // Timeout after 30 secs
  146. var timeout = window.setTimeout(function()
  147. {
  148. if (editorUi[clientName] == null)
  149. {
  150. spinner.stop();
  151. button.style.display = 'none';
  152. }
  153. }, 30000);
  154. editorUi.addListener('clientLoaded', mxUtils.bind(this, function(sender, evt)
  155. {
  156. if (editorUi[clientName] != null && evt.getProperty('client') == editorUi[clientName])
  157. {
  158. window.clearTimeout(timeout);
  159. mxUtils.setOpacity(label, 100);
  160. logo.style.visibility = '';
  161. spinner.stop();
  162. initButton();
  163. if (clientName == 'drive' && p3.parentNode != null)
  164. {
  165. p3.parentNode.removeChild(p3);
  166. }
  167. }
  168. }));
  169. }
  170. else
  171. {
  172. initButton();
  173. }
  174. container.appendChild(button);
  175. };
  176. var hd = document.createElement('p');
  177. hd.style.cssText = 'font-size:22px;padding:4px 0 16px 0;margin:0;color:gray;';
  178. mxUtils.write(hd, mxResources.get('saveDiagramsTo') + ':');
  179. div.appendChild(hd);
  180. var addButtons = function()
  181. {
  182. count = 0;
  183. if (typeof window.DriveClient === 'function')
  184. {
  185. addLogo(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googleDrive'), App.MODE_GOOGLE, 'drive');
  186. }
  187. if (typeof window.OneDriveClient === 'function')
  188. {
  189. addLogo(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), App.MODE_ONEDRIVE, 'oneDrive');
  190. }
  191. if (urlParams['noDevice'] != '1')
  192. {
  193. addLogo(IMAGE_PATH + '/osa_drive-harddisk.png', mxResources.get('device'), App.MODE_DEVICE);
  194. }
  195. if (isLocalStorage && (urlParams['browser'] == '1' || urlParams['offline'] == '1'))
  196. {
  197. addLogo(IMAGE_PATH + '/osa_database.png', mxResources.get('browser'), App.MODE_BROWSER);
  198. }
  199. if (typeof window.DropboxClient === 'function')
  200. {
  201. addLogo(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), App.MODE_DROPBOX, 'dropbox');
  202. }
  203. if (editorUi.gitHub != null)
  204. {
  205. addLogo(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), App.MODE_GITHUB, 'gitHub');
  206. }
  207. if (editorUi.gitLab != null)
  208. {
  209. addLogo(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), App.MODE_GITLAB, 'gitLab');
  210. }
  211. };
  212. div.appendChild(buttons);
  213. addButtons();
  214. var later = document.createElement('span');
  215. later.style.position = 'absolute';
  216. later.style.cursor = 'pointer';
  217. later.style.bottom = '27px';
  218. later.style.color = 'gray';
  219. later.style.userSelect = 'none';
  220. later.style.textAlign = 'center';
  221. later.style.left = '50%';
  222. mxUtils.setPrefixedStyle(later.style, 'transform', 'translate(-50%,0)');
  223. mxUtils.write(later, mxResources.get('decideLater'));
  224. div.appendChild(later);
  225. mxEvent.addListener(later, 'click', function()
  226. {
  227. editorUi.hideDialog();
  228. var prev = Editor.useLocalStorage;
  229. editorUi.createFile(editorUi.defaultFilename,
  230. null, null, null, null, null, null, true);
  231. Editor.useLocalStorage = prev;
  232. });
  233. // Checks if Google Drive is missing after a 5 sec delay
  234. if (mxClient.IS_SVG && isLocalStorage && urlParams['gapi'] != '0' &&
  235. (document.documentMode == null || document.documentMode >= 10))
  236. {
  237. window.setTimeout(function()
  238. {
  239. if (editorUi.drive == null)
  240. {
  241. // To check for Disconnect plugin in chrome use mxClient.IS_GC and check for URL:
  242. // chrome-extension://jeoacafpbcihiomhlakheieifhpjdfeo/scripts/vendor/jquery/jquery-2.0.3.min.map
  243. p3.style.padding = '7px';
  244. p3.style.fontSize = '9pt';
  245. p3.style.marginTop = '-14px';
  246. p3.innerHTML = '<a style="background-color:#dcdcdc;padding:6px;color:black;text-decoration:none;" ' +
  247. 'href="https://desk.draw.io/a/solutions/articles/16000074659" target="_blank">' +
  248. '<img border="0" src="' + mxGraph.prototype.warningImage.src + '" align="absmiddle" ' +
  249. 'style="margin-top:-4px"> ' + mxResources.get('googleDriveMissingClickHere') + '</a>';
  250. div.appendChild(p3);
  251. }
  252. }, 5000);
  253. }
  254. this.container = div;
  255. };
  256. /**
  257. * Constructs a dialog for creating new files from templates.
  258. */
  259. var SplashDialog = function(editorUi)
  260. {
  261. var div = document.createElement('div');
  262. div.style.textAlign = 'center';
  263. if (mxClient.IS_CHROMEAPP || EditorUi.isElectronApp)
  264. {
  265. var elt = editorUi.addLanguageMenu(div, false, '28px');
  266. if (elt != null)
  267. {
  268. elt.style.bottom = '24px';
  269. }
  270. }
  271. var logo = document.createElement('img');
  272. logo.setAttribute('border', '0');
  273. logo.setAttribute('align', 'absmiddle');
  274. logo.style.width = '32px';
  275. logo.style.height = '32px';
  276. logo.style.marginRight = '8px';
  277. logo.style.marginTop = '-4px';
  278. var buttons = document.createElement('div');
  279. buttons.style.margin = '8px 0px 0px 0px';
  280. buttons.style.padding = '18px 0px 24px 0px';
  281. var service = '';
  282. if (editorUi.mode == App.MODE_GOOGLE)
  283. {
  284. logo.src = IMAGE_PATH + '/google-drive-logo.svg';
  285. service = mxResources.get('googleDrive');
  286. }
  287. else if (editorUi.mode == App.MODE_DROPBOX)
  288. {
  289. logo.src = IMAGE_PATH + '/dropbox-logo.svg';
  290. service = mxResources.get('dropbox');
  291. }
  292. else if (editorUi.mode == App.MODE_ONEDRIVE)
  293. {
  294. logo.src = IMAGE_PATH + '/onedrive-logo.svg';
  295. service = mxResources.get('oneDrive');
  296. }
  297. else if (editorUi.mode == App.MODE_GITHUB)
  298. {
  299. logo.src = IMAGE_PATH + '/github-logo.svg';
  300. service = mxResources.get('github');
  301. }
  302. else if (editorUi.mode == App.MODE_GITLAB)
  303. {
  304. logo.src = IMAGE_PATH + '/gitlab-logo.svg';
  305. service = mxResources.get('gitlab');
  306. }
  307. else if (editorUi.mode == App.MODE_BROWSER)
  308. {
  309. logo.src = IMAGE_PATH + '/osa_database.png';
  310. service = mxResources.get('browser');
  311. }
  312. else if (editorUi.mode == App.MODE_TRELLO)
  313. {
  314. logo.src = IMAGE_PATH + '/trello-logo.svg';
  315. service = mxResources.get('trello');
  316. }
  317. else
  318. {
  319. logo.src = IMAGE_PATH + '/osa_drive-harddisk.png';
  320. buttons.style.paddingBottom = '10px';
  321. buttons.style.paddingTop = '30px';
  322. service = mxResources.get('device');
  323. }
  324. var btn = document.createElement('button');
  325. btn.className = 'geBigButton';
  326. btn.style.marginBottom = '8px';
  327. btn.style.fontSize = '18px';
  328. btn.style.padding = '10px';
  329. btn.style.width = '340px';
  330. if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp)
  331. {
  332. buttons.style.border = '1px solid #d3d3d3';
  333. buttons.style.borderWidth = '1px 0px 1px 0px';
  334. var table = document.createElement('table');
  335. var tbody = document.createElement('tbody');
  336. var row = document.createElement('tr');
  337. var left = document.createElement('td');
  338. var right = document.createElement('td');
  339. table.setAttribute('align', 'center');
  340. left.appendChild(logo);
  341. var title = document.createElement('div');
  342. title.style.fontSize = '22px';
  343. title.style.paddingBottom = '6px';
  344. title.style.color = 'gray';
  345. mxUtils.write(title, service);
  346. right.style.textAlign = 'left';
  347. right.appendChild(title);
  348. row.appendChild(left);
  349. row.appendChild(right);
  350. tbody.appendChild(row);
  351. table.appendChild(tbody);
  352. div.appendChild(table);
  353. var change = document.createElement('span');
  354. change.style.cssText = 'position:absolute;cursor:pointer;bottom:27px;color:gray;userSelect:none;text-align:center;left:50%;';
  355. mxUtils.setPrefixedStyle(change.style, 'transform', 'translate(-50%,0)');
  356. mxUtils.write(change, mxResources.get('changeStorage'));
  357. mxEvent.addListener(change, 'click', function()
  358. {
  359. editorUi.hideDialog(false);
  360. editorUi.setMode(null);
  361. editorUi.clearMode();
  362. editorUi.showSplash(true);
  363. });
  364. div.appendChild(change);
  365. }
  366. else
  367. {
  368. buttons.style.padding = '42px 0px 10px 0px';
  369. btn.style.marginBottom = '12px';
  370. }
  371. mxUtils.write(btn, mxResources.get('createNewDiagram'));
  372. mxEvent.addListener(btn, 'click', function()
  373. {
  374. editorUi.hideDialog();
  375. editorUi.actions.get('new').funct();
  376. });
  377. buttons.appendChild(btn);
  378. mxUtils.br(buttons);
  379. var btn = document.createElement('button');
  380. btn.className = 'geBigButton';
  381. btn.style.marginBottom = '22px';
  382. btn.style.fontSize = '18px';
  383. btn.style.padding = '10px';
  384. btn.style.width = '340px';
  385. mxUtils.write(btn, mxResources.get('openExistingDiagram'));
  386. mxEvent.addListener(btn, 'click', function()
  387. {
  388. editorUi.actions.get('open').funct();
  389. });
  390. buttons.appendChild(btn);
  391. var storage = 'undefined';
  392. if (editorUi.mode == App.MODE_GOOGLE)
  393. {
  394. storage = mxResources.get('googleDrive');
  395. }
  396. else if (editorUi.mode == App.MODE_DROPBOX)
  397. {
  398. storage = mxResources.get('dropbox');
  399. }
  400. else if (editorUi.mode == App.MODE_ONEDRIVE)
  401. {
  402. storage = mxResources.get('oneDrive');
  403. }
  404. else if (editorUi.mode == App.MODE_GITHUB)
  405. {
  406. storage = mxResources.get('github');
  407. }
  408. else if (editorUi.mode == App.MODE_GITLAB)
  409. {
  410. storage = mxResources.get('gitlab');
  411. }
  412. else if (editorUi.mode == App.MODE_TRELLO)
  413. {
  414. storage = mxResources.get('trello');
  415. }
  416. else if (editorUi.mode == App.MODE_DEVICE)
  417. {
  418. storage = mxResources.get('device');
  419. }
  420. else if (editorUi.mode == App.MODE_BROWSER)
  421. {
  422. storage = mxResources.get('browser');
  423. }
  424. if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp)
  425. {
  426. function addLogout(logout)
  427. {
  428. btn.style.marginBottom = '24px';
  429. var link = document.createElement('a');
  430. link.style.display = 'inline-block';
  431. link.style.color = 'gray';
  432. link.style.cursor = 'pointer';
  433. link.style.marginTop = '6px';
  434. mxUtils.write(link, mxResources.get('signOut'));
  435. // Makes room after last big buttons
  436. btn.style.marginBottom = '16px';
  437. buttons.style.paddingBottom = '18px';
  438. mxEvent.addListener(link, 'click', function()
  439. {
  440. editorUi.confirm(mxResources.get('areYouSure'), function()
  441. {
  442. logout();
  443. });
  444. });
  445. buttons.appendChild(link);
  446. };
  447. if (editorUi.mode == App.MODE_GOOGLE && editorUi.drive != null)
  448. {
  449. var driveUsers =editorUi.drive.getUsersList();
  450. if (driveUsers.length > 0)
  451. {
  452. var title = document.createElement('span');
  453. title.style.marginTop = '6px';
  454. mxUtils.write(title, mxResources.get('changeUser') + ':');
  455. // Makes room after last big buttons
  456. btn.style.marginBottom = '16px';
  457. buttons.style.paddingBottom = '18px';
  458. buttons.appendChild(title);
  459. var usersSelect = document.createElement('select');
  460. usersSelect.style.marginLeft = '4px';
  461. usersSelect.style.width = '140px';
  462. for (var i = 0; i < driveUsers.length; i++)
  463. {
  464. var option = document.createElement('option');
  465. mxUtils.write(option, driveUsers[i].displayName);
  466. option.value = i;
  467. usersSelect.appendChild(option);
  468. //More info (email) about the user in a disabled option
  469. option = document.createElement('option');
  470. option.innerHTML = '&nbsp;&nbsp;&nbsp;';
  471. mxUtils.write(option, '<' + driveUsers[i].email + '>');
  472. option.setAttribute('disabled', 'disabled');
  473. usersSelect.appendChild(option);
  474. }
  475. //Add account option
  476. var option = document.createElement('option');
  477. mxUtils.write(option, mxResources.get('addAccount'));
  478. option.value = driveUsers.length;
  479. usersSelect.appendChild(option);
  480. mxEvent.addListener(usersSelect, 'change', function()
  481. {
  482. var userIndex = usersSelect.value;
  483. var existingAccount = driveUsers.length != userIndex;
  484. if (existingAccount)
  485. {
  486. editorUi.drive.setUser(driveUsers[userIndex]);
  487. }
  488. editorUi.drive.authorize(existingAccount, function()
  489. {
  490. editorUi.setMode(App.MODE_GOOGLE);
  491. editorUi.hideDialog();
  492. editorUi.showSplash();
  493. }, function(resp)
  494. {
  495. editorUi.handleError(resp, null, function()
  496. {
  497. editorUi.hideDialog();
  498. editorUi.showSplash();
  499. });
  500. }, true);
  501. });
  502. buttons.appendChild(usersSelect);
  503. }
  504. else
  505. {
  506. addLogout(function()
  507. {
  508. editorUi.drive.logout();
  509. });
  510. }
  511. }
  512. else if (editorUi.mode == App.MODE_ONEDRIVE && editorUi.oneDrive != null && !editorUi.oneDrive.noLogout)
  513. {
  514. addLogout(function()
  515. {
  516. editorUi.oneDrive.logout();
  517. });
  518. }
  519. else if (editorUi.mode == App.MODE_GITHUB && editorUi.gitHub != null)
  520. {
  521. addLogout(function()
  522. {
  523. editorUi.gitHub.logout();
  524. editorUi.openLink('https://www.github.com/logout');
  525. });
  526. }
  527. else if (editorUi.mode == App.MODE_GITLAB && editorUi.gitLab != null)
  528. {
  529. addLogout(function()
  530. {
  531. editorUi.gitLab.logout();
  532. editorUi.openLink(DRAWIO_GITLAB_URL + '/users/sign_out');
  533. });
  534. }
  535. else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null)
  536. {
  537. if (editorUi.trello.isAuthorized())
  538. {
  539. addLogout(function()
  540. {
  541. editorUi.trello.logout();
  542. });
  543. }
  544. }
  545. else if (editorUi.mode == App.MODE_DROPBOX && editorUi.dropbox != null)
  546. {
  547. // NOTE: Dropbox has a logout option in the picker
  548. addLogout(function()
  549. {
  550. editorUi.dropbox.logout();
  551. editorUi.openLink('https://www.dropbox.com/logout');
  552. });
  553. }
  554. }
  555. div.appendChild(buttons);
  556. this.container = div;
  557. };
  558. /**
  559. * Constructs a new embed dialog
  560. */
  561. var EmbedDialog = function(editorUi, result, timeout, ignoreSize, previewFn, title, tweet, previewTitle, filename)
  562. {
  563. tweet = (tweet != null) ? tweet : 'Check out the diagram I made using @drawio';
  564. var div = document.createElement('div');
  565. var maxSize = 500000;
  566. var maxFbSize = 51200;
  567. var maxTwitterSize = 7168;
  568. // Checks if result is a link
  569. var validUrl = /^https?:\/\//.test(result) || /^mailto:\/\//.test(result);
  570. if (title != null)
  571. {
  572. mxUtils.write(div, title);
  573. }
  574. else
  575. {
  576. mxUtils.write(div, mxResources.get((result.length < maxSize) ?
  577. ((validUrl) ? 'link' : 'mainEmbedNotice') : 'preview') + ':');
  578. }
  579. mxUtils.br(div);
  580. var size = document.createElement('div');
  581. size.style.position = 'absolute';
  582. size.style.top = '30px';
  583. size.style.right = '30px';
  584. size.style.color = 'gray';
  585. mxUtils.write(size, editorUi.formatFileSize(result.length));
  586. div.appendChild(size);
  587. // Using DIV for faster rendering
  588. var text = document.createElement('textarea');
  589. text.setAttribute('autocomplete', 'off');
  590. text.setAttribute('autocorrect', 'off');
  591. text.setAttribute('autocapitalize', 'off');
  592. text.setAttribute('spellcheck', 'false');
  593. text.style.fontFamily = 'monospace';
  594. text.style.wordBreak = 'break-all';
  595. text.style.marginTop = '10px';
  596. text.style.resize = 'none';
  597. text.style.height = '150px';
  598. text.style.width = '440px';
  599. text.style.border = '1px solid gray';
  600. text.value = mxResources.get('updatingDocument');
  601. div.appendChild(text);
  602. mxUtils.br(div);
  603. this.init = function()
  604. {
  605. window.setTimeout(function()
  606. {
  607. if (result.length < maxSize)
  608. {
  609. text.value = result;
  610. text.focus();
  611. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  612. {
  613. text.select();
  614. }
  615. else
  616. {
  617. document.execCommand('selectAll', false, null);
  618. }
  619. }
  620. else
  621. {
  622. text.setAttribute('readonly', 'true');
  623. text.value = mxResources.get('tooLargeUseDownload');
  624. }
  625. }, 0);
  626. };
  627. var buttons = document.createElement('div');
  628. buttons.style.position = 'absolute';
  629. buttons.style.bottom = '36px';
  630. buttons.style.right = '32px';
  631. var previewBtn = null;
  632. // Loads forever in IE9
  633. if (EmbedDialog.showPreviewOption && (!mxClient.IS_CHROMEAPP || validUrl) && !navigator.standalone && (validUrl ||
  634. (mxClient.IS_SVG && (document.documentMode == null || document.documentMode > 9))))
  635. {
  636. previewBtn = mxUtils.button((previewTitle != null) ? previewTitle :
  637. mxResources.get((result.length < maxSize) ? 'preview' : 'openInNewWindow'), function()
  638. {
  639. var value = (result.length < maxSize) ? text.value : result;
  640. if (previewFn != null)
  641. {
  642. previewFn(value);
  643. }
  644. else
  645. {
  646. if (validUrl)
  647. {
  648. try
  649. {
  650. var win = editorUi.openLink(value);
  651. if (win != null && (timeout == null || timeout > 0))
  652. {
  653. window.setTimeout(mxUtils.bind(this, function()
  654. {
  655. try
  656. {
  657. if (win != null && win.location.href != null &&
  658. win.location.href.substring(0, 8) != value.substring(0, 8))
  659. {
  660. win.close();
  661. editorUi.handleError({message: mxResources.get('drawingTooLarge')});
  662. }
  663. }
  664. catch (e)
  665. {
  666. // ignore
  667. }
  668. }), timeout || 500);
  669. }
  670. }
  671. catch (e)
  672. {
  673. editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')});
  674. }
  675. }
  676. else
  677. {
  678. var wnd = window.open();
  679. var doc = (wnd != null) ? wnd.document : null;
  680. if (doc != null)
  681. {
  682. doc.writeln('<html><head><title>' + encodeURIComponent(mxResources.get('preview')) +
  683. '</title><meta charset="utf-8"></head>' +
  684. '<body>' + result + '</body></html>');
  685. doc.close();
  686. }
  687. else
  688. {
  689. editorUi.handleError({message: mxResources.get('errorUpdatingPreview')});
  690. }
  691. }
  692. }
  693. });
  694. previewBtn.className = 'geBtn';
  695. buttons.appendChild(previewBtn);
  696. }
  697. if (!validUrl || result.length > 7500)
  698. {
  699. var downloadBtn = mxUtils.button(mxResources.get('download'), function()
  700. {
  701. editorUi.hideDialog();
  702. editorUi.saveData((filename != null) ? filename : 'embed.txt', 'txt', result, 'text/plain');
  703. });
  704. downloadBtn.className = 'geBtn';
  705. buttons.appendChild(downloadBtn);
  706. }
  707. // Twitter-intent does not allow more characters, must be pasted manually
  708. if (validUrl && (!editorUi.isOffline() || mxClient.IS_CHROMEAPP))
  709. {
  710. if (result.length < maxFbSize)
  711. {
  712. var fbBtn = mxUtils.button('', function()
  713. {
  714. try
  715. {
  716. var url = 'https://www.facebook.com/sharer.php?p[url]=' +
  717. encodeURIComponent(text.value);
  718. editorUi.openLink(url);
  719. }
  720. catch (e)
  721. {
  722. editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')});
  723. }
  724. });
  725. var img = document.createElement('img');
  726. img.setAttribute('src', Editor.facebookImage);
  727. img.setAttribute('width', '18');
  728. img.setAttribute('height', '18');
  729. img.setAttribute('border', '0');
  730. fbBtn.appendChild(img);
  731. fbBtn.setAttribute('title', mxResources.get('facebook') + ' (' +
  732. editorUi.formatFileSize(maxFbSize) + ' max)');
  733. fbBtn.style.verticalAlign = 'bottom';
  734. fbBtn.style.paddingTop = '4px';
  735. fbBtn.style.minWidth = '46px'
  736. fbBtn.className = 'geBtn';
  737. buttons.appendChild(fbBtn);
  738. }
  739. if (result.length < maxTwitterSize)
  740. {
  741. var tweetBtn = mxUtils.button('', function()
  742. {
  743. try
  744. {
  745. var url = 'https://twitter.com/intent/tweet?text=' +
  746. encodeURIComponent(tweet) + '&url=' +
  747. encodeURIComponent(text.value);
  748. editorUi.openLink(url);
  749. }
  750. catch (e)
  751. {
  752. editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')});
  753. }
  754. });
  755. var img = document.createElement('img');
  756. img.setAttribute('src', Editor.tweetImage);
  757. img.setAttribute('width', '18');
  758. img.setAttribute('height', '18');
  759. img.setAttribute('border', '0');
  760. img.style.marginBottom = '5px'
  761. tweetBtn.appendChild(img);
  762. tweetBtn.setAttribute('title', mxResources.get('twitter') + ' (' +
  763. editorUi.formatFileSize(maxTwitterSize) + ' max)');
  764. tweetBtn.style.verticalAlign = 'bottom';
  765. tweetBtn.style.paddingTop = '4px';
  766. tweetBtn.style.minWidth = '46px'
  767. tweetBtn.className = 'geBtn';
  768. buttons.appendChild(tweetBtn);
  769. }
  770. }
  771. if (!editorUi.isOffline() && result.length < maxSize)
  772. {
  773. var emailBtn = mxUtils.button('', function()
  774. {
  775. try
  776. {
  777. var url = 'mailto:?subject=' +
  778. encodeURIComponent(filename || editorUi.defaultFilename) + '&body=' +
  779. encodeURIComponent(text.value);
  780. editorUi.openLink(url);
  781. }
  782. catch (e)
  783. {
  784. editorUi.handleError({message: e.message || mxResources.get('drawingTooLarge')});
  785. }
  786. });
  787. var img = document.createElement('img');
  788. img.className = 'geAdaptiveAsset';
  789. img.setAttribute('src', Editor.mailImage);
  790. img.setAttribute('width', '18');
  791. img.setAttribute('height', '18');
  792. img.setAttribute('border', '0');
  793. img.style.marginBottom = '5px'
  794. emailBtn.appendChild(img);
  795. emailBtn.style.verticalAlign = 'bottom';
  796. emailBtn.style.paddingTop = '4px';
  797. emailBtn.style.minWidth = '46px'
  798. emailBtn.className = 'geBtn';
  799. buttons.appendChild(emailBtn);
  800. }
  801. var closeBtn = mxUtils.button(mxResources.get('close'), function()
  802. {
  803. editorUi.hideDialog();
  804. });
  805. buttons.appendChild(closeBtn);
  806. var copyBtn = mxUtils.button(mxResources.get('copy'), function()
  807. {
  808. text.focus();
  809. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  810. {
  811. text.select();
  812. }
  813. else
  814. {
  815. document.execCommand('selectAll', false, null);
  816. }
  817. document.execCommand('copy');
  818. editorUi.alert(mxResources.get('copiedToClipboard'));
  819. });
  820. if (result.length < maxSize)
  821. {
  822. // Does not work in Safari and shows annoying dialog for IE11-
  823. if (!mxClient.IS_SF && document.documentMode == null)
  824. {
  825. buttons.appendChild(copyBtn);
  826. copyBtn.className = 'geBtn gePrimaryBtn';
  827. closeBtn.className = 'geBtn';
  828. }
  829. else
  830. {
  831. closeBtn.className = 'geBtn gePrimaryBtn';
  832. }
  833. }
  834. else if (previewBtn != null)
  835. {
  836. buttons.appendChild(previewBtn);
  837. closeBtn.className = 'geBtn';
  838. previewBtn.className = 'geBtn gePrimaryBtn';
  839. }
  840. div.appendChild(buttons);
  841. this.container = div;
  842. };
  843. /**
  844. * Add embed dialog option.
  845. */
  846. EmbedDialog.showPreviewOption = true;
  847. /**
  848. * Constructs a dialog for embedding the diagram in Google Sites.
  849. */
  850. var GoogleSitesDialog = function(editorUi, publicUrl)
  851. {
  852. var div = document.createElement('div');
  853. var graph = editorUi.editor.graph;
  854. var bounds = graph.getGraphBounds();
  855. var scale = graph.view.scale;
  856. var x0 = Math.floor(bounds.x / scale - graph.view.translate.x);
  857. var y0 = Math.floor(bounds.y / scale - graph.view.translate.y);
  858. mxUtils.write(div, mxResources.get('googleGadget') + ':');
  859. mxUtils.br(div);
  860. var gadgetInput = document.createElement('input');
  861. gadgetInput.setAttribute('type', 'text');
  862. gadgetInput.style.marginBottom = '8px';
  863. gadgetInput.style.marginTop = '2px';
  864. gadgetInput.style.width = '410px';
  865. div.appendChild(gadgetInput);
  866. mxUtils.br(div);
  867. this.init = function()
  868. {
  869. gadgetInput.focus();
  870. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  871. {
  872. gadgetInput.select();
  873. }
  874. else
  875. {
  876. document.execCommand('selectAll', false, null);
  877. }
  878. };
  879. mxUtils.write(div, mxResources.get('top') + ':');
  880. var topInput = document.createElement('input');
  881. topInput.setAttribute('type', 'text');
  882. topInput.setAttribute('size', '4');
  883. topInput.style.marginRight = '16px';
  884. topInput.style.marginLeft = '4px';
  885. topInput.value = x0;
  886. div.appendChild(topInput);
  887. mxUtils.write(div, mxResources.get('height') + ':');
  888. var heightInput = document.createElement('input');
  889. heightInput.setAttribute('type', 'text');
  890. heightInput.setAttribute('size', '4');
  891. heightInput.style.marginLeft = '4px';
  892. heightInput.value = Math.ceil(bounds.height / scale);
  893. div.appendChild(heightInput);
  894. mxUtils.br(div);
  895. var hr = document.createElement('hr');
  896. hr.setAttribute('size', '1');
  897. hr.style.marginBottom = '16px';
  898. hr.style.marginTop = '16px';
  899. div.appendChild(hr);
  900. mxUtils.write(div, mxResources.get('publicDiagramUrl') + ':');
  901. mxUtils.br(div);
  902. var urlInput = document.createElement('input');
  903. urlInput.setAttribute('type', 'text');
  904. urlInput.setAttribute('size', '28');
  905. urlInput.style.marginBottom = '8px';
  906. urlInput.style.marginTop = '2px';
  907. urlInput.style.width = '410px';
  908. urlInput.value = publicUrl || '';
  909. div.appendChild(urlInput);
  910. mxUtils.br(div);
  911. mxUtils.write(div, mxResources.get('borderWidth') + ':');
  912. var borderInput = document.createElement('input');
  913. borderInput.setAttribute('type', 'text');
  914. borderInput.setAttribute('size', '3');
  915. borderInput.style.marginBottom = '8px';
  916. borderInput.style.marginLeft = '4px';
  917. borderInput.value = '0';
  918. div.appendChild(borderInput);
  919. mxUtils.br(div);
  920. var panCheckBox = document.createElement('input');
  921. panCheckBox.setAttribute('type', 'checkbox');
  922. panCheckBox.setAttribute('checked', 'checked');
  923. panCheckBox.defaultChecked = true;
  924. panCheckBox.style.marginLeft = '16px';
  925. div.appendChild(panCheckBox);
  926. mxUtils.write(div, mxResources.get('pan') + ' ');
  927. var zoomCheckBox = document.createElement('input');
  928. zoomCheckBox.setAttribute('type', 'checkbox');
  929. zoomCheckBox.setAttribute('checked', 'checked');
  930. zoomCheckBox.defaultChecked = true;
  931. zoomCheckBox.style.marginLeft = '8px';
  932. div.appendChild(zoomCheckBox);
  933. mxUtils.write(div, mxResources.get('zoom') + ' ');
  934. var editCheckBox = document.createElement('input');
  935. editCheckBox.setAttribute('type', 'checkbox');
  936. editCheckBox.style.marginLeft = '8px';
  937. editCheckBox.setAttribute('title', window.location.href);
  938. div.appendChild(editCheckBox);
  939. mxUtils.write(div, mxResources.get('edit') + ' ');
  940. var editBlankCheckBox = document.createElement('input');
  941. editBlankCheckBox.setAttribute('type', 'checkbox');
  942. editBlankCheckBox.style.marginLeft = '8px';
  943. div.appendChild(editBlankCheckBox);
  944. mxUtils.write(div, mxResources.get('asNew') + ' ');
  945. mxUtils.br(div);
  946. var resizeCheckBox = document.createElement('input');
  947. resizeCheckBox.setAttribute('type', 'checkbox');
  948. resizeCheckBox.setAttribute('checked', 'checked');
  949. resizeCheckBox.defaultChecked = true;
  950. resizeCheckBox.style.marginLeft = '16px';
  951. div.appendChild(resizeCheckBox);
  952. mxUtils.write(div, mxResources.get('resize') + ' ');
  953. var fitCheckBox = document.createElement('input');
  954. fitCheckBox.setAttribute('type', 'checkbox');
  955. fitCheckBox.style.marginLeft = '8px';
  956. div.appendChild(fitCheckBox);
  957. mxUtils.write(div, mxResources.get('fit') + ' ');
  958. var embedCheckBox = document.createElement('input');
  959. embedCheckBox.setAttribute('type', 'checkbox');
  960. embedCheckBox.style.marginLeft = '8px';
  961. div.appendChild(embedCheckBox);
  962. mxUtils.write(div, mxResources.get('embed') + ' ');
  963. var node = null;
  964. var s = editorUi.getBasenames().join(';');
  965. var file = editorUi.getCurrentFile();
  966. function update()
  967. {
  968. var title = (file != null && file.getTitle() != null) ? file.getTitle() : this.defaultFilename;
  969. if (embedCheckBox.checked && urlInput.value != '')
  970. {
  971. var encUrl = encodeURIComponent(mxUtils.htmlEntities(urlInput.value));
  972. var gurl = 'https://www.draw.io/gadget.xml?type=4&diagram=' + encUrl;
  973. if (title != null)
  974. {
  975. gurl += '&title=' + encodeURIComponent(title);
  976. }
  977. if (s.length > 0)
  978. {
  979. gurl += '&s=' + s;
  980. }
  981. if (borderInput.value != '' && borderInput.value != '0')
  982. {
  983. gurl += '&border=' + borderInput.value;
  984. }
  985. if (heightInput.value != '')
  986. {
  987. gurl += '&height=' + heightInput.value;
  988. }
  989. gurl += '&pan=' + ((panCheckBox.checked) ? '1': '0');
  990. gurl += '&zoom=' + ((zoomCheckBox.checked) ? '1': '0');
  991. gurl += '&fit=' + ((fitCheckBox.checked) ? '1': '0');
  992. gurl += '&resize=' + ((resizeCheckBox.checked) ? '1': '0');
  993. gurl += '&x0=' + Number(topInput.value);
  994. gurl += '&y0=' + y0;
  995. if (graph.mathEnabled)
  996. {
  997. gurl += '&math=1';
  998. }
  999. if (editBlankCheckBox.checked)
  1000. {
  1001. gurl += '&edit=_blank';
  1002. }
  1003. else if (editCheckBox.checked)
  1004. {
  1005. gurl += '&edit=' + encodeURIComponent(mxUtils.htmlEntities(window.location.href));
  1006. }
  1007. gadgetInput.value = gurl;
  1008. }
  1009. else if (file.constructor == DriveFile || file.constructor == DropboxFile)
  1010. {
  1011. var gurl = 'https://www.draw.io/gadget.xml?embed=0&diagram=';
  1012. if (urlInput.value != '')
  1013. {
  1014. gurl += encodeURIComponent(mxUtils.htmlEntities(urlInput.value)) + '&type=3';
  1015. }
  1016. else
  1017. {
  1018. gurl += file.getHash().substring(1);
  1019. if (file.constructor == DropboxFile)
  1020. {
  1021. gurl += '&type=2';
  1022. }
  1023. else
  1024. {
  1025. gurl += '&type=1';
  1026. }
  1027. }
  1028. if (title != null)
  1029. {
  1030. gurl += '&title=' + encodeURIComponent(title);
  1031. }
  1032. if (heightInput.value != '')
  1033. {
  1034. var h = parseInt(heightInput.value) + parseInt(topInput.value);
  1035. gurl += '&height=' + h;
  1036. }
  1037. gadgetInput.value = gurl;
  1038. }
  1039. else
  1040. {
  1041. gadgetInput.value = '';
  1042. }
  1043. };
  1044. mxEvent.addListener(panCheckBox, 'change', update);
  1045. mxEvent.addListener(zoomCheckBox, 'change', update);
  1046. mxEvent.addListener(resizeCheckBox, 'change', update);
  1047. mxEvent.addListener(fitCheckBox, 'change', update);
  1048. mxEvent.addListener(editCheckBox, 'change', update);
  1049. mxEvent.addListener(editBlankCheckBox, 'change', update);
  1050. mxEvent.addListener(embedCheckBox, 'change', update);
  1051. mxEvent.addListener(heightInput, 'change', update);
  1052. mxEvent.addListener(topInput, 'change', update);
  1053. mxEvent.addListener(borderInput, 'change', update);
  1054. mxEvent.addListener(urlInput, 'change', update);
  1055. update();
  1056. mxEvent.addListener(gadgetInput, 'click', function()
  1057. {
  1058. gadgetInput.focus();
  1059. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  1060. {
  1061. gadgetInput.select();
  1062. }
  1063. else
  1064. {
  1065. document.execCommand('selectAll', false, null);
  1066. }
  1067. });
  1068. var buttons = document.createElement('div');
  1069. buttons.style.paddingTop = '12px';
  1070. buttons.style.textAlign = 'right';
  1071. var closeBtn = mxUtils.button(mxResources.get('close'), function()
  1072. {
  1073. editorUi.hideDialog();
  1074. });
  1075. closeBtn.className = 'geBtn gePrimaryBtn';
  1076. buttons.appendChild(closeBtn);
  1077. div.appendChild(buttons);
  1078. this.container = div;
  1079. };
  1080. /**
  1081. * Constructs a new parse dialog.
  1082. */
  1083. var CreateGraphDialog = function(editorUi, title, type)
  1084. {
  1085. var div = document.createElement('div');
  1086. div.style.textAlign = 'right';
  1087. this.init = function()
  1088. {
  1089. var container = document.createElement('div');
  1090. container.style.position = 'relative';
  1091. container.style.border = '1px solid gray';
  1092. container.style.width = '100%';
  1093. container.style.height = '360px';
  1094. container.style.overflow = 'hidden';
  1095. container.style.marginBottom = '16px';
  1096. mxEvent.disableContextMenu(container);
  1097. div.appendChild(container);
  1098. var graph = new Graph(container);
  1099. graph.setCellsCloneable(true);
  1100. graph.setPanning(true);
  1101. graph.setAllowDanglingEdges(false);
  1102. graph.connectionHandler.select = false;
  1103. graph.view.setTranslate(20, 20);
  1104. graph.border = 20;
  1105. graph.panningHandler.useLeftButtonForPanning = true;
  1106. var vertexStyle = 'rounded=1;';
  1107. var edgeStyle = 'curved=1;';
  1108. var startStyle = 'ellipse';
  1109. // FIXME: Does not work in iPad
  1110. var mxCellRendererInstallCellOverlayListeners = mxCellRenderer.prototype.installCellOverlayListeners;
  1111. graph.cellRenderer.installCellOverlayListeners = function(state, overlay, shape)
  1112. {
  1113. mxCellRenderer.prototype.installCellOverlayListeners.apply(this, arguments);
  1114. mxEvent.addListener(shape.node, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown', function (evt)
  1115. {
  1116. overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state));
  1117. });
  1118. if (!mxClient.IS_POINTER && mxClient.IS_TOUCH)
  1119. {
  1120. mxEvent.addListener(shape.node, 'touchstart', function (evt)
  1121. {
  1122. overlay.fireEvent(new mxEventObject('pointerdown', 'event', evt, 'state', state));
  1123. });
  1124. }
  1125. };
  1126. graph.getAllConnectionConstraints = function()
  1127. {
  1128. return null;
  1129. };
  1130. // Keeps highlight behind overlays
  1131. graph.connectionHandler.marker.highlight.keepOnTop = false;
  1132. graph.connectionHandler.createEdgeState = function(me)
  1133. {
  1134. var edge = graph.createEdge(null, null, null, null, null, edgeStyle);
  1135. return new mxCellState(this.graph.view, edge, this.graph.getCellStyle(edge));
  1136. };
  1137. // Gets the default parent for inserting new cells. This
  1138. // is normally the first child of the root (ie. layer 0).
  1139. var parent = graph.getDefaultParent();
  1140. var addOverlay = mxUtils.bind(this, function(cell)
  1141. {
  1142. // Creates a new overlay with an image and a tooltip
  1143. var overlay = new mxCellOverlay(this.connectImage, 'Add outgoing');
  1144. overlay.cursor = 'hand';
  1145. // Installs a handler for clicks on the overlay
  1146. overlay.addListener(mxEvent.CLICK, function(sender, evt2)
  1147. {
  1148. // TODO: Add menu for picking next shape
  1149. graph.connectionHandler.reset();
  1150. graph.clearSelection();
  1151. var geo = graph.getCellGeometry(cell);
  1152. var v2;
  1153. executeLayout(function()
  1154. {
  1155. v2 = graph.insertVertex(parent, null, 'Entry', geo.x, geo.y, 80, 30, vertexStyle);
  1156. addOverlay(v2);
  1157. graph.view.refresh(v2);
  1158. var e1 = graph.insertEdge(parent, null, '', cell, v2, edgeStyle);
  1159. }, function()
  1160. {
  1161. graph.scrollCellToVisible(v2);
  1162. });
  1163. });
  1164. // FIXME: Does not work in iPad (inserts loop)
  1165. overlay.addListener('pointerdown', function(sender, eo)
  1166. {
  1167. var evt2 = eo.getProperty('event');
  1168. var state = eo.getProperty('state');
  1169. graph.popupMenuHandler.hideMenu();
  1170. graph.stopEditing(false);
  1171. var pt = mxUtils.convertPoint(graph.container,
  1172. mxEvent.getClientX(evt2), mxEvent.getClientY(evt2));
  1173. graph.connectionHandler.start(state, pt.x, pt.y);
  1174. graph.isMouseDown = true;
  1175. graph.isMouseTrigger = mxEvent.isMouseEvent(evt2);
  1176. mxEvent.consume(evt2);
  1177. });
  1178. // Sets the overlay for the cell in the graph
  1179. graph.addCellOverlay(cell, overlay);
  1180. });
  1181. // Adds cells to the model in a single step
  1182. graph.getModel().beginUpdate();
  1183. var v1;
  1184. try
  1185. {
  1186. v1 = graph.insertVertex(parent, null, 'Start', 0, 0, 80, 30, startStyle);
  1187. addOverlay(v1);
  1188. }
  1189. finally
  1190. {
  1191. // Updates the display
  1192. graph.getModel().endUpdate();
  1193. }
  1194. var layout;
  1195. if (type == 'horizontalTree')
  1196. {
  1197. layout = new mxCompactTreeLayout(graph);
  1198. layout.edgeRouting = false;
  1199. layout.levelDistance = 30;
  1200. edgeStyle = 'edgeStyle=elbowEdgeStyle;elbow=horizontal;';
  1201. }
  1202. else if (type == 'verticalTree')
  1203. {
  1204. layout = new mxCompactTreeLayout(graph, false);
  1205. layout.edgeRouting = false;
  1206. layout.levelDistance = 30;
  1207. edgeStyle = 'edgeStyle=elbowEdgeStyle;elbow=vertical;';
  1208. }
  1209. else if (type == 'radialTree')
  1210. {
  1211. layout = new mxRadialTreeLayout(graph, false);
  1212. layout.edgeRouting = false;
  1213. layout.levelDistance = 80;
  1214. }
  1215. else if (type == 'verticalFlow')
  1216. {
  1217. layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_NORTH);
  1218. }
  1219. else if (type == 'horizontalFlow')
  1220. {
  1221. layout = new mxHierarchicalLayout(graph, mxConstants.DIRECTION_WEST);
  1222. }
  1223. else if (type == 'circle')
  1224. {
  1225. layout = new mxCircleLayout(graph);
  1226. }
  1227. else
  1228. {
  1229. layout = new mxFastOrganicLayout(graph, false);
  1230. layout.forceConstant = 80;
  1231. }
  1232. if (layout != null)
  1233. {
  1234. var executeLayout = function(change, post)
  1235. {
  1236. graph.getModel().beginUpdate();
  1237. try
  1238. {
  1239. if (change != null)
  1240. {
  1241. change();
  1242. }
  1243. layout.execute(graph.getDefaultParent(), v1);
  1244. }
  1245. catch (e)
  1246. {
  1247. throw e;
  1248. }
  1249. finally
  1250. {
  1251. // New API for animating graph layout results asynchronously
  1252. var morph = new mxMorphing(graph);
  1253. morph.addListener(mxEvent.DONE, mxUtils.bind(this, function()
  1254. {
  1255. graph.getModel().endUpdate();
  1256. if (post != null)
  1257. {
  1258. post();
  1259. }
  1260. }));
  1261. morph.startAnimation();
  1262. }
  1263. };
  1264. var edgeHandleConnect = mxEdgeHandler.prototype.connect;
  1265. mxEdgeHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
  1266. {
  1267. edgeHandleConnect.apply(this, arguments);
  1268. executeLayout();
  1269. };
  1270. graph.resizeCell = function()
  1271. {
  1272. mxGraph.prototype.resizeCell.apply(this, arguments);
  1273. executeLayout();
  1274. };
  1275. graph.connectionHandler.addListener(mxEvent.CONNECT, function()
  1276. {
  1277. executeLayout();
  1278. });
  1279. }
  1280. var cancelBtn = mxUtils.button(mxResources.get('close'), function()
  1281. {
  1282. editorUi.confirm(mxResources.get('areYouSure'), function()
  1283. {
  1284. if (container.parentNode != null)
  1285. {
  1286. graph.destroy();
  1287. container.parentNode.removeChild(container);
  1288. }
  1289. editorUi.hideDialog();
  1290. });
  1291. })
  1292. cancelBtn.className = 'geBtn';
  1293. if (editorUi.editor.cancelFirst)
  1294. {
  1295. div.appendChild(cancelBtn);
  1296. }
  1297. var okBtn = mxUtils.button(mxResources.get('insert'), function(evt)
  1298. {
  1299. graph.clearCellOverlays();
  1300. var cells = graph.getModel().getChildren(graph.getDefaultParent());
  1301. var pt = (mxEvent.isAltDown(evt)) ?
  1302. editorUi.editor.graph.getFreeInsertPoint() :
  1303. editorUi.editor.graph.getCenterInsertPoint(
  1304. graph.getBoundingBoxFromGeometry(cells, true));
  1305. cells = editorUi.editor.graph.importCells(cells, pt.x, pt.y);
  1306. var view = editorUi.editor.graph.view;
  1307. var temp = view.getBounds(cells);
  1308. temp.x -= view.translate.x;
  1309. temp.y -= view.translate.y;
  1310. editorUi.editor.graph.scrollRectToVisible(temp);
  1311. editorUi.editor.graph.setSelectionCells(cells);
  1312. if (container.parentNode != null)
  1313. {
  1314. graph.destroy();
  1315. container.parentNode.removeChild(container);
  1316. }
  1317. editorUi.hideDialog();
  1318. });
  1319. div.appendChild(okBtn);
  1320. okBtn.className = 'geBtn gePrimaryBtn';
  1321. if (!editorUi.editor.cancelFirst)
  1322. {
  1323. div.appendChild(cancelBtn);
  1324. }
  1325. };
  1326. this.container = div;
  1327. };
  1328. /**
  1329. *
  1330. */
  1331. CreateGraphDialog.prototype.connectImage = new mxImage((mxClient.IS_SVG) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RjQ3OTk0QjMyRDcyMTFFNThGQThGNDVBMjNBMjFDMzkiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RjQ3OTk0QjQyRDcyMTFFNThGQThGNDVBMjNBMjFDMzkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDoyRjA0N0I2MjJENzExMUU1OEZBOEY0NUEyM0EyMUMzOSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpGNDc5OTRCMjJENzIxMUU1OEZBOEY0NUEyM0EyMUMzOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PjIf+MgAAATlSURBVHjanFZraFxFFD735u4ru3ls0yZG26ShgmJoKK1J2vhIYzBgRdtIURHyw1hQUH9IxIgI2h8iCEUF/1RRlNQYCsYfCTHVhiTtNolpZCEStqSC22xIsrs1bDfu7t37Gs/cO3Ozxs1DBw73zpk555vzmHNGgJ0NYatFgmNLYUHYUoHASMz5ijmgVLmxgfKCUiBxC4ACJAeSG8nb1dVVOTc3dyoSibwWDofPBIPBJzo7O8vpGtvjpDICGztxkciECpF2LS0tvZtOpwNkk5FKpcYXFxffwL1+JuPgllPj8nk1F6RoaGjoKCqZ5ApljZDZO4SMRA0SuG2QUJIQRV8HxMOM9vf3H0ZZH9Nhg20MMl2QkFwjIyNHWlpahtADnuUMwLcRHX5aNSBjCJYEsSSLUeLEbhGe3ytCmQtA1/XY+Pj46dbW1iDuyCJp9BC5ycBj4hoeHq5ra2sbw0Xn1ZgBZ+dVkA1Lc+6p0Ck2p0QS4Ox9EhwpEylYcmBg4LH29vYQLilIOt0u5FhDfevNZDI/u93uw6PLOrwTUtjxrbPYbhD42WgMrF8JmR894ICmCgnQjVe8Xu8pXEkzMJKbuo5oNPomBbm1ZsD7s2kwFA1JZ6QBUXWT1nmGNc/qoMgavDcrQzxjQGFh4aOYIJ0sFAXcEtui4uLiVjr5KpSBVFYDDZVrWUaKRRWSAYeK0fmKykgDXbVoNaPChRuyqdDv97czL5nXxQbq6empQmsaklkDBiNpSwFVrmr2P6UyicD5piI4f8wHh0oEm8/p4h8pyGiEWvVQd3e3nxtjAzU1NR2jP7NRBWQ8GbdEzzJAmc0V3RR4cI8Dvmwuhc8fKUFA0d6/ltHg5p+Kuaejo6OeY0jcNJ/PV00ZS0nFUoZRvvFS1bZFsKHCCQ2Pl8H0chY+C96B6ZUsrCQ1qKtwQVFRURW/QhIXMAzDPAZ6BgOr8tTa8dDxCmiYGApaJbJMxSzV+brE8pdgWkcpY5dbMF1AR9XH8/xu2ilef48bvn92n82ZwHh+8ssqTEXS9p7dHisiiURikd8PbpExNTU1UVNTA3V3Y7lC16n0gpB/NwpNcZjfa7dScC4Qh0kOQCwnlEgi3F/hMVl9fX0zvKrzSk2lfXjRhj0eT/2rvWG4+Pta3oJY7XfC3hInXAv/ldeFLx8shQ+eqQL0UAAz7ylkpej5eNZRVBWL6BU6ef14OYiY1oqyTtmsavr/5koaRucT1pzx+ZpL1+GV5nLutksUgIcmtwTRiuuVZXnU5XId7A2swJkfFsymRWC91hHg1Viw6x23+7vn9sPJ+j20BE1hCXqSWaNSQ8ScbknRZWxub1PGCw/fBV+c3AeijlUbY5bBjEqr9GuYZP4jP41WudGSC6erTRCqdGZm5i1WvXWeDHnbBCZGc2Nj4wBl/hZOwrmBBfgmlID1HmGJutHaF+tKoevp/XCgstDkjo2NtWKLuc6AVN4mNjY+s1XQxoenOoFuDPHGtnRbJj9ej5GvL0dI7+giuRyMk1giazc+DP6vgUDgOJVlOv7R+PJ12QIeL6SyeDz+Kfp8ZrNWjgDTsVjsQ7qXyTjztXJhm9ePxFLfMTg4eG9tbe1RTP9KFFYQfHliYmIS69kCC7jKYmKwxxD5P88tkVkqbPPcIps9t4T/+HjcuJ/s5BFJgf4WYABCtxGuxIZ90gAAAABJRU5ErkJggg==' :
  1332. IMAGE_PATH + '/handle-connect.png', 26, 26);
  1333. /**
  1334. * Constructs a new parse dialog.
  1335. */
  1336. var BackgroundImageDialog = function(editorUi, applyFn, img, color, showColor)
  1337. {
  1338. var graph = editorUi.editor.graph;
  1339. var div = document.createElement('div');
  1340. div.style.whiteSpace = 'nowrap';
  1341. var h3 = document.createElement('h2');
  1342. mxUtils.write(h3, mxResources.get('background'));
  1343. h3.style.marginTop = '0px';
  1344. div.appendChild(h3);
  1345. var isPageLink = img != null && img.originalSrc != null;
  1346. var pageFound = false;
  1347. var urlRadio = document.createElement('input');
  1348. urlRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  1349. urlRadio.setAttribute('value', 'url');
  1350. urlRadio.setAttribute('type', 'radio');
  1351. urlRadio.setAttribute('name', 'geBackgroundImageDialogOption');
  1352. var pageRadio = document.createElement('input');
  1353. pageRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  1354. pageRadio.setAttribute('value', 'url');
  1355. pageRadio.setAttribute('type', 'radio');
  1356. pageRadio.setAttribute('name', 'geBackgroundImageDialogOption');
  1357. var urlInput = document.createElement('input');
  1358. urlInput.setAttribute('type', 'text');
  1359. urlInput.style.marginBottom = '8px';
  1360. urlInput.style.width = '360px';
  1361. urlInput.value = (isPageLink || img == null) ? '' : img.src;
  1362. var pageSelect = document.createElement('select');
  1363. pageSelect.style.width = '360px';
  1364. if (editorUi.pages != null)
  1365. {
  1366. for (var i = 0; i < editorUi.pages.length; i++)
  1367. {
  1368. var pageOption = document.createElement('option');
  1369. mxUtils.write(pageOption, editorUi.pages[i].getName() ||
  1370. mxResources.get('pageWithNumber', [i + 1]));
  1371. pageOption.setAttribute('value', 'data:page/id,' +
  1372. editorUi.pages[i].getId());
  1373. if (editorUi.pages[i] == editorUi.currentPage)
  1374. {
  1375. pageOption.setAttribute('disabled', 'disabled');
  1376. }
  1377. if (img != null && img.originalSrc == pageOption.getAttribute('value'))
  1378. {
  1379. pageOption.setAttribute('selected', 'selected');
  1380. pageFound = true;
  1381. }
  1382. pageSelect.appendChild(pageOption);
  1383. }
  1384. }
  1385. if (!isPageLink && (editorUi.pages == null || editorUi.pages.length == 1))
  1386. {
  1387. urlRadio.style.display = 'none';
  1388. pageRadio.style.display = 'none';
  1389. pageSelect.style.display = 'none';
  1390. }
  1391. var notFoundOption = document.createElement('option');
  1392. var resetting = false;
  1393. var ignoreEvt = false;
  1394. var urlChanged = function(evt, done)
  1395. {
  1396. // Skips blur event if called from apply button
  1397. if (!resetting && (evt == null || !ignoreEvt))
  1398. {
  1399. if (pageRadio.checked)
  1400. {
  1401. if (done != null)
  1402. {
  1403. done((notFoundOption.selected) ? null : pageSelect.value);
  1404. }
  1405. }
  1406. else if (urlInput.value != '' && !editorUi.isOffline())
  1407. {
  1408. urlInput.value = mxUtils.trim(urlInput.value);
  1409. editorUi.loadImage(urlInput.value, function(img)
  1410. {
  1411. widthInput.value = img.width;
  1412. heightInput.value = img.height;
  1413. if (done != null)
  1414. {
  1415. done(urlInput.value);
  1416. }
  1417. }, function()
  1418. {
  1419. editorUi.showError(mxResources.get('error'), mxResources.get('fileNotFound'), mxResources.get('ok'));
  1420. widthInput.value = '';
  1421. heightInput.value = '';
  1422. if (done != null)
  1423. {
  1424. done(null);
  1425. }
  1426. });
  1427. }
  1428. else
  1429. {
  1430. widthInput.value = '';
  1431. heightInput.value = '';
  1432. if (done != null)
  1433. {
  1434. done('');
  1435. }
  1436. }
  1437. }
  1438. };
  1439. var openFiles = mxUtils.bind(this, function(files)
  1440. {
  1441. editorUi.importFiles(files, 0, 0, editorUi.maxBackgroundSize, function(data, mimeType, x, y, w, h)
  1442. {
  1443. urlInput.value = data;
  1444. urlChanged();
  1445. urlInput.focus();
  1446. }, function()
  1447. {
  1448. // No post processing
  1449. }, function(file)
  1450. {
  1451. // Handles only images
  1452. return file.type.substring(0, 6) == 'image/';
  1453. }, function(queue)
  1454. {
  1455. // Invokes elements of queue in order
  1456. for (var i = 0; i < queue.length; i++)
  1457. {
  1458. queue[i]();
  1459. }
  1460. }, true, editorUi.maxBackgroundBytes, editorUi.maxBackgroundBytes, true);
  1461. });
  1462. this.init = function()
  1463. {
  1464. if (isPageLink)
  1465. {
  1466. pageSelect.focus();
  1467. }
  1468. else
  1469. {
  1470. urlInput.focus();
  1471. }
  1472. mxEvent.addListener(pageSelect, 'focus', function()
  1473. {
  1474. urlRadio.removeAttribute('checked');
  1475. pageRadio.setAttribute('checked', 'checked');
  1476. pageRadio.checked = true;
  1477. });
  1478. mxEvent.addListener(urlInput, 'focus', function()
  1479. {
  1480. pageRadio.removeAttribute('checked');
  1481. urlRadio.setAttribute('checked', 'checked');
  1482. urlRadio.checked = true;
  1483. });
  1484. // Installs drag and drop handler for local images and links
  1485. if (Graph.fileSupport)
  1486. {
  1487. urlInput.setAttribute('placeholder', mxResources.get('dragImagesHere'));
  1488. // Setup the dnd listeners
  1489. var dlg = div.parentNode;
  1490. var dropElt = null;
  1491. mxEvent.addListener(dlg, 'dragleave', function(evt)
  1492. {
  1493. if (dropElt != null)
  1494. {
  1495. dropElt.parentNode.removeChild(dropElt);
  1496. dropElt = null;
  1497. }
  1498. evt.stopPropagation();
  1499. evt.preventDefault();
  1500. });
  1501. mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
  1502. {
  1503. // IE 10 does not implement pointer-events so it can't have a drop highlight
  1504. if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10))
  1505. {
  1506. dropElt = editorUi.highlightElement(dlg);
  1507. }
  1508. evt.stopPropagation();
  1509. evt.preventDefault();
  1510. }));
  1511. mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
  1512. {
  1513. if (dropElt != null)
  1514. {
  1515. dropElt.parentNode.removeChild(dropElt);
  1516. dropElt = null;
  1517. }
  1518. if (evt.dataTransfer.files.length > 0)
  1519. {
  1520. openFiles(evt.dataTransfer.files);
  1521. }
  1522. else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
  1523. {
  1524. var uri = evt.dataTransfer.getData('text/uri-list');
  1525. if ((/\.(gif|jpg|jpeg|tiff|png|svg)$/i).test(uri))
  1526. {
  1527. urlInput.value = decodeURIComponent(uri);
  1528. urlChanged();
  1529. }
  1530. }
  1531. evt.stopPropagation();
  1532. evt.preventDefault();
  1533. }), false);
  1534. }
  1535. };
  1536. div.appendChild(urlRadio);
  1537. div.appendChild(urlInput);
  1538. mxUtils.br(div);
  1539. var span = document.createElement('span');
  1540. span.style.marginLeft = '30px';
  1541. mxUtils.write(span, mxResources.get('width') + ':');
  1542. div.appendChild(span);
  1543. var widthInput = document.createElement('input');
  1544. widthInput.setAttribute('type', 'text');
  1545. widthInput.style.width = '60px';
  1546. widthInput.style.marginLeft = '8px';
  1547. widthInput.style.marginRight = '16px';
  1548. widthInput.value = (img != null && !isPageLink) ? img.width : '';
  1549. div.appendChild(widthInput);
  1550. mxUtils.write(div, mxResources.get('height') + ':');
  1551. var heightInput = document.createElement('input');
  1552. heightInput.setAttribute('type', 'text');
  1553. heightInput.style.width = '60px';
  1554. heightInput.style.marginLeft = '8px';
  1555. heightInput.style.marginRight = '16px';
  1556. heightInput.value = (img != null && !isPageLink) ? img.height : '';
  1557. div.appendChild(heightInput);
  1558. mxUtils.br(div);
  1559. mxUtils.br(div);
  1560. mxEvent.addListener(urlInput, 'change', urlChanged);
  1561. ImageDialog.filePicked = function(data)
  1562. {
  1563. if (data.action == google.picker.Action.PICKED)
  1564. {
  1565. if (data.docs[0].thumbnails != null)
  1566. {
  1567. var thumb = data.docs[0].thumbnails[data.docs[0].thumbnails.length - 1];
  1568. if (thumb != null)
  1569. {
  1570. urlInput.value = thumb.url;
  1571. urlChanged();
  1572. }
  1573. }
  1574. }
  1575. urlInput.focus();
  1576. };
  1577. div.appendChild(pageRadio);
  1578. div.appendChild(pageSelect);
  1579. mxUtils.br(div);
  1580. mxUtils.br(div);
  1581. if (isPageLink)
  1582. {
  1583. pageRadio.setAttribute('checked', 'checked');
  1584. pageRadio.checked = true;
  1585. }
  1586. else
  1587. {
  1588. urlRadio.setAttribute('checked', 'checked');
  1589. urlRadio.checked = true;
  1590. }
  1591. if (!pageFound && pageRadio.checked)
  1592. {
  1593. mxUtils.write(notFoundOption, mxResources.get('pageNotFound'));
  1594. notFoundOption.setAttribute('disabled', 'disabled');
  1595. notFoundOption.setAttribute('selected', 'selected');
  1596. notFoundOption.setAttribute('value', 'pageNotFound');
  1597. pageSelect.appendChild(notFoundOption);
  1598. mxEvent.addListener(pageSelect, 'change', function()
  1599. {
  1600. if (notFoundOption.parentNode != null && !notFoundOption.selected)
  1601. {
  1602. notFoundOption.parentNode.removeChild(notFoundOption);
  1603. }
  1604. });
  1605. }
  1606. var bgDiv = document.createElement('div');
  1607. bgDiv.style.display = (showColor) ? 'inline-flex' : 'none';
  1608. bgDiv.style.alignItems = 'center';
  1609. bgDiv.style.cursor = 'default';
  1610. bgDiv.style.minWidth = '40%';
  1611. bgDiv.style.height = '20px';
  1612. var cb = document.createElement('input');
  1613. cb.setAttribute('type', 'checkbox');
  1614. cb.style.margin = '0px 10px 0px 4px';
  1615. cb.style.verticalAlign = 'bottom';
  1616. cb.defaultChecked = color != mxConstants.NONE && color != null;
  1617. cb.checked = cb.defaultChecked;
  1618. bgDiv.appendChild(cb);
  1619. mxUtils.write(bgDiv, mxResources.get('fillColor'));
  1620. var shadowDiv = bgDiv.cloneNode(false);
  1621. var shadow = document.createElement('input');
  1622. shadow.setAttribute('type', 'checkbox');
  1623. shadow.style.margin = '0px 10px 0px 30px';
  1624. shadow.style.verticalAlign = 'bottom';
  1625. shadow.defaultChecked = graph.shadowVisible;
  1626. shadow.checked = shadow.defaultChecked;
  1627. shadowDiv.appendChild(shadow);
  1628. mxUtils.write(shadowDiv, mxResources.get('shadow'));
  1629. if (!mxClient.IS_SVG || mxClient.IS_SF)
  1630. {
  1631. shadow.setAttribute('disabled', 'disabled');
  1632. }
  1633. mxEvent.addListener(shadowDiv, 'click', function(evt)
  1634. {
  1635. if (mxEvent.getSource(evt) != shadow)
  1636. {
  1637. shadow.checked = !shadow.checked;
  1638. }
  1639. });
  1640. // TODO: Move createColorButton to editorUi
  1641. var backgroundButton = document.createElement('button');
  1642. backgroundButton.style.width = '36px';
  1643. backgroundButton.style.height = '18px';
  1644. backgroundButton.style.cursor = 'pointer';
  1645. backgroundButton.style.marginLeft = '10px';
  1646. backgroundButton.style.backgroundPosition = 'center center';
  1647. backgroundButton.style.backgroundRepeat = 'no-repeat';
  1648. backgroundButton.style.verticalAlign = 'bottom';
  1649. backgroundButton.className = 'geColorBtn';
  1650. var newBackgroundColor = color;
  1651. function updateBackgroundColor()
  1652. {
  1653. if (newBackgroundColor == null || newBackgroundColor == mxConstants.NONE)
  1654. {
  1655. backgroundButton.style.display = 'none';
  1656. cb.checked = false;
  1657. }
  1658. else
  1659. {
  1660. backgroundButton.style.backgroundColor = newBackgroundColor;
  1661. backgroundButton.style.display = '';
  1662. cb.checked = true;
  1663. }
  1664. };
  1665. updateBackgroundColor();
  1666. mxEvent.addListener(bgDiv, 'click', function(evt)
  1667. {
  1668. if (mxEvent.getSource(evt) != cb)
  1669. {
  1670. cb.checked = !cb.checked;
  1671. }
  1672. if (cb.checked)
  1673. {
  1674. newBackgroundColor = '#ffffff';
  1675. }
  1676. else
  1677. {
  1678. newBackgroundColor = null;
  1679. }
  1680. updateBackgroundColor();
  1681. });
  1682. mxEvent.addListener(backgroundButton, 'click', function(evt)
  1683. {
  1684. editorUi.pickColor(newBackgroundColor || 'none', function(color)
  1685. {
  1686. newBackgroundColor = color;
  1687. updateBackgroundColor();
  1688. });
  1689. mxEvent.consume(evt);
  1690. });
  1691. bgDiv.appendChild(backgroundButton);
  1692. div.appendChild(bgDiv);
  1693. div.appendChild(shadowDiv);
  1694. mxUtils.br(div);
  1695. var btns = document.createElement('div');
  1696. btns.style.marginTop = '30px';
  1697. btns.style.textAlign = 'right';
  1698. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  1699. {
  1700. resetting = true;
  1701. editorUi.hideDialog();
  1702. });
  1703. cancelBtn.className = 'geBtn';
  1704. if (editorUi.editor.cancelFirst)
  1705. {
  1706. btns.appendChild(cancelBtn);
  1707. }
  1708. var resetBtn = mxUtils.button(mxResources.get('reset'), function()
  1709. {
  1710. urlInput.value = '';
  1711. widthInput.value = '';
  1712. heightInput.value = '';
  1713. urlRadio.checked = true;
  1714. newBackgroundColor = mxConstants.NONE;
  1715. updateBackgroundColor();
  1716. resetting = false;
  1717. });
  1718. mxEvent.addGestureListeners(resetBtn, function()
  1719. {
  1720. // Blocks processing a image URL while clicking reset
  1721. resetting = true;
  1722. });
  1723. resetBtn.className = 'geBtn';
  1724. resetBtn.width = '100';
  1725. btns.appendChild(resetBtn);
  1726. if (Graph.fileSupport)
  1727. {
  1728. var fileInput = document.createElement('input');
  1729. fileInput.setAttribute('multiple', 'multiple');
  1730. fileInput.setAttribute('type', 'file');
  1731. mxEvent.addListener(fileInput, 'change', function(evt)
  1732. {
  1733. if (fileInput.files != null)
  1734. {
  1735. openFiles(fileInput.files);
  1736. // Resets input to force change event for same file (type reset required for IE)
  1737. fileInput.type = '';
  1738. fileInput.type = 'file';
  1739. fileInput.value = '';
  1740. }
  1741. });
  1742. fileInput.style.display = 'none';
  1743. div.appendChild(fileInput);
  1744. var btn = mxUtils.button(mxResources.get('open'), function()
  1745. {
  1746. fileInput.click();
  1747. });
  1748. btn.className = 'geBtn';
  1749. btns.appendChild(btn);
  1750. }
  1751. applyBtn = mxUtils.button(mxResources.get('apply'), function()
  1752. {
  1753. editorUi.hideDialog();
  1754. urlChanged(null, function(url)
  1755. {
  1756. applyFn((url != '' && url != null) ? new mxImage(url, widthInput.value,
  1757. heightInput.value) : null, url == null, newBackgroundColor,
  1758. (!mxClient.IS_SVG || mxClient.IS_SF) ? null : shadow.checked);
  1759. });
  1760. });
  1761. mxEvent.addGestureListeners(applyBtn, function()
  1762. {
  1763. ignoreEvt = true;
  1764. });
  1765. applyBtn.className = 'geBtn gePrimaryBtn';
  1766. btns.appendChild(applyBtn);
  1767. if (!editorUi.editor.cancelFirst)
  1768. {
  1769. btns.appendChild(cancelBtn);
  1770. }
  1771. div.appendChild(btns);
  1772. this.container = div;
  1773. };
  1774. /**
  1775. * Constructs a new parse dialog.
  1776. */
  1777. var ParseDialog = function(editorUi, title, defaultType)
  1778. {
  1779. var plantUmlExample = '@startuml\nskinparam shadowing false\nAlice -> Bob: Authentication Request\nBob --> Alice: Authentication Response\n\n' +
  1780. 'Alice -> Bob: Another authentication Request\nAlice <-- Bob: Another authentication Response\n@enduml';
  1781. var insertPoint = editorUi.editor.graph.getFreeInsertPoint();
  1782. function parse(text, type, evt)
  1783. {
  1784. var lines = text.split('\n');
  1785. if (type == 'plantUmlPng' || type == 'plantUmlSvg' || type == 'plantUmlTxt')
  1786. {
  1787. if (editorUi.spinner.spin(document.body, mxResources.get('inserting')))
  1788. {
  1789. var graph = editorUi.editor.graph;
  1790. var format = (type == 'plantUmlTxt') ? 'txt' :
  1791. ((type == 'plantUmlPng') ? 'png' : 'svg');
  1792. function insertPlantUmlImage(text, format, data, w, h)
  1793. {
  1794. insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : graph.getCenterInsertPoint(new mxRectangle(0, 0, w, h));
  1795. var cell = null;
  1796. graph.getModel().beginUpdate();
  1797. try
  1798. {
  1799. cell = (format == 'txt') ?
  1800. editorUi.insertAsPreText(data, insertPoint.x, insertPoint.y) :
  1801. graph.insertVertex(null, null, null, insertPoint.x, insertPoint.y,
  1802. w, h, 'shape=image;noLabel=1;verticalAlign=top;aspect=fixed;imageAspect=0;' +
  1803. 'image=' + editorUi.convertDataUri(data) + ';')
  1804. graph.setAttributeForCell(cell, 'plantUmlData',
  1805. JSON.stringify({data: text, format: format},
  1806. null, 2));
  1807. }
  1808. finally
  1809. {
  1810. graph.getModel().endUpdate();
  1811. }
  1812. if (cell != null)
  1813. {
  1814. graph.setSelectionCell(cell);
  1815. graph.scrollCellToVisible(cell);
  1816. }
  1817. };
  1818. // Hardcoded response for default settings
  1819. if (text == plantUmlExample && format == 'svg')
  1820. {
  1821. window.setTimeout(function()
  1822. {
  1823. editorUi.spinner.stop();
  1824. insertPlantUmlImage(text, format, 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiBjb250ZW50U2NyaXB0VHlwZT0iYXBwbGljYXRpb24vZWNtYXNjcmlwdCIgY29udGVudFN0eWxlVHlwZT0idGV4dC9jc3MiIGhlaWdodD0iMjEycHgiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiIHN0eWxlPSJ3aWR0aDoyOTVweDtoZWlnaHQ6MjEycHg7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAyOTUgMjEyIiB3aWR0aD0iMjk1cHgiIHpvb21BbmRQYW49Im1hZ25pZnkiPjxkZWZzLz48Zz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsgc3Ryb2tlLWRhc2hhcnJheTogNS4wLDUuMDsiIHgxPSIzMSIgeDI9IjMxIiB5MT0iMzQuNDg4MyIgeTI9IjE3MS43MzA1Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7IHN0cm9rZS1kYXNoYXJyYXk6IDUuMCw1LjA7IiB4MT0iMjY0LjUiIHgyPSIyNjQuNSIgeTE9IjM0LjQ4ODMiIHkyPSIxNzEuNzMwNSIvPjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGhlaWdodD0iMzAuNDg4MyIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjU7IiB3aWR0aD0iNDciIHg9IjgiIHk9IjMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIzMyIgeD0iMTUiIHk9IjIzLjUzNTIiPkFsaWNlPC90ZXh0PjxyZWN0IGZpbGw9IiNGRUZFQ0UiIGhlaWdodD0iMzAuNDg4MyIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjU7IiB3aWR0aD0iNDciIHg9IjgiIHk9IjE3MC43MzA1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTQiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMzMiIHg9IjE1IiB5PSIxOTEuMjY1NiI+QWxpY2U8L3RleHQ+PHJlY3QgZmlsbD0iI0ZFRkVDRSIgaGVpZ2h0PSIzMC40ODgzIiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuNTsiIHdpZHRoPSI0MCIgeD0iMjQ0LjUiIHk9IjMiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIyNiIgeD0iMjUxLjUiIHk9IjIzLjUzNTIiPkJvYjwvdGV4dD48cmVjdCBmaWxsPSIjRkVGRUNFIiBoZWlnaHQ9IjMwLjQ4ODMiIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS41OyIgd2lkdGg9IjQwIiB4PSIyNDQuNSIgeT0iMTcwLjczMDUiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIyNiIgeD0iMjUxLjUiIHk9IjE5MS4yNjU2Ij5Cb2I8L3RleHQ+PHBvbHlnb24gZmlsbD0iI0E4MDAzNiIgcG9pbnRzPSIyNTIuNSw2MS43OTg4LDI2Mi41LDY1Ljc5ODgsMjUyLjUsNjkuNzk4OCwyNTYuNSw2NS43OTg4IiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiIHgxPSIzMS41IiB4Mj0iMjU4LjUiIHkxPSI2NS43OTg4IiB5Mj0iNjUuNzk4OCIvPjx0ZXh0IGZpbGw9IiMwMDAwMDAiIGZvbnQtZmFtaWx5PSJzYW5zLXNlcmlmIiBmb250LXNpemU9IjEzIiBsZW5ndGhBZGp1c3Q9InNwYWNpbmdBbmRHbHlwaHMiIHRleHRMZW5ndGg9IjE0NyIgeD0iMzguNSIgeT0iNjEuMDU2NiI+QXV0aGVudGljYXRpb24gUmVxdWVzdDwvdGV4dD48cG9seWdvbiBmaWxsPSIjQTgwMDM2IiBwb2ludHM9IjQyLjUsOTEuMTA5NCwzMi41LDk1LjEwOTQsNDIuNSw5OS4xMDk0LDM4LjUsOTUuMTA5NCIgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7Ii8+PGxpbmUgc3R5bGU9InN0cm9rZTogI0E4MDAzNjsgc3Ryb2tlLXdpZHRoOiAxLjA7IHN0cm9rZS1kYXNoYXJyYXk6IDIuMCwyLjA7IiB4MT0iMzYuNSIgeDI9IjI2My41IiB5MT0iOTUuMTA5NCIgeTI9Ijk1LjEwOTQiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIxNTciIHg9IjQ4LjUiIHk9IjkwLjM2NzIiPkF1dGhlbnRpY2F0aW9uIFJlc3BvbnNlPC90ZXh0Pjxwb2x5Z29uIGZpbGw9IiNBODAwMzYiIHBvaW50cz0iMjUyLjUsMTIwLjQxOTksMjYyLjUsMTI0LjQxOTksMjUyLjUsMTI4LjQxOTksMjU2LjUsMTI0LjQxOTkiIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS4wOyIvPjxsaW5lIHN0eWxlPSJzdHJva2U6ICNBODAwMzY7IHN0cm9rZS13aWR0aDogMS4wOyIgeDE9IjMxLjUiIHgyPSIyNTguNSIgeTE9IjEyNC40MTk5IiB5Mj0iMTI0LjQxOTkiLz48dGV4dCBmaWxsPSIjMDAwMDAwIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxMyIgbGVuZ3RoQWRqdXN0PSJzcGFjaW5nQW5kR2x5cGhzIiB0ZXh0TGVuZ3RoPSIxOTkiIHg9IjM4LjUiIHk9IjExOS42Nzc3Ij5Bbm90aGVyIGF1dGhlbnRpY2F0aW9uIFJlcXVlc3Q8L3RleHQ+PHBvbHlnb24gZmlsbD0iI0E4MDAzNiIgcG9pbnRzPSI0Mi41LDE0OS43MzA1LDMyLjUsMTUzLjczMDUsNDIuNSwxNTcuNzMwNSwzOC41LDE1My43MzA1IiBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsiLz48bGluZSBzdHlsZT0ic3Ryb2tlOiAjQTgwMDM2OyBzdHJva2Utd2lkdGg6IDEuMDsgc3Ryb2tlLWRhc2hhcnJheTogMi4wLDIuMDsiIHgxPSIzNi41IiB4Mj0iMjYzLjUiIHkxPSIxNTMuNzMwNSIgeTI9IjE1My43MzA1Ii8+PHRleHQgZmlsbD0iIzAwMDAwMCIgZm9udC1mYW1pbHk9InNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMTMiIGxlbmd0aEFkanVzdD0ic3BhY2luZ0FuZEdseXBocyIgdGV4dExlbmd0aD0iMjA5IiB4PSI0OC41IiB5PSIxNDguOTg4MyI+QW5vdGhlciBhdXRoZW50aWNhdGlvbiBSZXNwb25zZTwvdGV4dD48IS0tTUQ1PVs3ZjNlNGQwYzkwMWVmZGJjNTdlYjQ0MjQ5YTNiODE5N10KQHN0YXJ0dW1sDQpza2lucGFyYW0gc2hhZG93aW5nIGZhbHNlDQpBbGljZSAtPiBCb2I6IEF1dGhlbnRpY2F0aW9uIFJlcXVlc3QNCkJvYiAtIC0+IEFsaWNlOiBBdXRoZW50aWNhdGlvbiBSZXNwb25zZQ0KDQpBbGljZSAtPiBCb2I6IEFub3RoZXIgYXV0aGVudGljYXRpb24gUmVxdWVzdA0KQWxpY2UgPC0gLSBCb2I6IEFub3RoZXIgYXV0aGVudGljYXRpb24gUmVzcG9uc2UNCkBlbmR1bWwNCgpQbGFudFVNTCB2ZXJzaW9uIDEuMjAyMC4wMihTdW4gTWFyIDAxIDA0OjIyOjA3IENTVCAyMDIwKQooTUlUIHNvdXJjZSBkaXN0cmlidXRpb24pCkphdmEgUnVudGltZTogT3BlbkpESyBSdW50aW1lIEVudmlyb25tZW50CkpWTTogT3BlbkpESyA2NC1CaXQgU2VydmVyIFZNCkphdmEgVmVyc2lvbjogMTIrMzMKT3BlcmF0aW5nIFN5c3RlbTogTWFjIE9TIFgKRGVmYXVsdCBFbmNvZGluZzogVVRGLTgKTGFuZ3VhZ2U6IGVuCkNvdW50cnk6IFVTCi0tPjwvZz48L3N2Zz4=',
  1825. 295, 212);
  1826. }, 200);
  1827. }
  1828. else
  1829. {
  1830. editorUi.generatePlantUmlImage(text, format, function(data, w, h)
  1831. {
  1832. editorUi.spinner.stop();
  1833. insertPlantUmlImage(text, format, data, w, h);
  1834. }, function(e)
  1835. {
  1836. editorUi.handleError(e);
  1837. });
  1838. }
  1839. }
  1840. }
  1841. else if (type == 'mermaid')
  1842. {
  1843. if (editorUi.spinner.spin(document.body, mxResources.get('inserting')))
  1844. {
  1845. var graph = editorUi.editor.graph;
  1846. editorUi.generateMermaidImage(text, null, function(data, w, h)
  1847. {
  1848. insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint : graph.getCenterInsertPoint(new mxRectangle(0, 0, w, h));
  1849. editorUi.spinner.stop();
  1850. var cell = null;
  1851. graph.getModel().beginUpdate();
  1852. try
  1853. {
  1854. cell = graph.insertVertex(null, null, null, insertPoint.x, insertPoint.y,
  1855. w, h, 'shape=image;noLabel=1;verticalAlign=top;imageAspect=1;' +
  1856. 'image=' + data + ';')
  1857. graph.setAttributeForCell(cell, 'mermaidData',
  1858. JSON.stringify({data: text, config:
  1859. EditorUi.defaultMermaidConfig}, null, 2));
  1860. }
  1861. finally
  1862. {
  1863. graph.getModel().endUpdate();
  1864. }
  1865. if (cell != null)
  1866. {
  1867. graph.setSelectionCell(cell);
  1868. graph.scrollCellToVisible(cell);
  1869. }
  1870. }, function(e)
  1871. {
  1872. editorUi.handleError(e);
  1873. });
  1874. }
  1875. }
  1876. else if (type == 'table')
  1877. {
  1878. var tableCell = null;
  1879. var cells = [];
  1880. var dx = 0;
  1881. var pkMap = {};
  1882. //First pass to find primary keys
  1883. for (var i = 0; i < lines.length; i++)
  1884. {
  1885. var line = mxUtils.trim(lines[i]);
  1886. if (line.substring(0, 11).toLowerCase() == 'primary key')
  1887. {
  1888. var pk = line.match(/\((.+)\)/);
  1889. if (pk && pk[1])
  1890. {
  1891. pkMap[pk[1]] = true;
  1892. }
  1893. lines.splice(i, 1);
  1894. }
  1895. else if (line.toLowerCase().indexOf('primary key') > 0)
  1896. {
  1897. pkMap[line.split(' ')[0]] = true;
  1898. lines[i] = mxUtils.trim(line.replace(/primary key/i, ''));
  1899. }
  1900. }
  1901. for (var i = 0; i < lines.length; i++)
  1902. {
  1903. var tmp = mxUtils.trim(lines[i]);
  1904. if (tmp.substring(0, 12).toLowerCase() == 'create table')
  1905. {
  1906. var name = mxUtils.trim(tmp.substring(12));
  1907. if (name.charAt(name.length - 1) == '(')
  1908. {
  1909. name = mxUtils.trim(name.substring(0, name.length - 1));
  1910. }
  1911. tableCell = new mxCell(name, new mxGeometry(dx, 0, 160, 30),
  1912. 'shape=table;startSize=30;container=1;collapsible=1;childLayout=tableLayout;' +
  1913. 'fixedRows=1;rowLines=0;fontStyle=1;align=center;resizeLast=1;');
  1914. tableCell.vertex = true;
  1915. cells.push(tableCell);
  1916. var size = editorUi.editor.graph.getPreferredSizeForCell(rowCell);
  1917. if (size != null)
  1918. {
  1919. tableCell.geometry.width = size.width + 10;
  1920. }
  1921. }
  1922. else if (tableCell != null && tmp.charAt(0) == ')')
  1923. {
  1924. dx += tableCell.geometry.width + 40;
  1925. tableCell = null;
  1926. }
  1927. else if (tmp != '(' && tableCell != null)
  1928. {
  1929. var name = tmp.substring(0, (tmp.charAt(tmp.length - 1) == ',') ? tmp.length - 1 : tmp.length);
  1930. var pk = pkMap[name.split(' ')[0]];
  1931. var rowCell = new mxCell('', new mxGeometry(0, 0, 160, 30),
  1932. 'shape=tableRow;horizontal=0;startSize=0;swimlaneHead=0;swimlaneBody=0;fillColor=none;' +
  1933. 'collapsible=0;dropTarget=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;' +
  1934. 'strokeColor=inherit;top=0;left=0;right=0;bottom=' + (pk ? '1' : '0') + ';');
  1935. rowCell.vertex = true;
  1936. var left = new mxCell(pk ? 'PK' : '', new mxGeometry(0, 0, 30, 30),
  1937. 'shape=partialRectangle;overflow=hidden;connectable=0;fillColor=none;' +
  1938. 'strokeColor=inherit;top=0;left=0;bottom=0;right=0;' +
  1939. (pk ? 'fontStyle=1;' : ''));
  1940. left.vertex = true;
  1941. rowCell.insert(left);
  1942. var right = new mxCell(name, new mxGeometry(30, 0, 130, 30),
  1943. 'shape=partialRectangle;overflow=hidden;connectable=0;fillColor=none;align=left;' +
  1944. 'strokeColor=inherit;top=0;left=0;bottom=0;right=0;spacingLeft=6;' +
  1945. (pk ? 'fontStyle=5;' : ''));
  1946. right.vertex = true;
  1947. rowCell.insert(right);
  1948. var size = editorUi.editor.graph.getPreferredSizeForCell(right);
  1949. if (size != null && tableCell.geometry.width < size.width + 30)
  1950. {
  1951. tableCell.geometry.width = Math.min(320, Math.max(tableCell.geometry.width, size.width + 30));
  1952. }
  1953. tableCell.insert(rowCell, pk? 0 : null);
  1954. tableCell.geometry.height += 30;
  1955. }
  1956. }
  1957. if (cells.length > 0)
  1958. {
  1959. var graph = editorUi.editor.graph;
  1960. insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint :
  1961. graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true));
  1962. graph.setSelectionCells(graph.importCells(cells, insertPoint.x, insertPoint.y));
  1963. graph.scrollCellToVisible(graph.getSelectionCell());
  1964. }
  1965. }
  1966. else if (type == 'list')
  1967. {
  1968. if (lines.length > 0)
  1969. {
  1970. var graph = editorUi.editor.graph;
  1971. var listCell = null;
  1972. var cells = [];
  1973. var x0 = 0;
  1974. for (var i = 0; i < lines.length; i++)
  1975. {
  1976. if (lines[i].charAt(0) != ';')
  1977. {
  1978. if (lines[i].length == 0)
  1979. {
  1980. listCell = null;
  1981. }
  1982. else
  1983. {
  1984. if (listCell == null)
  1985. {
  1986. listCell = new mxCell(lines[i], new mxGeometry(x0, 0, 160, 26 + 4),
  1987. 'swimlane;fontStyle=1;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;');
  1988. listCell.vertex = true;
  1989. cells.push(listCell);
  1990. var size = graph.getPreferredSizeForCell(listCell);
  1991. if (size != null && listCell.geometry.width < size.width + 10)
  1992. {
  1993. listCell.geometry.width = size.width + 10;
  1994. }
  1995. x0 += listCell.geometry.width + 40;
  1996. }
  1997. else if (lines[i] == '--')
  1998. {
  1999. var divider = new mxCell('', new mxGeometry(0, 0, 40, 8), 'line;strokeWidth=1;fillColor=none;align=left;verticalAlign=middle;spacingTop=-1;spacingLeft=3;spacingRight=3;rotatable=0;labelPosition=right;points=[];portConstraint=eastwest;');
  2000. divider.vertex = true;
  2001. listCell.geometry.height += divider.geometry.height;
  2002. listCell.insert(divider);
  2003. }
  2004. else if (lines[i].length > 0)
  2005. {
  2006. var field = new mxCell(lines[i], new mxGeometry(0, 0, 60, 26), 'text;strokeColor=none;fillColor=none;align=left;verticalAlign=top;spacingLeft=4;spacingRight=4;overflow=hidden;rotatable=0;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;');
  2007. field.vertex = true;
  2008. var size = graph.getPreferredSizeForCell(field);
  2009. if (size != null && field.geometry.width < size.width)
  2010. {
  2011. field.geometry.width = size.width;
  2012. }
  2013. listCell.geometry.width = Math.max(listCell.geometry.width, field.geometry.width);
  2014. listCell.geometry.height += field.geometry.height;
  2015. listCell.insert(field);
  2016. }
  2017. }
  2018. }
  2019. }
  2020. if (cells.length > 0)
  2021. {
  2022. insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint :
  2023. graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true));
  2024. graph.getModel().beginUpdate();
  2025. try
  2026. {
  2027. cells = graph.importCells(cells, insertPoint.x, insertPoint.y);
  2028. var inserted = [];
  2029. for (var i = 0; i < cells.length; i++)
  2030. {
  2031. inserted.push(cells[i]);
  2032. inserted = inserted.concat(cells[i].children);
  2033. }
  2034. graph.fireEvent(new mxEventObject('cellsInserted', 'cells', inserted));
  2035. }
  2036. finally
  2037. {
  2038. graph.getModel().endUpdate();
  2039. }
  2040. graph.setSelectionCells(cells);
  2041. graph.scrollCellToVisible(graph.getSelectionCell());
  2042. }
  2043. }
  2044. }
  2045. else
  2046. {
  2047. var vertices = new Object();
  2048. var cells = [];
  2049. function getOrCreateVertex(id)
  2050. {
  2051. var vertex = vertices[id];
  2052. if (vertex == null)
  2053. {
  2054. vertex = new mxCell(id, new mxGeometry(0, 0, 80, 30), 'whiteSpace=wrap;html=1;');
  2055. vertex.vertex = true;
  2056. vertices[id] = vertex;
  2057. cells.push(vertex);
  2058. }
  2059. return vertex;
  2060. };
  2061. for (var i = 0; i < lines.length; i++)
  2062. {
  2063. if (lines[i].charAt(0) != ';')
  2064. {
  2065. var values = lines[i].split('->');
  2066. if (values.length >= 2)
  2067. {
  2068. var source = getOrCreateVertex(values[0]);
  2069. var target = getOrCreateVertex(values[values.length - 1]);
  2070. var edge = new mxCell((values.length > 2) ? values[1] : '', new mxGeometry());
  2071. edge.edge = true;
  2072. source.insertEdge(edge, true);
  2073. target.insertEdge(edge, false);
  2074. cells.push(edge);
  2075. }
  2076. }
  2077. }
  2078. if (cells.length > 0)
  2079. {
  2080. var container = document.createElement('div');
  2081. container.style.visibility = 'hidden';
  2082. document.body.appendChild(container);
  2083. // Temporary graph for running the layout
  2084. var graph = new Graph(container);
  2085. graph.getModel().beginUpdate();
  2086. try
  2087. {
  2088. cells = graph.importCells(cells);
  2089. for (var i = 0; i < cells.length; i++)
  2090. {
  2091. if (graph.getModel().isVertex(cells[i]))
  2092. {
  2093. var size = graph.getPreferredSizeForCell(cells[i]);
  2094. cells[i].geometry.width = Math.max(cells[i].geometry.width, size.width);
  2095. cells[i].geometry.height = Math.max(cells[i].geometry.height, size.height);
  2096. }
  2097. }
  2098. var runEdgeLayout = true;
  2099. if (type == 'horizontalFlow' || type == 'verticalFlow')
  2100. {
  2101. var flowLayout = new mxHierarchicalLayout(graph,
  2102. (type == 'horizontalFlow') ?
  2103. mxConstants.DIRECTION_WEST :
  2104. mxConstants.DIRECTION_NORTH);
  2105. flowLayout.execute(graph.getDefaultParent(), cells);
  2106. runEdgeLayout = false;
  2107. }
  2108. else if (type == 'circle')
  2109. {
  2110. var circleLayout = new mxCircleLayout(graph);
  2111. circleLayout.execute(graph.getDefaultParent());
  2112. }
  2113. else
  2114. {
  2115. var layout = new mxFastOrganicLayout(graph);
  2116. layout.disableEdgeStyle = false;
  2117. layout.forceConstant = 180;
  2118. layout.execute(graph.getDefaultParent());
  2119. }
  2120. if (runEdgeLayout)
  2121. {
  2122. var edgeLayout = new mxParallelEdgeLayout(graph);
  2123. edgeLayout.spacing = 30;
  2124. edgeLayout.execute(graph.getDefaultParent());
  2125. }
  2126. }
  2127. finally
  2128. {
  2129. graph.getModel().endUpdate();
  2130. }
  2131. graph.clearCellOverlays();
  2132. // Copy to actual graph
  2133. var inserted = [];
  2134. editorUi.editor.graph.getModel().beginUpdate();
  2135. try
  2136. {
  2137. cells = graph.getModel().getChildren(graph.getDefaultParent());
  2138. insertPoint = (mxEvent.isAltDown(evt)) ? insertPoint :
  2139. editorUi.editor.graph.getCenterInsertPoint(graph.getBoundingBoxFromGeometry(cells, true));
  2140. inserted = editorUi.editor.graph.importCells(cells, insertPoint.x, insertPoint.y)
  2141. editorUi.editor.graph.fireEvent(new mxEventObject('cellsInserted', 'cells', inserted));
  2142. }
  2143. finally
  2144. {
  2145. editorUi.editor.graph.getModel().endUpdate();
  2146. }
  2147. editorUi.editor.graph.setSelectionCells(inserted);
  2148. editorUi.editor.graph.scrollCellToVisible(editorUi.editor.graph.getSelectionCell());
  2149. graph.destroy();
  2150. container.parentNode.removeChild(container);
  2151. }
  2152. }
  2153. };
  2154. var div = document.createElement('div');
  2155. div.style.textAlign = 'right';
  2156. var textarea = document.createElement('textarea');
  2157. textarea.style.boxSizing = 'border-box';
  2158. textarea.style.resize = 'none';
  2159. textarea.style.width = '100%';
  2160. textarea.style.height = '354px';
  2161. textarea.style.marginBottom = '16px';
  2162. var typeSelect = document.createElement('select');
  2163. if (defaultType == 'formatSql' || defaultType == 'mermaid')
  2164. {
  2165. typeSelect.style.display = 'none';
  2166. }
  2167. var listOption = document.createElement('option');
  2168. listOption.setAttribute('value', 'list');
  2169. mxUtils.write(listOption, mxResources.get('list'));
  2170. if (defaultType != 'plantUml')
  2171. {
  2172. typeSelect.appendChild(listOption);
  2173. }
  2174. if (defaultType == null || defaultType == 'fromText')
  2175. {
  2176. listOption.setAttribute('selected', 'selected');
  2177. }
  2178. var tableOption = document.createElement('option');
  2179. tableOption.setAttribute('value', 'table');
  2180. mxUtils.write(tableOption, mxResources.get('formatSql'));
  2181. if (defaultType == 'formatSql')
  2182. {
  2183. typeSelect.appendChild(tableOption);
  2184. tableOption.setAttribute('selected', 'selected');
  2185. }
  2186. var mermaidOption = document.createElement('option');
  2187. mermaidOption.setAttribute('value', 'mermaid');
  2188. mxUtils.write(mermaidOption, mxResources.get('formatSql'));
  2189. if (defaultType == 'mermaid')
  2190. {
  2191. typeSelect.appendChild(mermaidOption);
  2192. mermaidOption.setAttribute('selected', 'selected');
  2193. }
  2194. var diagramOption = document.createElement('option');
  2195. diagramOption.setAttribute('value', 'diagram');
  2196. mxUtils.write(diagramOption, mxResources.get('diagram'));
  2197. var circleOption = document.createElement('option');
  2198. circleOption.setAttribute('value', 'circle');
  2199. mxUtils.write(circleOption, mxResources.get('circle'));
  2200. var horizontalFlowOption = document.createElement('option');
  2201. horizontalFlowOption.setAttribute('value', 'horizontalFlow');
  2202. mxUtils.write(horizontalFlowOption, mxResources.get('horizontalFlow'));
  2203. var verticalFlowOption = document.createElement('option');
  2204. verticalFlowOption.setAttribute('value', 'verticalFlow');
  2205. mxUtils.write(verticalFlowOption, mxResources.get('verticalFlow'));
  2206. if (defaultType != 'plantUml')
  2207. {
  2208. typeSelect.appendChild(diagramOption);
  2209. typeSelect.appendChild(circleOption);
  2210. typeSelect.appendChild(horizontalFlowOption);
  2211. typeSelect.appendChild(verticalFlowOption);
  2212. }
  2213. var plantUmlSvgOption = document.createElement('option');
  2214. plantUmlSvgOption.setAttribute('value', 'plantUmlSvg');
  2215. mxUtils.write(plantUmlSvgOption, mxResources.get('plantUml') + ' (' + mxResources.get('formatSvg') + ')');
  2216. if (defaultType == 'plantUml')
  2217. {
  2218. plantUmlSvgOption.setAttribute('selected', 'selected');
  2219. }
  2220. var plantUmlPngOption = document.createElement('option');
  2221. plantUmlPngOption.setAttribute('value', 'plantUmlPng');
  2222. mxUtils.write(plantUmlPngOption, mxResources.get('plantUml') + ' (' + mxResources.get('formatPng') + ')');
  2223. var plantUmlTxtOption = document.createElement('option');
  2224. plantUmlTxtOption.setAttribute('value', 'plantUmlTxt');
  2225. mxUtils.write(plantUmlTxtOption, mxResources.get('plantUml') + ' (' + mxResources.get('text') + ')');
  2226. // Disabled for invalid hosts via CORS headers
  2227. if (EditorUi.enablePlantUml && Graph.fileSupport &&
  2228. !editorUi.isOffline() && defaultType == 'plantUml')
  2229. {
  2230. typeSelect.appendChild(plantUmlSvgOption);
  2231. typeSelect.appendChild(plantUmlPngOption);
  2232. typeSelect.appendChild(plantUmlTxtOption);
  2233. }
  2234. function getDefaultValue()
  2235. {
  2236. if (typeSelect.value == 'list')
  2237. {
  2238. return 'Person\n-name: String\n-birthDate: Date\n--\n+getName(): String\n+setName(String): void\n+isBirthday(): boolean\n\n' +
  2239. 'Address\n-street: String\n-city: String\n-state: String';
  2240. }
  2241. else if (typeSelect.value == 'mermaid')
  2242. {
  2243. return 'graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;';
  2244. }
  2245. else if (typeSelect.value == 'table')
  2246. {
  2247. return 'CREATE TABLE Suppliers\n(\nsupplier_id int NOT NULL PRIMARY KEY,\n' +
  2248. 'supplier_name char(50) NOT NULL,\ncontact_name char(50),\n);\n' +
  2249. 'CREATE TABLE Customers\n(\ncustomer_id int NOT NULL PRIMARY KEY,\n' +
  2250. 'customer_name char(50) NOT NULL,\naddress char(50),\n' +
  2251. 'city char(50),\nstate char(25),\nzip_code char(10)\n);\n';
  2252. }
  2253. else if (typeSelect.value == 'plantUmlPng')
  2254. {
  2255. return '@startuml\nskinparam backgroundcolor transparent\nskinparam shadowing false\nAlice -> Bob: Authentication Request\nBob --> Alice: Authentication Response\n\nAlice -> Bob: Another authentication Request\nAlice <-- Bob: Another authentication Response\n@enduml';
  2256. }
  2257. else if (typeSelect.value == 'plantUmlSvg' || typeSelect.value == 'plantUmlTxt')
  2258. {
  2259. return plantUmlExample;
  2260. }
  2261. else
  2262. {
  2263. return ';Example:\na->b\nb->edge label->c\nc->a\n';
  2264. }
  2265. };
  2266. var defaultValue = getDefaultValue();
  2267. textarea.value = defaultValue;
  2268. div.appendChild(textarea);
  2269. this.init = function()
  2270. {
  2271. textarea.focus();
  2272. };
  2273. // Enables dropping files
  2274. if (Graph.fileSupport)
  2275. {
  2276. function handleDrop(evt)
  2277. {
  2278. evt.stopPropagation();
  2279. evt.preventDefault();
  2280. if (evt.dataTransfer.files.length > 0)
  2281. {
  2282. var file = evt.dataTransfer.files[0];
  2283. var reader = new FileReader();
  2284. reader.onload = function(e) { textarea.value = e.target.result; };
  2285. reader.readAsText(file);
  2286. }
  2287. };
  2288. function handleDragOver(evt)
  2289. {
  2290. evt.stopPropagation();
  2291. evt.preventDefault();
  2292. };
  2293. // Setup the dnd listeners.
  2294. textarea.addEventListener('dragover', handleDragOver, false);
  2295. textarea.addEventListener('drop', handleDrop, false);
  2296. }
  2297. div.appendChild(typeSelect);
  2298. mxEvent.addListener(typeSelect, 'change', function()
  2299. {
  2300. var newDefaultValue = getDefaultValue();
  2301. if (textarea.value.length == 0 || textarea.value == defaultValue)
  2302. {
  2303. defaultValue = newDefaultValue;
  2304. textarea.value = defaultValue;
  2305. }
  2306. });
  2307. if (!editorUi.isOffline() && (defaultType == 'mermaid' || defaultType == 'plantUml'))
  2308. {
  2309. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  2310. {
  2311. editorUi.openLink((defaultType == 'mermaid') ?
  2312. 'https://mermaid-js.github.io/mermaid/#/' :
  2313. 'https://plantuml.com/');
  2314. });
  2315. helpBtn.className = 'geBtn';
  2316. div.appendChild(helpBtn);
  2317. }
  2318. var cancelBtn = mxUtils.button(mxResources.get('close'), function()
  2319. {
  2320. if (textarea.value == defaultValue)
  2321. {
  2322. editorUi.hideDialog();
  2323. }
  2324. else
  2325. {
  2326. editorUi.confirm(mxResources.get('areYouSure'), function()
  2327. {
  2328. editorUi.hideDialog();
  2329. });
  2330. }
  2331. });
  2332. cancelBtn.className = 'geBtn';
  2333. if (editorUi.editor.cancelFirst)
  2334. {
  2335. div.appendChild(cancelBtn);
  2336. }
  2337. var okBtn = mxUtils.button(mxResources.get('insert'), function(evt)
  2338. {
  2339. try
  2340. {
  2341. editorUi.hideDialog();
  2342. parse(textarea.value, typeSelect.value, evt);
  2343. }
  2344. catch (e)
  2345. {
  2346. editorUi.handleError(e);
  2347. }
  2348. });
  2349. okBtn.className = 'geBtn gePrimaryBtn';
  2350. div.appendChild(okBtn);
  2351. if (!editorUi.editor.cancelFirst)
  2352. {
  2353. div.appendChild(cancelBtn);
  2354. }
  2355. this.container = div;
  2356. };
  2357. /**
  2358. * Constructs a new dialog for creating files from templates.
  2359. */
  2360. var NewDialog = function(editorUi, compact, showName, callback, createOnly, cancelCallback,
  2361. leftHighlight, rightHighlight, rightHighlightBorder, itemPadding, templateFile,
  2362. recentDocsCallback, searchDocsCallback, openExtDocCallback, showImport, createButtonLabel, customTempCallback, withoutType)
  2363. {
  2364. var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  2365. var smallScreen = ww < 500;
  2366. showName = (showName != null) ? showName : true;
  2367. createOnly = (createOnly != null) ? createOnly : false;
  2368. leftHighlight = (leftHighlight != null) ? leftHighlight : (Editor.isDarkMode() ? Editor.darkColor : '#ebf2f9');
  2369. rightHighlight = (rightHighlight != null) ? rightHighlight : (Editor.isDarkMode() ? '#fff' : '#e6eff8');
  2370. rightHighlightBorder = (rightHighlightBorder != null) ? rightHighlightBorder : (Editor.isDarkMode() ? '1px dashed #00a8ff' : '1px solid #ccd9ea');
  2371. templateFile = (templateFile != null) ? templateFile : EditorUi.templateFile;
  2372. var outer = document.createElement('div');
  2373. outer.style.userSelect = 'none';
  2374. outer.style.height = '100%';
  2375. var header = document.createElement('div');
  2376. header.style.whiteSpace = 'nowrap';
  2377. header.style.height = '46px';
  2378. if (showName)
  2379. {
  2380. outer.appendChild(header);
  2381. }
  2382. var logo = document.createElement('img');
  2383. logo.setAttribute('border', '0');
  2384. logo.setAttribute('align', 'absmiddle');
  2385. logo.style.width = '40px';
  2386. logo.style.height = '40px';
  2387. logo.style.marginRight = '10px';
  2388. logo.style.paddingBottom = '4px';
  2389. if (editorUi.mode == App.MODE_GOOGLE)
  2390. {
  2391. logo.src = IMAGE_PATH + '/google-drive-logo.svg';
  2392. }
  2393. else if (editorUi.mode == App.MODE_DROPBOX)
  2394. {
  2395. logo.src = IMAGE_PATH + '/dropbox-logo.svg';
  2396. }
  2397. else if (editorUi.mode == App.MODE_ONEDRIVE)
  2398. {
  2399. logo.src = IMAGE_PATH + '/onedrive-logo.svg';
  2400. }
  2401. else if (editorUi.mode == App.MODE_GITHUB)
  2402. {
  2403. logo.src = IMAGE_PATH + '/github-logo.svg';
  2404. }
  2405. else if (editorUi.mode == App.MODE_GITLAB)
  2406. {
  2407. logo.src = IMAGE_PATH + '/gitlab-logo.svg';
  2408. }
  2409. else if (editorUi.mode == App.MODE_TRELLO)
  2410. {
  2411. logo.src = IMAGE_PATH + '/trello-logo.svg';
  2412. }
  2413. else if (editorUi.mode == App.MODE_BROWSER)
  2414. {
  2415. logo.src = IMAGE_PATH + '/osa_database.png';
  2416. }
  2417. else
  2418. {
  2419. logo.src = IMAGE_PATH + '/osa_drive-harddisk.png';
  2420. }
  2421. if (!compact && !smallScreen && showName)
  2422. {
  2423. header.appendChild(logo);
  2424. }
  2425. if (showName)
  2426. {
  2427. mxUtils.write(header, (smallScreen? mxResources.get('name') : ((editorUi.mode == null || editorUi.mode == App.MODE_GOOGLE ||
  2428. editorUi.mode == App.MODE_BROWSER) ? mxResources.get('diagramName') : mxResources.get('filename'))) + ':');
  2429. }
  2430. var ext = '.drawio';
  2431. if (editorUi.mode == App.MODE_GOOGLE && editorUi.drive != null)
  2432. {
  2433. ext = editorUi.drive.extension;
  2434. }
  2435. else if (editorUi.mode == App.MODE_DROPBOX && editorUi.dropbox != null)
  2436. {
  2437. ext = editorUi.dropbox.extension;
  2438. }
  2439. else if (editorUi.mode == App.MODE_ONEDRIVE && editorUi.oneDrive != null)
  2440. {
  2441. ext = editorUi.oneDrive.extension;
  2442. }
  2443. else if (editorUi.mode == App.MODE_GITHUB && editorUi.gitHub != null)
  2444. {
  2445. ext = editorUi.gitHub.extension;
  2446. }
  2447. else if (editorUi.mode == App.MODE_GITLAB && editorUi.gitLab != null)
  2448. {
  2449. ext = editorUi.gitLab.extension;
  2450. }
  2451. else if (editorUi.mode == App.MODE_TRELLO && editorUi.trello != null)
  2452. {
  2453. ext = editorUi.trello.extension;
  2454. }
  2455. var nameInput = document.createElement('input');
  2456. nameInput.setAttribute('value', editorUi.defaultFilename + ext);
  2457. nameInput.style.marginLeft = '10px';
  2458. nameInput.style.width = (compact || smallScreen) ? '144px' : '244px';
  2459. this.init = function()
  2460. {
  2461. if (showName)
  2462. {
  2463. nameInput.focus();
  2464. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  2465. {
  2466. nameInput.select();
  2467. }
  2468. else
  2469. {
  2470. document.execCommand('selectAll', false, null);
  2471. }
  2472. }
  2473. if (div.parentNode != null && div.parentNode.parentNode != null)
  2474. {
  2475. mxEvent.addGestureListeners(div.parentNode.parentNode, mxUtils.bind(this, function(evt)
  2476. {
  2477. editorUi.sidebar.hideTooltip();
  2478. }), null, null);
  2479. }
  2480. };
  2481. // Adds filetype dropdown
  2482. if (showName)
  2483. {
  2484. header.appendChild(nameInput);
  2485. if (withoutType)
  2486. {
  2487. nameInput.style.width = (compact || smallScreen) ? '350px' : '450px';
  2488. }
  2489. else
  2490. {
  2491. if (editorUi.editor.diagramFileTypes != null)
  2492. {
  2493. var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes);
  2494. typeSelect.style.marginLeft = '6px';
  2495. typeSelect.style.width = (compact || smallScreen) ? '80px' : '180px';
  2496. header.appendChild(typeSelect);
  2497. }
  2498. if (editorUi.editor.fileExtensions != null)
  2499. {
  2500. var hint = FilenameDialog.createTypeHint(editorUi,
  2501. nameInput, editorUi.editor.fileExtensions);
  2502. hint.style.marginTop = '12px';
  2503. header.appendChild(hint);
  2504. }
  2505. }
  2506. }
  2507. var hasTabs = false;
  2508. var i0 = 0;
  2509. // Dynamic loading
  2510. function addTemplates(smallSize)
  2511. {
  2512. //smallSize: Reduce template button size to fit 4 in a row
  2513. if (smallSize != null)
  2514. {
  2515. w = h = smallSize? 135 : 140;
  2516. }
  2517. var first = true;
  2518. //TODO support paging of external templates
  2519. if (templates != null)
  2520. {
  2521. while (i0 < templates.length && (first || mxUtils.mod(i0, 30) != 0))
  2522. {
  2523. var tmp = templates[i0++];
  2524. var btn = addButton(tmp.url, tmp.libs, tmp.title, tmp.tooltip? tmp.tooltip : tmp.title,
  2525. tmp.select, tmp.imgUrl, tmp.info, tmp.onClick, tmp.preview, tmp.noImg, tmp.clibs);
  2526. if (first)
  2527. {
  2528. btn.click();
  2529. }
  2530. first = false;
  2531. }
  2532. }
  2533. };
  2534. var spinner = new Spinner({
  2535. lines: 12, // The number of lines to draw
  2536. length: 10, // The length of each line
  2537. width: 5, // The line thickness
  2538. radius: 10, // The radius of the inner circle
  2539. rotate: 0, // The rotation offset
  2540. color: '#000', // #rgb or #rrggbb
  2541. speed: 1.5, // Rounds per second
  2542. trail: 60, // Afterglow percentage
  2543. shadow: false, // Whether to render a shadow
  2544. hwaccel: false, // Whether to use hardware acceleration
  2545. top: '40%',
  2546. zIndex: 2e9 // The z-index (defaults to 2000000000)
  2547. });
  2548. var createButton = mxUtils.button(createButtonLabel || mxResources.get('create'), function()
  2549. {
  2550. createButton.setAttribute('disabled', 'disabled');
  2551. create();
  2552. createButton.removeAttribute('disabled');
  2553. });
  2554. createButton.className = 'geBtn gePrimaryBtn';
  2555. var magnifyImage = document.createElement('img');
  2556. magnifyImage.setAttribute('src', Sidebar.prototype.searchImage);
  2557. magnifyImage.setAttribute('title', mxResources.get('preview'));
  2558. magnifyImage.className = 'geActiveButton';
  2559. magnifyImage.style.position = 'absolute';
  2560. magnifyImage.style.cursor = 'default';
  2561. magnifyImage.style.padding = '8px';
  2562. magnifyImage.style.right = '0px';
  2563. magnifyImage.style.top = '0px';
  2564. // Shows a tooltip with the rendered template
  2565. var loading = false;
  2566. var extImg = null;
  2567. var wasVisible = false;
  2568. function showTooltip(xml, x, y, elt, title, url)
  2569. {
  2570. // Checks if dialog still visible
  2571. if (xml != null && mxUtils.isAncestorNode(document.body, elt))
  2572. {
  2573. var doc = mxUtils.parseXml(xml);
  2574. var tempNode = Editor.parseDiagramNode(doc.documentElement);
  2575. var codec = new mxCodec(tempNode.ownerDocument);
  2576. var model = new mxGraphModel();
  2577. codec.decode(tempNode, model);
  2578. var cells = model.root.getChildAt(0).children;
  2579. var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  2580. var wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  2581. // TODO: Use maxscreensize
  2582. editorUi.sidebar.createTooltip(elt, cells, Math.min(ww - 80, 1000), Math.min(wh - 80, 800),
  2583. (title != null) ? mxResources.get(title) : null,
  2584. true, new mxPoint(x, y), true, function()
  2585. {
  2586. wasVisible = editorUi.sidebar.tooltip != null &&
  2587. editorUi.sidebar.tooltip.style.display != 'none';
  2588. if (url != null)
  2589. {
  2590. selectElement(elt, null, null, url, infoObj, clibs);
  2591. }
  2592. }, true, false);
  2593. }
  2594. };
  2595. if (recentDocsCallback || searchDocsCallback)
  2596. {
  2597. var tabsEl = [];
  2598. var oldTemplates = null, origCategories = null, origCustomCatCount = null;
  2599. var setActiveTab = function(index)
  2600. {
  2601. createButton.setAttribute('disabled', 'disabled');
  2602. for (var i = 0; i < tabsEl.length; i++)
  2603. {
  2604. if (i == index)
  2605. tabsEl[i].className = 'geBtn gePrimaryBtn';
  2606. else
  2607. tabsEl[i].className = 'geBtn';
  2608. }
  2609. }
  2610. hasTabs = true;
  2611. var tabs = document.createElement('div');
  2612. tabs.style.whiteSpace = 'nowrap';
  2613. tabs.style.height = '30px';
  2614. outer.appendChild(tabs);
  2615. var templatesTab = mxUtils.button(mxResources.get('Templates', null, 'Templates'), function()
  2616. {
  2617. list.style.display = '';
  2618. searchBox.style.display = '';
  2619. div.style.left = '160px';
  2620. setActiveTab(0);
  2621. div.scrollTop = 0;
  2622. div.innerText = '';
  2623. i0 = 0;
  2624. if (oldTemplates != templates)
  2625. {
  2626. templates = oldTemplates;
  2627. categories = origCategories;
  2628. customCatCount = origCustomCatCount;
  2629. list.innerText = '';
  2630. initUi();
  2631. oldTemplates = null;
  2632. }
  2633. });
  2634. tabsEl.push(templatesTab);
  2635. tabs.appendChild(templatesTab);
  2636. var getExtTemplates = function(isSearch)
  2637. {
  2638. list.style.display = 'none';
  2639. searchBox.style.display = 'none';
  2640. div.style.left = '30px';
  2641. setActiveTab(isSearch? -1 : 1); //deselect all of them if isSearch
  2642. if (oldTemplates == null)
  2643. {
  2644. oldTemplates = templates;
  2645. }
  2646. div.scrollTop = 0;
  2647. div.innerText = '';
  2648. spinner.spin(div);
  2649. var callback2 = function(docList, errorMsg, searchImportCats)
  2650. {
  2651. i0 = 0;
  2652. spinner.stop();
  2653. templates = docList;
  2654. searchImportCats = searchImportCats || {};
  2655. var importListsCount = 0;
  2656. for (var cat in searchImportCats)
  2657. {
  2658. importListsCount += searchImportCats[cat].length;
  2659. }
  2660. if (errorMsg)
  2661. {
  2662. div.innerText = errorMsg;
  2663. }
  2664. else if (docList.length == 0 && importListsCount == 0)
  2665. {
  2666. div.innerText = mxResources.get('noDiagrams', null, 'No Diagrams Found');
  2667. }
  2668. else
  2669. {
  2670. div.innerText = '';
  2671. if (importListsCount > 0)
  2672. {
  2673. list.style.display = '';
  2674. div.style.left = '160px';
  2675. list.innerText = '';
  2676. customCatCount = 0;
  2677. categories = {'draw.io': docList};
  2678. for (var cat in searchImportCats)
  2679. {
  2680. categories[cat] = searchImportCats[cat];
  2681. }
  2682. initUi();
  2683. }
  2684. else
  2685. {
  2686. addTemplates(true);
  2687. }
  2688. }
  2689. }
  2690. if (isSearch)
  2691. {
  2692. searchDocsCallback(searchInput.value, callback2);
  2693. }
  2694. else
  2695. {
  2696. recentDocsCallback(callback2);
  2697. }
  2698. }
  2699. if (recentDocsCallback)
  2700. {
  2701. var recentTab = mxUtils.button(mxResources.get('Recent', null, 'Recent'), function()
  2702. {
  2703. getExtTemplates();
  2704. });
  2705. tabs.appendChild(recentTab);
  2706. tabsEl.push(recentTab);
  2707. }
  2708. if (searchDocsCallback)
  2709. {
  2710. var searchTab = document.createElement('span');
  2711. searchTab.style.marginLeft = '10px';
  2712. searchTab.innerText = mxResources.get('search') + ':';
  2713. tabs.appendChild(searchTab);
  2714. var searchInput = document.createElement('input');
  2715. searchInput.style.marginRight = '10px';
  2716. searchInput.style.marginLeft = '10px';
  2717. searchInput.style.width = '220px';
  2718. mxEvent.addListener(searchInput, 'keypress', function(e)
  2719. {
  2720. if (e.keyCode == 13)
  2721. {
  2722. getExtTemplates(true);
  2723. }
  2724. });
  2725. tabs.appendChild(searchInput);
  2726. var searchBtn = mxUtils.button(mxResources.get('search'), function()
  2727. {
  2728. getExtTemplates(true);
  2729. });
  2730. searchBtn.className = 'geBtn';
  2731. tabs.appendChild(searchBtn);
  2732. }
  2733. setActiveTab(0);
  2734. }
  2735. var templateLibs = null;
  2736. var templateClibs = null;
  2737. var templateXml = null;
  2738. var selectedElt = null;
  2739. var templateExtUrl = null;
  2740. var templateRealUrl = null;
  2741. var templateInfoObj = null;
  2742. var lastAiXml = null;
  2743. function createAiContent()
  2744. {
  2745. var content = document.createElement('div');
  2746. content.style.position = 'absolute';
  2747. content.style.overflow = 'hidden';
  2748. content.style.left = '4px';
  2749. content.style.right = '4px';
  2750. content.style.bottom = '4px';
  2751. content.style.top = '4px';
  2752. mxUtils.write(content, 'OpenAI API Key:');
  2753. mxUtils.br(content);
  2754. var openAiKey = document.createElement('input');
  2755. openAiKey.setAttribute('type', 'text');
  2756. openAiKey.setAttribute('placeholder', 'Paste secret key here');
  2757. openAiKey.style.width = '100%';
  2758. openAiKey.style.marginTop = '4px';
  2759. openAiKey.style.marginBottom = '10px';
  2760. openAiKey.style.boxSizing = 'border-box';
  2761. content.appendChild(openAiKey);
  2762. if (isLocalStorage)
  2763. {
  2764. var storedKey = localStorage.getItem('.openAiKey');
  2765. openAiKey.value = storedKey || '';
  2766. mxEvent.addListener(openAiKey, 'change', function()
  2767. {
  2768. localStorage.setItem('.openAiKey', openAiKey.value);
  2769. });
  2770. }
  2771. mxUtils.br(content);
  2772. mxUtils.write(content, mxResources.get('diagramContent') + ':');
  2773. mxUtils.br(content);
  2774. var description = document.createElement('input');
  2775. description.setAttribute('type', 'text');
  2776. description.setAttribute('placeholder', mxResources.get('description'));
  2777. description.style.width = '100%';
  2778. description.style.marginTop = '4px';
  2779. description.style.marginBottom = '4px';
  2780. description.style.boxSizing = 'border-box';
  2781. content.appendChild(description);
  2782. mxUtils.br(content);
  2783. var preview = document.createElement('div');
  2784. preview.style.top = '132px'
  2785. preview.style.left = '2px';
  2786. preview.style.right = '2px';
  2787. preview.style.bottom = '2px';
  2788. preview.style.position = 'absolute';
  2789. preview.style.border = '1px solid #424242';
  2790. var previewText = document.createElement('div');
  2791. previewText.style.boxSizing = 'border-box';
  2792. previewText.style.position = 'relative';
  2793. previewText.style.textAlign = 'center';
  2794. previewText.style.top = '50%';
  2795. mxUtils.write(previewText, mxResources.get('preview'));
  2796. preview.appendChild(previewText);
  2797. // Adds diagram type options
  2798. var typeSelect = document.createElement('select');
  2799. typeSelect.className = 'geBtn';
  2800. typeSelect.style.maxWidth = '160px';
  2801. typeSelect.style.marginLeft = '10px';
  2802. var option = document.createElement('option');
  2803. mxUtils.write(option, mxResources.get('type'));
  2804. option.setAttribute('value', '');
  2805. typeSelect.appendChild(option);
  2806. for (var i = 0; i < EditorUi.mermaidDiagramTypes.length; i++)
  2807. {
  2808. var option = document.createElement('option');
  2809. var type = EditorUi.mermaidDiagramTypes[i];
  2810. var key = type;
  2811. // Maps types to translations
  2812. if (key == 'erDiagram')
  2813. {
  2814. key = 'entityRelationshipDiagram';
  2815. }
  2816. var title = mxResources.get(key, null, key.charAt(0).toUpperCase() +
  2817. key.substring(1).replace(/[A-Z]/g, ' $&'));
  2818. option.setAttribute('value', type);
  2819. mxUtils.write(option, title);
  2820. typeSelect.appendChild(option);
  2821. }
  2822. var button = mxUtils.button(mxResources.get('generate'), function()
  2823. {
  2824. var prompt = 'create mermaid ' + ((typeSelect.value != '') ?
  2825. (typeSelect.value + ' ') : '') + 'declaration for ' +
  2826. description.value;
  2827. var type = ((typeSelect.value != '') ? (' (' + mxUtils.trim(
  2828. mxUtils.getTextContent(typeSelect.options[
  2829. typeSelect.selectedIndex])) + ')') : '');
  2830. var title = description.value + type;
  2831. editorUi.generateOpenAiMermaidDiagram(openAiKey.value, prompt,
  2832. function(mermaidData, imageData, w, h)
  2833. {
  2834. preview.innerHTML = '';
  2835. var img = document.createElement('img');
  2836. img.setAttribute('title', title);
  2837. img.src = 'data:image/svg+xml;base64,' +
  2838. imageData.substring(imageData.indexOf(',') + 1);
  2839. img.style.cursor = 'pointer';
  2840. img.style.width = '100%';
  2841. img.style.height = '100%';
  2842. preview.appendChild(img);
  2843. var xml = editorUi.createMermaidXml('%% Input: ' + title +
  2844. '\n' + mermaidData, EditorUi.defaultMermaidConfig,
  2845. imageData, w, h);
  2846. // Updates template XML for insert button
  2847. var previewXml = '<mxfile><diagram id="d" name="n">' +
  2848. Graph.compress(xml) + '</diagram></mxfile>';
  2849. templateXml = xml;
  2850. lastAiXml = xml;
  2851. var magnify = magnifyImage.cloneNode(true);
  2852. preview.appendChild(magnify);
  2853. var mouseDownHandler = function(evt)
  2854. {
  2855. wasVisible = editorUi.sidebar.tooltip != null &&
  2856. editorUi.sidebar.tooltip.style.display != 'none';
  2857. };
  2858. var mouseUpHandler = function(evt)
  2859. {
  2860. if (!wasVisible)
  2861. {
  2862. showTooltip(previewXml, mxEvent.getClientX(evt),
  2863. mxEvent.getClientY(evt), img, title);
  2864. }
  2865. };
  2866. mxEvent.addGestureListeners(img, mouseDownHandler, null, mouseUpHandler);
  2867. mxEvent.addGestureListeners(magnify, mouseDownHandler, null, mouseUpHandler);
  2868. }, function(e)
  2869. {
  2870. editorUi.handleError(e);
  2871. }
  2872. );
  2873. });
  2874. button.className = 'geBtn gePrimaryBtn';
  2875. mxEvent.addListener(description, 'keydown', function(e)
  2876. {
  2877. if (e.keyCode == 13)
  2878. {
  2879. button.click();
  2880. }
  2881. });
  2882. var buttons = document.createElement('div');
  2883. buttons.style.height = '40px';
  2884. buttons.style.marginTop = '4px';
  2885. buttons.style.marginBottom = '4px';
  2886. buttons.style.whiteSpace = 'nowrap';
  2887. buttons.style.overflowX = 'auto';
  2888. buttons.style.overflowY = 'hidden';
  2889. var keyButton = mxUtils.button('Get Key', function()
  2890. {
  2891. editorUi.openLink('https://beta.openai.com/account/api-keys');
  2892. });
  2893. keyButton.className = 'geBtn';
  2894. keyButton.style.marginLeft = '10px';
  2895. var helpButton = mxUtils.button(mxResources.get('help'), function()
  2896. {
  2897. editorUi.openLink('https://github.com/jgraph/drawio/discussions/3313');
  2898. });
  2899. helpButton.className = 'geBtn';
  2900. helpButton.style.marginLeft = '10px';
  2901. buttons.appendChild(button);
  2902. buttons.appendChild(typeSelect);
  2903. buttons.appendChild(keyButton);
  2904. buttons.appendChild(helpButton);
  2905. content.appendChild(buttons);
  2906. content.appendChild(preview);
  2907. return content;
  2908. };
  2909. function create()
  2910. {
  2911. if (templateExtUrl && openExtDocCallback != null)
  2912. {
  2913. if (!showName)
  2914. {
  2915. editorUi.hideDialog();
  2916. }
  2917. openExtDocCallback(templateExtUrl, templateInfoObj, nameInput.value);
  2918. }
  2919. else if (callback)
  2920. {
  2921. if (!showName)
  2922. {
  2923. editorUi.hideDialog();
  2924. }
  2925. callback(templateXml, nameInput.value, templateRealUrl, templateLibs);
  2926. }
  2927. else
  2928. {
  2929. var title = nameInput.value;
  2930. if (title != null && title.length > 0)
  2931. {
  2932. editorUi.pickFolder(editorUi.mode, function(folderId)
  2933. {
  2934. editorUi.createFile(title, templateXml, (templateLibs != null &&
  2935. templateLibs.length > 0) ? templateLibs : null, null, function()
  2936. {
  2937. editorUi.hideDialog();
  2938. }, null, folderId, null, (templateClibs != null &&
  2939. templateClibs.length > 0) ? templateClibs : null);
  2940. }, editorUi.mode != App.MODE_GOOGLE ||
  2941. editorUi.stateArg == null ||
  2942. editorUi.stateArg.folderId == null);
  2943. }
  2944. }
  2945. };
  2946. var div = document.createElement('div');
  2947. div.style.border = '1px solid #d3d3d3';
  2948. div.style.position = 'absolute';
  2949. div.style.left = '160px';
  2950. div.style.right = '34px';
  2951. var divTop = (showName) ? 72 : 40;
  2952. divTop += hasTabs? 30 : 0;
  2953. div.style.top = divTop + 'px';
  2954. div.style.bottom = '68px';
  2955. div.style.margin = '6px 0 0 -1px';
  2956. div.style.padding = '6px';
  2957. div.style.overflow = 'auto';
  2958. // mxEvent.addListener(div, 'dragstart', function(evt)
  2959. // {
  2960. // if (!mxEvent.isTouchEvent(evt))
  2961. // {
  2962. // mxEvent.consume(evt);
  2963. // }
  2964. // });
  2965. var searchBox = document.createElement('div');
  2966. searchBox.style.cssText = 'position:absolute;left:30px;width:128px;top:' + divTop +
  2967. 'px;height:22px;margin-top: 6px;white-space: nowrap;';
  2968. var tmplSearchInput = document.createElement('input');
  2969. tmplSearchInput.style.cssText = 'width:105px;height:16px;border:1px solid #d3d3d3;' +
  2970. 'padding: 3px 20px 3px 3px;font-size: 12px;border-radius:0px;';
  2971. tmplSearchInput.setAttribute('placeholder', mxResources.get('search'));
  2972. tmplSearchInput.setAttribute('type', 'text');
  2973. searchBox.appendChild(tmplSearchInput);
  2974. var cross = document.createElement('img');
  2975. var searchImg = typeof Sidebar != 'undefined'? Sidebar.prototype.searchImage : IMAGE_PATH + '/search.png';
  2976. cross.setAttribute('src', searchImg);
  2977. cross.setAttribute('title', mxResources.get('search'));
  2978. cross.style.position = 'relative';
  2979. cross.style.left = '-18px';
  2980. cross.style.top = '1px';
  2981. // Needed to block event transparency in IE
  2982. cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')';
  2983. searchBox.appendChild(cross);
  2984. mxEvent.addListener(cross, 'click', function()
  2985. {
  2986. if (cross.getAttribute('src') == Dialog.prototype.closeImage)
  2987. {
  2988. cross.setAttribute('src', searchImg);
  2989. cross.setAttribute('title', mxResources.get('search'));
  2990. tmplSearchInput.value = '';
  2991. resetTemplates();
  2992. }
  2993. tmplSearchInput.focus();
  2994. });
  2995. mxEvent.addListener(tmplSearchInput, 'keydown', mxUtils.bind(this, function(evt)
  2996. {
  2997. if (evt.keyCode == 13 /* Enter */)
  2998. {
  2999. filterTemplates();
  3000. mxEvent.consume(evt);
  3001. }
  3002. }));
  3003. mxEvent.addListener(tmplSearchInput, 'keyup', mxUtils.bind(this, function(evt)
  3004. {
  3005. if (tmplSearchInput.value == '')
  3006. {
  3007. cross.setAttribute('src', searchImg);
  3008. cross.setAttribute('title', mxResources.get('search'));
  3009. }
  3010. else
  3011. {
  3012. cross.setAttribute('src', Dialog.prototype.closeImage);
  3013. cross.setAttribute('title', mxResources.get('reset'));
  3014. }
  3015. }));
  3016. divTop += 23;
  3017. var list = document.createElement('div');
  3018. list.style.cssText = 'position:absolute;left:30px;width:128px;top:' + divTop + 'px;bottom:68px;margin-top:6px;overflow:auto;border:1px solid #d3d3d3;';
  3019. mxEvent.addListener(div, 'scroll', function()
  3020. {
  3021. editorUi.sidebar.hideTooltip();
  3022. });
  3023. var w = 140;
  3024. var h = 140;
  3025. function selectElement(elt, xml, libs, extUrl, infoObj, clibs, realUrl)
  3026. {
  3027. if (selectedElt != null)
  3028. {
  3029. selectedElt.style.backgroundColor = 'transparent';
  3030. selectedElt.style.border = '1px solid transparent';
  3031. }
  3032. createButton.removeAttribute('disabled');
  3033. templateXml = xml;
  3034. templateLibs = libs;
  3035. templateClibs = clibs;
  3036. selectedElt = elt;
  3037. templateExtUrl = extUrl;
  3038. templateRealUrl = realUrl;
  3039. templateInfoObj = infoObj;
  3040. selectedElt.style.backgroundColor = rightHighlight;
  3041. selectedElt.style.border = rightHighlightBorder;
  3042. };
  3043. function addButton(url, libs, title, tooltip, select, imgUrl, infoObj, onClick, preview, noImg, clibs)
  3044. {
  3045. var elt = document.createElement('div');
  3046. elt.className = 'geTemplate geAdaptiveAsset';
  3047. elt.style.position = 'relative';
  3048. elt.style.height = w + 'px';
  3049. elt.style.width = h + 'px';
  3050. elt.style.border = '1px solid transparent';
  3051. var xmlData = null, realUrl = url;
  3052. if (title != null)
  3053. {
  3054. elt.setAttribute('title', mxResources.get(title, null, title));
  3055. }
  3056. else if (tooltip != null && tooltip.length > 0)
  3057. {
  3058. elt.setAttribute('title', tooltip);
  3059. }
  3060. function loadXmlData(url, callback)
  3061. {
  3062. if (xmlData == null)
  3063. {
  3064. realUrl = url;
  3065. if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl))
  3066. {
  3067. realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl);
  3068. }
  3069. else
  3070. {
  3071. realUrl = TEMPLATE_PATH + '/' + realUrl;
  3072. }
  3073. mxUtils.get(realUrl, mxUtils.bind(this, function(req)
  3074. {
  3075. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  3076. {
  3077. xmlData = req.getText();
  3078. callback(xmlData, realUrl);
  3079. }
  3080. else
  3081. {
  3082. callback(xmlData, realUrl);
  3083. }
  3084. }));
  3085. }
  3086. else
  3087. {
  3088. callback(xmlData, realUrl);
  3089. }
  3090. }
  3091. function loadTooltip(evt, tooltipTitle)
  3092. {
  3093. if (url != null && !loading && editorUi.sidebar.currentElt != elt)
  3094. {
  3095. editorUi.sidebar.hideTooltip();
  3096. if (extImg != null)
  3097. {
  3098. //Create a diagram with the image to use the same code
  3099. //Note: Without compression it doesn't work for some reason. Find out why later
  3100. var xml = '<mxfile><diagram id="d" name="n">' + Graph.compress('<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/>' +
  3101. '<mxCell id="2" value="" style="shape=image;image=' + extImg.src + ';imageAspect=1;" parent="1" vertex="1"><mxGeometry width="' +
  3102. extImg.naturalWidth + '" height="' + extImg.naturalHeight + '" as="geometry" /></mxCell></root></mxGraphModel>') + '</diagram></mxfile>';
  3103. showTooltip(xml, mxEvent.getClientX(evt), mxEvent.getClientY(evt), title, url);
  3104. return;
  3105. }
  3106. editorUi.sidebar.currentElt = elt;
  3107. loading = true;
  3108. loadXmlData(url, function(xml)
  3109. {
  3110. if (loading && editorUi.sidebar.currentElt == elt)
  3111. {
  3112. showTooltip(xml, mxEvent.getClientX(evt),
  3113. mxEvent.getClientY(evt), elt,
  3114. tooltipTitle);
  3115. }
  3116. loading = false;
  3117. });
  3118. }
  3119. else
  3120. {
  3121. editorUi.sidebar.hideTooltip();
  3122. }
  3123. };
  3124. if (imgUrl != null)
  3125. {
  3126. elt.style.display = 'inline-flex';
  3127. elt.style.justifyContent = 'center';
  3128. elt.style.alignItems = 'center';
  3129. var img = document.createElement('img');
  3130. img.setAttribute('src', imgUrl);
  3131. img.setAttribute('alt', tooltip);
  3132. img.style.maxWidth = w + 'px';
  3133. img.style.maxHeight = h + 'px';
  3134. extImg = img;
  3135. var fallbackImgUrl = imgUrl.replace('.drawio.xml', '').replace('.drawio', '').replace('.xml', '');
  3136. elt.appendChild(img);
  3137. img.onerror = function()
  3138. {
  3139. if (this.src != fallbackImgUrl)
  3140. {
  3141. this.src = fallbackImgUrl;
  3142. }
  3143. else
  3144. {
  3145. this.src = Editor.errorImage;
  3146. this.onerror = null;
  3147. }
  3148. };
  3149. mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt)
  3150. {
  3151. selectElement(elt, null, null, url, infoObj, clibs);
  3152. }), null, null);
  3153. mxEvent.addListener(elt, 'dblclick', function(evt)
  3154. {
  3155. create();
  3156. mxEvent.consume(evt);
  3157. });
  3158. }
  3159. else if (!noImg && url != null && url.length > 0)
  3160. {
  3161. var png = preview || (TEMPLATE_PATH + '/' + url.substring(0, url.length - 4) + '.png');
  3162. elt.style.backgroundImage = 'url(' + png + ')';
  3163. elt.style.backgroundPosition = 'center center';
  3164. elt.style.backgroundRepeat = 'no-repeat';
  3165. if (title != null)
  3166. {
  3167. var table = document.createElement('table');
  3168. table.setAttribute('width', '100%');
  3169. table.setAttribute('height', '100%');
  3170. table.style.background = Editor.isDarkMode() ? 'transparent' : 'rgba(255,255,255,0.85)';
  3171. table.style.lineHeight = '1.3em';
  3172. table.style.border = 'inherit';
  3173. var tbody = document.createElement('tbody');
  3174. var row = document.createElement('tr');
  3175. var td = document.createElement('td');
  3176. td.setAttribute('align', 'center');
  3177. td.setAttribute('valign', 'middle');
  3178. var span = document.createElement('span');
  3179. span.style.display = 'inline-block';
  3180. span.style.padding = '4px 8px 4px 8px';
  3181. span.style.userSelect = 'none';
  3182. span.style.borderRadius = '3px';
  3183. span.style.background = 'rgba(255,255,255,0.85)';
  3184. span.style.overflow = 'hidden';
  3185. span.style.textOverflow = 'ellipsis';
  3186. span.style.maxWidth = (w - 34) + 'px';
  3187. mxUtils.write(span, mxResources.get(title, null, title));
  3188. td.appendChild(span);
  3189. row.appendChild(td);
  3190. tbody.appendChild(row);
  3191. table.appendChild(tbody);
  3192. elt.appendChild(table);
  3193. }
  3194. function activate(doCreate)
  3195. {
  3196. createButton.setAttribute('disabled', 'disabled');
  3197. elt.style.backgroundColor = 'transparent';
  3198. elt.style.border = '1px solid transparent';
  3199. spinner.spin(div);
  3200. loadXmlData(url, function(xml, realUrl)
  3201. {
  3202. spinner.stop();
  3203. if (xml != null)
  3204. {
  3205. selectElement(elt, xml, libs, null, null, clibs, realUrl);
  3206. if (doCreate)
  3207. {
  3208. create();
  3209. }
  3210. }
  3211. });
  3212. };
  3213. mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt)
  3214. {
  3215. activate();
  3216. }), null, null);
  3217. mxEvent.addListener(elt, 'dblclick', function(evt)
  3218. {
  3219. activate(true);
  3220. mxEvent.consume(evt);
  3221. });
  3222. }
  3223. else
  3224. {
  3225. var table = document.createElement('table');
  3226. table.setAttribute('width', '100%');
  3227. table.setAttribute('height', '100%');
  3228. table.style.lineHeight = '1.3em';
  3229. var tbody = document.createElement('tbody');
  3230. var row = document.createElement('tr');
  3231. var td = document.createElement('td');
  3232. td.setAttribute('align', 'center');
  3233. td.setAttribute('valign', 'middle');
  3234. var span = document.createElement('span');
  3235. span.style.display = 'inline-block';
  3236. span.style.padding = '4px 8px 4px 8px';
  3237. span.style.userSelect = 'none';
  3238. span.style.borderRadius = '3px';
  3239. span.style.background = '#ffffff';
  3240. span.style.overflow = 'hidden';
  3241. span.style.textOverflow = 'ellipsis';
  3242. span.style.maxWidth = (w - 34) + 'px';
  3243. mxUtils.write(span, mxResources.get(title, null, title));
  3244. td.appendChild(span);
  3245. row.appendChild(td);
  3246. tbody.appendChild(row);
  3247. table.appendChild(tbody);
  3248. elt.appendChild(table);
  3249. if (select)
  3250. {
  3251. selectElement(elt);
  3252. }
  3253. mxEvent.addGestureListeners(elt, mxUtils.bind(this, function(evt)
  3254. {
  3255. selectElement(elt, null, null, url, infoObj);
  3256. }), null, null);
  3257. if (onClick != null)
  3258. {
  3259. mxEvent.addListener(elt, 'click', onClick);
  3260. }
  3261. else
  3262. {
  3263. mxEvent.addListener(elt, 'click', function(evt)
  3264. {
  3265. selectElement(elt, null, null, url, infoObj);
  3266. });
  3267. mxEvent.addListener(elt, 'dblclick', function(evt)
  3268. {
  3269. create();
  3270. mxEvent.consume(evt);
  3271. });
  3272. }
  3273. }
  3274. // Adds preview button
  3275. if (url != null)
  3276. {
  3277. var magnify = magnifyImage.cloneNode(true);
  3278. elt.appendChild(magnify);
  3279. mxEvent.addGestureListeners(magnify, mxUtils.bind(this, function(evt)
  3280. {
  3281. wasVisible = editorUi.sidebar.currentElt == elt;
  3282. }), null, null);
  3283. mxEvent.addListener(magnify, 'click', mxUtils.bind(this, function(evt)
  3284. {
  3285. if (!wasVisible)
  3286. {
  3287. loadTooltip(evt, (title != null) ? title : tooltip);
  3288. }
  3289. mxEvent.consume(evt);
  3290. }));
  3291. }
  3292. div.appendChild(elt);
  3293. return elt;
  3294. };
  3295. var categories = {}, subCategories = {}, customCats = {};
  3296. var customCatCount = 0, firstInitUi = true;
  3297. var currentEntry = null, lastEntry = null;
  3298. // Adds local basic templates
  3299. categories['basic'] = [{title: 'blankDiagram', select: true}];
  3300. var templates = categories['basic'];
  3301. if (urlParams['test'] == '1' && editorUi.getServiceName() == 'draw.io')
  3302. {
  3303. categories['aiTemplate'] = {content: createAiContent()};
  3304. }
  3305. function resetTemplates()
  3306. {
  3307. if (lastEntry != null)
  3308. {
  3309. lastEntry.click();
  3310. lastEntry = null;
  3311. }
  3312. };
  3313. function filterTemplates()
  3314. {
  3315. var searchTerms = tmplSearchInput.value;
  3316. if (searchTerms == '')
  3317. {
  3318. resetTemplates();
  3319. return;
  3320. }
  3321. if (NewDialog.tagsList[templateFile] == null)
  3322. {
  3323. var tagsList = {};
  3324. for (var cat in categories)
  3325. {
  3326. if (categories[cat].content == null)
  3327. {
  3328. var templateList = categories[cat];
  3329. for (var i = 0; i < templateList.length; i++)
  3330. {
  3331. var temp = templateList[i];
  3332. if (temp.tags != null)
  3333. {
  3334. var tags = temp.tags.toLowerCase().split(';');
  3335. for (var j = 0; j < tags.length; j++)
  3336. {
  3337. if (tagsList[tags[j]] == null)
  3338. {
  3339. tagsList[tags[j]] = [];
  3340. }
  3341. tagsList[tags[j]].push(temp);
  3342. }
  3343. }
  3344. }
  3345. }
  3346. }
  3347. NewDialog.tagsList[templateFile] = tagsList;
  3348. }
  3349. var tmp = searchTerms.toLowerCase().split(' ');
  3350. tagsList = NewDialog.tagsList[templateFile];
  3351. if (customCatCount > 0 && tagsList.__tagsList__ == null)
  3352. {
  3353. for (var cat in customCats)
  3354. {
  3355. var templateList = customCats[cat];
  3356. for (var i = 0; i < templateList.length; i++)
  3357. {
  3358. var temp = templateList[i];
  3359. var tags = temp.title.split(' ');
  3360. tags.push(cat);
  3361. for (var j = 0; j < tags.length; j++)
  3362. {
  3363. var tag = tags[j].toLowerCase();
  3364. if (tagsList[tag] == null)
  3365. {
  3366. tagsList[tag] = [];
  3367. }
  3368. tagsList[tag].push(temp);
  3369. }
  3370. }
  3371. }
  3372. tagsList.__tagsList__ = true;
  3373. }
  3374. var results = [], resMap = {}, index = 0;
  3375. for (var i = 0; i < tmp.length; i++)
  3376. {
  3377. if (tmp[i].length > 0)
  3378. {
  3379. var list = tagsList[tmp[i]];
  3380. var tmpResMap = {};
  3381. results = [];
  3382. if (list != null)
  3383. {
  3384. for (var j = 0; j < list.length; j++)
  3385. {
  3386. var temp = list[j];
  3387. //ANDing terms
  3388. if ((index == 0) == (resMap[temp.url] == null))
  3389. {
  3390. tmpResMap[temp.url] = true;
  3391. results.push(temp);
  3392. }
  3393. }
  3394. }
  3395. resMap = tmpResMap;
  3396. index++;
  3397. }
  3398. }
  3399. div.scrollTop = 0;
  3400. div.innerText = '';
  3401. i0 = 0;
  3402. var msgDiv = document.createElement('div');
  3403. msgDiv.style.cssText = 'border: 1px solid #D3D3D3; padding: 6px; background: #F5F5F5;';
  3404. mxUtils.write(msgDiv, mxResources.get(results.length == 0 ? 'noResultsFor' : 'resultsFor', [searchTerms]));
  3405. div.appendChild(msgDiv);
  3406. if (currentEntry != null && lastEntry == null)
  3407. {
  3408. currentEntry.style.backgroundColor = '';
  3409. lastEntry = currentEntry;
  3410. currentEntry = msgDiv; //To prevebt NPE later
  3411. }
  3412. templates = results;
  3413. oldTemplates = null;
  3414. addTemplates(false);
  3415. };
  3416. function initUi()
  3417. {
  3418. if (firstInitUi)
  3419. {
  3420. firstInitUi = false;
  3421. mxEvent.addListener(div, 'scroll', function(evt)
  3422. {
  3423. if (div.scrollTop + div.clientHeight >= div.scrollHeight)
  3424. {
  3425. addTemplates();
  3426. mxEvent.consume(evt);
  3427. }
  3428. });
  3429. }
  3430. if (customCatCount > 0)
  3431. {
  3432. var titleCss = 'font-weight: bold;background: #f9f9f9;padding: 5px 0 5px 0;text-align: center;';
  3433. var title = document.createElement('div');
  3434. title.style.cssText = titleCss;
  3435. mxUtils.write(title, mxResources.get('custom'));
  3436. list.appendChild(title);
  3437. for (var cat in customCats)
  3438. {
  3439. var entry = document.createElement('div');
  3440. var label = cat;
  3441. var templateList = customCats[cat];
  3442. if (label.length > 18)
  3443. {
  3444. label = label.substring(0, 18) + '&hellip;';
  3445. }
  3446. entry.style.cssText = 'display:block;cursor:pointer;padding:6px;white-space:nowrap;margin-bottom:-1px;overflow:hidden;text-overflow:ellipsis;user-select:none;';
  3447. entry.setAttribute('title', label + ' (' + templateList.length + ')');
  3448. mxUtils.write(entry, entry.getAttribute('title'));
  3449. if (itemPadding != null)
  3450. {
  3451. entry.style.padding = itemPadding;
  3452. }
  3453. list.appendChild(entry);
  3454. (function(cat2, entry2)
  3455. {
  3456. mxEvent.addListener(entry, 'click', function()
  3457. {
  3458. if (currentEntry != entry2)
  3459. {
  3460. currentEntry.style.backgroundColor = '';
  3461. currentEntry = entry2;
  3462. currentEntry.style.backgroundColor = leftHighlight;
  3463. div.scrollTop = 0;
  3464. div.innerText = '';
  3465. i0 = 0;
  3466. templates = customCats[cat2];
  3467. oldTemplates = null;
  3468. addTemplates(false);
  3469. }
  3470. });
  3471. })(cat, entry);
  3472. }
  3473. title = document.createElement('div');
  3474. title.style.cssText = titleCss;
  3475. mxUtils.write(title, 'draw.io');
  3476. list.appendChild(title);
  3477. }
  3478. function getEntryTitle(cat, templateList)
  3479. {
  3480. var label = mxResources.get(cat, null,
  3481. cat.substring(0, 1).toUpperCase() +
  3482. cat.substring(1));
  3483. if (label.length > 18)
  3484. {
  3485. label = label.substring(0, 18) + '&hellip;';
  3486. }
  3487. return label + ((templateList != null) ?
  3488. ' (' + templateList.length + ')' : '');
  3489. };
  3490. function addEntryHandler(cat, entry, subCat)
  3491. {
  3492. mxEvent.addListener(entry, 'click', function()
  3493. {
  3494. if (currentEntry != entry)
  3495. {
  3496. currentEntry.style.backgroundColor = '';
  3497. currentEntry = entry;
  3498. currentEntry.style.backgroundColor = leftHighlight;
  3499. div.scrollTop = 0;
  3500. div.innerText = '';
  3501. i0 = 0;
  3502. if (categories[cat].content != null)
  3503. {
  3504. div.appendChild(categories[cat].content);
  3505. templateXml = lastAiXml;
  3506. templates = null;
  3507. }
  3508. else
  3509. {
  3510. templates = subCat? subCategories[cat][subCat] : categories[cat];
  3511. oldTemplates = null;
  3512. addTemplates(false);
  3513. }
  3514. }
  3515. });
  3516. };
  3517. for (var cat in categories)
  3518. {
  3519. if (categories[cat].content != null)
  3520. {
  3521. var entry = document.createElement(subCats? 'ul' : 'div');
  3522. var title = getEntryTitle(cat);
  3523. entry.style.cssText = 'display:block;cursor:pointer;padding:6px;white-space:nowrap;margin-bottom:-1px;overflow:hidden;text-overflow:ellipsis;user-select:none;transition: all 0.5s;';
  3524. entry.setAttribute('title', title);
  3525. mxUtils.write(entry, title);
  3526. list.appendChild(entry);
  3527. addEntryHandler(cat, entry);
  3528. }
  3529. else
  3530. {
  3531. var subCats = subCategories[cat];
  3532. var entry = document.createElement(subCats? 'ul' : 'div');
  3533. var clickElem = entry;
  3534. var templateList = categories[cat];
  3535. var entryTitle = getEntryTitle(cat, templateList);
  3536. if (subCats != null)
  3537. {
  3538. var entryLi = document.createElement('li');
  3539. var entryDiv = document.createElement('div');
  3540. entryDiv.className = 'geTempTreeCaret';
  3541. entryDiv.setAttribute('title', entryTitle);
  3542. mxUtils.write(entryDiv, entryTitle);
  3543. clickElem = entryDiv;
  3544. entryLi.appendChild(entryDiv);
  3545. //We support one level deep only
  3546. var subUl = document.createElement('ul');
  3547. subUl.className = 'geTempTreeNested';
  3548. subUl.style.visibility = 'hidden';
  3549. for (var subCat in subCats)
  3550. {
  3551. var subLi = document.createElement('li');
  3552. var subTitle = getEntryTitle(subCat, subCats[subCat]);
  3553. subLi.setAttribute('title', subTitle);
  3554. mxUtils.write(subLi, subTitle);
  3555. addEntryHandler(cat, subLi, subCat);
  3556. subUl.appendChild(subLi);
  3557. }
  3558. entryLi.appendChild(subUl);
  3559. entry.className = 'geTempTree';
  3560. entry.appendChild(entryLi);
  3561. (function(subUl2, entryDiv2)
  3562. {
  3563. mxEvent.addListener(entryDiv2, 'click', function()
  3564. {
  3565. subUl2.style.visibility = 'visible';
  3566. subUl2.classList.toggle('geTempTreeActive');
  3567. if (subUl2.classList.toggle('geTempTreeNested'))
  3568. {
  3569. //Must hide sub elements to allow click on elements above it
  3570. setTimeout(function()
  3571. {
  3572. subUl2.style.visibility = 'hidden';
  3573. }, 550);
  3574. }
  3575. entryDiv2.classList.toggle('geTempTreeCaret-down');
  3576. });
  3577. })(subUl, entryDiv);
  3578. }
  3579. else
  3580. {
  3581. entry.style.cssText = 'display:block;cursor:pointer;padding:6px;white-space:nowrap;margin-bottom:-1px;overflow:hidden;text-overflow:ellipsis;user-select:none;transition: all 0.5s;';
  3582. entry.setAttribute('title', entryTitle);
  3583. mxUtils.write(entry, entryTitle);
  3584. }
  3585. if (itemPadding != null)
  3586. {
  3587. entry.style.padding = itemPadding;
  3588. }
  3589. list.appendChild(entry);
  3590. if (currentEntry == null && templateList.length > 0)
  3591. {
  3592. currentEntry = entry;
  3593. currentEntry.style.backgroundColor = leftHighlight;
  3594. templates = templateList;
  3595. }
  3596. addEntryHandler(cat, clickElem);
  3597. }
  3598. }
  3599. addTemplates(false);
  3600. };
  3601. if (!compact)
  3602. {
  3603. outer.appendChild(searchBox);
  3604. outer.appendChild(list);
  3605. outer.appendChild(div);
  3606. var indexLoaded = false;
  3607. var realUrl = templateFile;
  3608. if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl))
  3609. {
  3610. realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl);
  3611. }
  3612. function loadDrawioTemplates()
  3613. {
  3614. mxUtils.get(realUrl, function(req)
  3615. {
  3616. // Workaround for index loaded 3 times in iOS offline mode
  3617. if (!indexLoaded)
  3618. {
  3619. indexLoaded = true;
  3620. var tmpDoc = req.getXml();
  3621. var node = tmpDoc.documentElement.firstChild;
  3622. var clibs = {};
  3623. while (node != null)
  3624. {
  3625. if (typeof(node.getAttribute) !== 'undefined')
  3626. {
  3627. if (node.nodeName == 'clibs')
  3628. {
  3629. var name = node.getAttribute('name');
  3630. var adds = node.getElementsByTagName('add');
  3631. var temp = [];
  3632. for (var i = 0; i < adds.length; i++)
  3633. {
  3634. temp.push(encodeURIComponent(mxUtils.getTextContent(adds[i])));
  3635. }
  3636. if (name != null && temp.length > 0)
  3637. {
  3638. clibs[name] = temp.join(';');
  3639. }
  3640. }
  3641. else
  3642. {
  3643. var url = node.getAttribute('url');
  3644. if (url != null)
  3645. {
  3646. var category = node.getAttribute('section');
  3647. var subCategory = node.getAttribute('subsection');
  3648. if (category == null)
  3649. {
  3650. var slash = url.indexOf('/');
  3651. category = url.substring(0, slash);
  3652. if (subCategory == null)
  3653. {
  3654. var nextSlash = url.indexOf('/', slash + 1);
  3655. if (nextSlash > -1)
  3656. {
  3657. subCategory = url.substring(slash + 1, nextSlash);
  3658. }
  3659. }
  3660. }
  3661. var list = categories[category];
  3662. if (list == null)
  3663. {
  3664. list = [];
  3665. categories[category] = list;
  3666. }
  3667. var tempLibs = node.getAttribute('clibs');
  3668. if (clibs[tempLibs] != null)
  3669. {
  3670. tempLibs = clibs[tempLibs];
  3671. }
  3672. var tempObj = {url: node.getAttribute('url'), libs: node.getAttribute('libs'),
  3673. title: node.getAttribute('title'), tooltip: node.getAttribute('name') || node.getAttribute('url'),
  3674. preview: node.getAttribute('preview'), clibs: tempLibs, tags: node.getAttribute('tags')};
  3675. list.push(tempObj);
  3676. if (subCategory != null)
  3677. {
  3678. var subCats = subCategories[category];
  3679. if (subCats == null)
  3680. {
  3681. subCats = {};
  3682. subCategories[category] = subCats;
  3683. }
  3684. var subCatList = subCats[subCategory];
  3685. if (subCatList == null)
  3686. {
  3687. subCatList = [];
  3688. subCats[subCategory] = subCatList;
  3689. }
  3690. subCatList.push(tempObj);
  3691. }
  3692. }
  3693. }
  3694. }
  3695. node = node.nextSibling;
  3696. }
  3697. spinner.stop();
  3698. initUi();
  3699. }
  3700. });
  3701. };
  3702. spinner.spin(div);
  3703. if (customTempCallback != null)
  3704. {
  3705. customTempCallback(function(cats, count)
  3706. {
  3707. customCats = cats;
  3708. customCatCount = count;
  3709. //Custom templates doesn't change after being loaded, so cache them here. Also, only count is overridden
  3710. origCustomCatCount = count;
  3711. loadDrawioTemplates();
  3712. },
  3713. loadDrawioTemplates); //In case of an error, just load draw.io templates only
  3714. }
  3715. else
  3716. {
  3717. loadDrawioTemplates();
  3718. }
  3719. //draw.io templates doesn't change after being loaded, so cache them here
  3720. origCategories = categories;
  3721. }
  3722. mxEvent.addListener(nameInput, 'keypress', function(e)
  3723. {
  3724. if (editorUi.dialog.container.firstChild == outer &&
  3725. e.keyCode == 13)
  3726. {
  3727. create();
  3728. }
  3729. });
  3730. var btns = document.createElement('div');
  3731. btns.style.marginTop = (compact) ? '4px' : '16px';
  3732. btns.style.textAlign = 'right';
  3733. btns.style.position = 'absolute';
  3734. btns.style.left = '40px';
  3735. btns.style.bottom = '24px';
  3736. btns.style.right = '40px';
  3737. if (!compact && !editorUi.isOffline() && showName && callback == null && !createOnly)
  3738. {
  3739. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  3740. {
  3741. editorUi.openLink('https://support.draw.io/display/DO/Creating+and+Opening+Files');
  3742. });
  3743. helpBtn.className = 'geBtn';
  3744. btns.appendChild(helpBtn);
  3745. }
  3746. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  3747. {
  3748. if (cancelCallback != null)
  3749. {
  3750. cancelCallback();
  3751. }
  3752. editorUi.hideDialog(true);
  3753. });
  3754. cancelBtn.className = 'geBtn';
  3755. if (editorUi.editor.cancelFirst && (!createOnly || cancelCallback != null))
  3756. {
  3757. btns.appendChild(cancelBtn);
  3758. }
  3759. if (!compact && urlParams['embed'] != '1' && !createOnly && !mxClient.IS_ANDROID &&
  3760. !mxClient.IS_IOS && urlParams['noDevice'] != '1')
  3761. {
  3762. var fromTmpBtn = mxUtils.button(mxResources.get('fromTemplateUrl'), function()
  3763. {
  3764. var dlg = new FilenameDialog(editorUi, '', mxResources.get('create'), function(fileUrl)
  3765. {
  3766. if (fileUrl != null && fileUrl.length > 0)
  3767. {
  3768. editorUi.editor.loadUrl(editorUi.editor.getProxiedUrl(fileUrl), function(data)
  3769. {
  3770. templateXml = data;
  3771. templateLibs = null;
  3772. templateRealURl = fileUrl;
  3773. editorUi.hideDialog();
  3774. create();
  3775. }, function(err)
  3776. {
  3777. editorUi.handleError(err);
  3778. });
  3779. }
  3780. }, mxResources.get('url'), null, null, null, false);
  3781. editorUi.showDialog(dlg.container, 300, 80, true, true);
  3782. dlg.init();
  3783. });
  3784. fromTmpBtn.className = 'geBtn';
  3785. btns.appendChild(fromTmpBtn);
  3786. }
  3787. if (Graph.fileSupport && showImport)
  3788. {
  3789. var importBtn = mxUtils.button(mxResources.get('import'), function()
  3790. {
  3791. if (editorUi.newDlgFileInputElt == null)
  3792. {
  3793. var fileInput = document.createElement('input');
  3794. fileInput.setAttribute('multiple', 'multiple');
  3795. fileInput.setAttribute('type', 'file');
  3796. mxEvent.addListener(fileInput, 'change', function(evt)
  3797. {
  3798. editorUi.openFiles(fileInput.files, true);
  3799. fileInput.value = '';
  3800. });
  3801. fileInput.style.display = 'none';
  3802. document.body.appendChild(fileInput);
  3803. editorUi.newDlgFileInputElt = fileInput;
  3804. }
  3805. editorUi.newDlgFileInputElt.click();
  3806. });
  3807. importBtn.className = 'geBtn';
  3808. btns.appendChild(importBtn);
  3809. }
  3810. btns.appendChild(createButton);
  3811. if (!editorUi.editor.cancelFirst && callback == null && (!createOnly || cancelCallback != null))
  3812. {
  3813. btns.appendChild(cancelBtn);
  3814. }
  3815. outer.appendChild(btns);
  3816. this.container = outer;
  3817. };
  3818. NewDialog.tagsList = {};
  3819. /**
  3820. * Constructs a dialog for creating new files from a template URL.
  3821. * Also used for dialog choosing where to save or export resources
  3822. */
  3823. var CreateDialog = function(editorUi, title, createFn, cancelFn, dlgTitle, btnLabel, overrideExtension, allowBrowser,
  3824. allowTab, helpLink, showDeviceButton, rowLimit, data, mimeType, base64Encoded, hints, hideDialog)
  3825. {
  3826. showDeviceButton = urlParams['noDevice'] == '1'? false : showDeviceButton;
  3827. overrideExtension = (overrideExtension != null) ? overrideExtension : true;
  3828. allowBrowser = (allowBrowser != null) ? allowBrowser : true;
  3829. rowLimit = (rowLimit != null) ? rowLimit : 4;
  3830. hideDialog = (hideDialog != null) ? hideDialog : true;
  3831. var div = document.createElement('div');
  3832. div.style.whiteSpace = 'nowrap';
  3833. var showButtons = true;
  3834. if (cancelFn == null)
  3835. {
  3836. editorUi.addLanguageMenu(div);
  3837. }
  3838. var h3 = document.createElement('h2');
  3839. mxUtils.write(h3, dlgTitle || mxResources.get('create'));
  3840. h3.style.marginTop = '0px';
  3841. h3.style.marginBottom = '24px';
  3842. div.appendChild(h3);
  3843. mxUtils.write(div, mxResources.get('filename') + ':');
  3844. var nameInput = document.createElement('input');
  3845. nameInput.setAttribute('value', title);
  3846. nameInput.style.width = '200px';
  3847. nameInput.style.marginLeft = '10px';
  3848. nameInput.style.marginBottom = '20px';
  3849. nameInput.style.maxWidth = '70%';
  3850. this.init = function()
  3851. {
  3852. nameInput.focus();
  3853. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  3854. {
  3855. nameInput.select();
  3856. }
  3857. else
  3858. {
  3859. document.execCommand('selectAll', false, null);
  3860. }
  3861. };
  3862. div.appendChild(nameInput);
  3863. if (hints != null)
  3864. {
  3865. if (editorUi.editor.diagramFileTypes != null)
  3866. {
  3867. var typeSelect = FilenameDialog.createFileTypes(editorUi, nameInput, editorUi.editor.diagramFileTypes);
  3868. typeSelect.style.marginLeft = '6px';
  3869. typeSelect.style.width = '90px';
  3870. div.appendChild(typeSelect);
  3871. }
  3872. div.appendChild(FilenameDialog.createTypeHint(editorUi, nameInput, hints));
  3873. }
  3874. var copyBtn = null;
  3875. // Disables SVG preview if SVG is not supported in browser
  3876. if (urlParams['noDevice'] != '1' && data != null && mimeType != null && (mimeType.substring(0, 6) == 'image/' &&
  3877. (mimeType.substring(0, 9) != 'image/svg' || mxClient.IS_SVG)))
  3878. {
  3879. nameInput.style.width = '160px';
  3880. var preview = document.createElement('img');
  3881. var temp = (base64Encoded) ? data : btoa(unescape(encodeURIComponent(data)));
  3882. preview.setAttribute('src', 'data:' + mimeType + ';base64,' + temp);
  3883. preview.style.position = 'absolute';
  3884. preview.style.top = '70px';
  3885. preview.style.right = '100px';
  3886. preview.style.maxWidth = '120px';
  3887. preview.style.maxHeight = '80px';
  3888. mxUtils.setPrefixedStyle(preview.style, 'transform',
  3889. 'translate(50%,-50%)');
  3890. div.appendChild(preview);
  3891. if (!mxClient.IS_FF && mimeType == 'image/png' && navigator.clipboard != null &&
  3892. typeof window.ClipboardItem === 'function')
  3893. {
  3894. copyBtn = mxUtils.button(mxResources.get('copy'), function(evt)
  3895. {
  3896. var blob = editorUi.base64ToBlob(temp, 'image/png');
  3897. var html = '<img src="' + 'data:' + mimeType + ';base64,' + temp + '">';
  3898. var cbi = new ClipboardItem({'image/png': blob,
  3899. 'text/html': new Blob([html], {type: 'text/html'})});
  3900. navigator.clipboard.write([cbi]).then(mxUtils.bind(this, function()
  3901. {
  3902. editorUi.alert(mxResources.get('copiedToClipboard'));
  3903. }))['catch'](mxUtils.bind(this, function(e)
  3904. {
  3905. editorUi.handleError(e);
  3906. }));
  3907. });
  3908. copyBtn.style.marginTop = '6px';
  3909. copyBtn.className = 'geBtn';
  3910. }
  3911. if (allowTab && Editor.popupsAllowed)
  3912. {
  3913. preview.style.cursor = 'pointer';
  3914. mxEvent.addGestureListeners(preview, null, null, function(evt)
  3915. {
  3916. if (!mxEvent.isPopupTrigger(evt))
  3917. {
  3918. create('_blank');
  3919. }
  3920. });
  3921. }
  3922. }
  3923. mxUtils.br(div);
  3924. var buttons = document.createElement('div');
  3925. buttons.style.textAlign = 'center';
  3926. var count = 0;
  3927. function addLogo(img, title, mode, clientName)
  3928. {
  3929. var button = document.createElement('a');
  3930. button.style.overflow = 'hidden';
  3931. var logo = document.createElement('img');
  3932. logo.src = img;
  3933. logo.setAttribute('border', '0');
  3934. logo.setAttribute('align', 'absmiddle');
  3935. logo.style.width = '60px';
  3936. logo.style.height = '60px';
  3937. logo.style.paddingBottom = '6px';
  3938. button.style.display = 'inline-block';
  3939. button.className = 'geBaseButton';
  3940. button.style.position = 'relative';
  3941. button.style.margin = '4px';
  3942. button.style.padding = '8px 8px 10px 8px';
  3943. button.style.whiteSpace = 'nowrap';
  3944. button.appendChild(logo);
  3945. button.style.color = 'gray';
  3946. button.style.fontSize = '11px';
  3947. var label = document.createElement('div');
  3948. button.appendChild(label);
  3949. mxUtils.write(label, title);
  3950. function initButton()
  3951. {
  3952. mxEvent.addListener(button, 'click', function()
  3953. {
  3954. // Updates extension
  3955. change(mode);
  3956. create(mode);
  3957. });
  3958. };
  3959. // Supports lazy loading
  3960. if (clientName != null && editorUi[clientName] == null)
  3961. {
  3962. logo.style.visibility = 'hidden';
  3963. mxUtils.setOpacity(label, 10);
  3964. var size = 12;
  3965. var spinner = new Spinner({
  3966. lines: 12, // The number of lines to draw
  3967. length: size, // The length of each line
  3968. width: 5, // The line thickness
  3969. radius: 10, // The radius of the inner circle
  3970. rotate: 0, // The rotation offset
  3971. color: '#000', // #rgb or #rrggbb
  3972. speed: 1.5, // Rounds per second
  3973. trail: 60, // Afterglow percentage
  3974. shadow: false, // Whether to render a shadow
  3975. hwaccel: false, // Whether to use hardware acceleration
  3976. top: '40%',
  3977. zIndex: 2e9 // The z-index (defaults to 2000000000)
  3978. });
  3979. spinner.spin(button);
  3980. // Timeout after 30 secs
  3981. var timeout = window.setTimeout(function()
  3982. {
  3983. if (editorUi[clientName] == null)
  3984. {
  3985. spinner.stop();
  3986. button.style.display = 'none';
  3987. }
  3988. }, 30000);
  3989. editorUi.addListener('clientLoaded', mxUtils.bind(this, function()
  3990. {
  3991. if (editorUi[clientName] != null)
  3992. {
  3993. window.clearTimeout(timeout);
  3994. mxUtils.setOpacity(label, 100);
  3995. logo.style.visibility = '';
  3996. spinner.stop();
  3997. initButton();
  3998. }
  3999. }));
  4000. }
  4001. else
  4002. {
  4003. initButton();
  4004. }
  4005. buttons.appendChild(button);
  4006. if (++count == rowLimit)
  4007. {
  4008. mxUtils.br(buttons);
  4009. count = 0;
  4010. }
  4011. };
  4012. if (!showButtons)
  4013. {
  4014. mxUtils.write(div, mxResources.get('chooseAnOption') + ':');
  4015. }
  4016. else
  4017. {
  4018. buttons.style.marginTop = '6px';
  4019. div.appendChild(buttons);
  4020. }
  4021. // Adds all papersize options
  4022. var serviceSelect = document.createElement('select');
  4023. serviceSelect.style.marginLeft = '10px';
  4024. if (!editorUi.isOfflineApp() && !editorUi.isOffline())
  4025. {
  4026. if (typeof window.DriveClient === 'function')
  4027. {
  4028. var googleOption = document.createElement('option');
  4029. googleOption.setAttribute('value', App.MODE_GOOGLE);
  4030. mxUtils.write(googleOption, mxResources.get('googleDrive'));
  4031. serviceSelect.appendChild(googleOption);
  4032. addLogo(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googleDrive'), App.MODE_GOOGLE, 'drive');
  4033. }
  4034. if (typeof window.OneDriveClient === 'function')
  4035. {
  4036. var oneDriveOption = document.createElement('option');
  4037. oneDriveOption.setAttribute('value', App.MODE_ONEDRIVE);
  4038. mxUtils.write(oneDriveOption, mxResources.get('oneDrive'));
  4039. serviceSelect.appendChild(oneDriveOption);
  4040. if (editorUi.mode == App.MODE_ONEDRIVE)
  4041. {
  4042. oneDriveOption.setAttribute('selected', 'selected');
  4043. }
  4044. addLogo(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), App.MODE_ONEDRIVE, 'oneDrive');
  4045. }
  4046. if (typeof window.DropboxClient === 'function')
  4047. {
  4048. var dropboxOption = document.createElement('option');
  4049. dropboxOption.setAttribute('value', App.MODE_DROPBOX);
  4050. mxUtils.write(dropboxOption, mxResources.get('dropbox'));
  4051. serviceSelect.appendChild(dropboxOption);
  4052. if (editorUi.mode == App.MODE_DROPBOX)
  4053. {
  4054. dropboxOption.setAttribute('selected', 'selected');
  4055. }
  4056. addLogo(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), App.MODE_DROPBOX, 'dropbox');
  4057. }
  4058. if (editorUi.gitHub != null)
  4059. {
  4060. var gitHubOption = document.createElement('option');
  4061. gitHubOption.setAttribute('value', App.MODE_GITHUB);
  4062. mxUtils.write(gitHubOption, mxResources.get('github'));
  4063. serviceSelect.appendChild(gitHubOption);
  4064. addLogo(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), App.MODE_GITHUB, 'gitHub');
  4065. }
  4066. if (editorUi.gitLab != null)
  4067. {
  4068. var gitLabOption = document.createElement('option');
  4069. gitLabOption.setAttribute('value', App.MODE_GITLAB);
  4070. mxUtils.write(gitLabOption, mxResources.get('gitlab'));
  4071. serviceSelect.appendChild(gitLabOption);
  4072. addLogo(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), App.MODE_GITLAB, 'gitLab');
  4073. }
  4074. if (typeof window.TrelloClient === 'function')
  4075. {
  4076. var trelloOption = document.createElement('option');
  4077. trelloOption.setAttribute('value', App.MODE_TRELLO);
  4078. mxUtils.write(trelloOption, mxResources.get('trello'));
  4079. serviceSelect.appendChild(trelloOption);
  4080. addLogo(IMAGE_PATH + '/trello-logo.svg', mxResources.get('trello'), App.MODE_TRELLO, 'trello');
  4081. }
  4082. }
  4083. if (!Editor.useLocalStorage || urlParams['storage'] == 'device' ||
  4084. (editorUi.getCurrentFile() != null/* && !mxClient.IS_IOS*/ && urlParams['noDevice'] != '1'))
  4085. {
  4086. var deviceOption = document.createElement('option');
  4087. deviceOption.setAttribute('value', App.MODE_DEVICE);
  4088. mxUtils.write(deviceOption, mxResources.get('device'));
  4089. serviceSelect.appendChild(deviceOption);
  4090. if (editorUi.mode == App.MODE_DEVICE || !allowBrowser)
  4091. {
  4092. deviceOption.setAttribute('selected', 'selected');
  4093. }
  4094. if (showDeviceButton)
  4095. {
  4096. addLogo(IMAGE_PATH + '/osa_drive-harddisk.png', mxResources.get('device'), App.MODE_DEVICE);
  4097. }
  4098. }
  4099. if (allowBrowser && isLocalStorage && urlParams['browser'] != '0')
  4100. {
  4101. var browserOption = document.createElement('option');
  4102. browserOption.setAttribute('value', App.MODE_BROWSER);
  4103. mxUtils.write(browserOption, mxResources.get('browser'));
  4104. serviceSelect.appendChild(browserOption);
  4105. if (editorUi.mode == App.MODE_BROWSER)
  4106. {
  4107. browserOption.setAttribute('selected', 'selected');
  4108. }
  4109. addLogo(IMAGE_PATH + '/osa_database.png', mxResources.get('browser'), App.MODE_BROWSER);
  4110. }
  4111. function change(newMode)
  4112. {
  4113. if (overrideExtension)
  4114. {
  4115. var fn = nameInput.value;
  4116. var idx = fn.lastIndexOf('.');
  4117. if (title.lastIndexOf('.') < 0 && (!showButtons || idx < 0))
  4118. {
  4119. newMode = (newMode != null) ? newMode : serviceSelect.value;
  4120. var ext = '';
  4121. if (newMode == App.MODE_GOOGLE)
  4122. {
  4123. ext = editorUi.drive.extension;
  4124. }
  4125. else if (newMode == App.MODE_GITHUB)
  4126. {
  4127. ext = editorUi.gitHub.extension;
  4128. }
  4129. else if (newMode == App.MODE_GITLAB)
  4130. {
  4131. ext = editorUi.gitLab.extension;
  4132. }
  4133. else if (newMode == App.MODE_TRELLO)
  4134. {
  4135. ext = editorUi.trello.extension;
  4136. }
  4137. else if (newMode == App.MODE_DROPBOX)
  4138. {
  4139. ext = editorUi.dropbox.extension;
  4140. }
  4141. else if (newMode == App.MODE_ONEDRIVE)
  4142. {
  4143. ext = editorUi.oneDrive.extension;
  4144. }
  4145. else if (newMode == App.MODE_DEVICE)
  4146. {
  4147. ext = '.drawio';
  4148. }
  4149. if (idx >= 0)
  4150. {
  4151. fn = fn.substring(0, idx);
  4152. }
  4153. nameInput.value = fn + ext;
  4154. }
  4155. }
  4156. };
  4157. var btns = document.createElement('div');
  4158. btns.style.marginTop = (showButtons) ? '26px' : '38px';
  4159. btns.style.textAlign = 'center';
  4160. if (!showButtons)
  4161. {
  4162. div.appendChild(serviceSelect);
  4163. mxEvent.addListener(serviceSelect, 'change', change);
  4164. change();
  4165. }
  4166. if (helpLink != null)
  4167. {
  4168. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  4169. {
  4170. editorUi.openLink(helpLink);
  4171. });
  4172. helpBtn.className = 'geBtn';
  4173. btns.appendChild(helpBtn);
  4174. }
  4175. var cancelBtn = mxUtils.button(mxResources.get((cancelFn != null) ? 'close' : 'cancel'), function()
  4176. {
  4177. if (cancelFn != null)
  4178. {
  4179. cancelFn();
  4180. }
  4181. else
  4182. {
  4183. editorUi.fileLoaded(null);
  4184. editorUi.hideDialog();
  4185. window.close();
  4186. window.location.href = editorUi.getUrl();
  4187. }
  4188. });
  4189. cancelBtn.className = 'geBtn';
  4190. if (editorUi.editor.cancelFirst && cancelFn == null)
  4191. {
  4192. btns.appendChild(cancelBtn);
  4193. }
  4194. function create(mode)
  4195. {
  4196. var title = nameInput.value;
  4197. if (mode == null || (title != null && title.length > 0))
  4198. {
  4199. if (hideDialog)
  4200. {
  4201. editorUi.hideDialog();
  4202. }
  4203. createFn(title, mode, nameInput);
  4204. };
  4205. }
  4206. if (cancelFn == null)
  4207. {
  4208. var laterBtn = mxUtils.button(mxResources.get('decideLater'), function()
  4209. {
  4210. create(null);
  4211. });
  4212. laterBtn.className = 'geBtn';
  4213. btns.appendChild(laterBtn);
  4214. }
  4215. if (allowTab && Editor.popupsAllowed)
  4216. {
  4217. var openBtn = mxUtils.button(mxResources.get('openInNewWindow'), function()
  4218. {
  4219. create('_blank');
  4220. });
  4221. openBtn.className = 'geBtn';
  4222. btns.appendChild(openBtn);
  4223. }
  4224. if (CreateDialog.showDownloadButton)
  4225. {
  4226. var downloadButton = mxUtils.button(mxResources.get('download'), function()
  4227. {
  4228. create('download');
  4229. });
  4230. downloadButton.className = 'geBtn';
  4231. btns.appendChild(downloadButton);
  4232. if (copyBtn != null)
  4233. {
  4234. downloadButton.style.marginTop = '6px';
  4235. btns.style.marginTop = '6px';
  4236. }
  4237. }
  4238. if (copyBtn != null)
  4239. {
  4240. mxUtils.br(btns);
  4241. btns.appendChild(copyBtn);
  4242. }
  4243. if (/*!mxClient.IS_IOS || */!showButtons)
  4244. {
  4245. var createBtn = mxUtils.button(btnLabel || mxResources.get('create'), function()
  4246. {
  4247. create((showDeviceButton) ? 'download' : ((showButtons) ? App.MODE_DEVICE : serviceSelect.value));
  4248. });
  4249. createBtn.className = 'geBtn gePrimaryBtn';
  4250. btns.appendChild(createBtn);
  4251. }
  4252. if (!editorUi.editor.cancelFirst || cancelFn != null)
  4253. {
  4254. btns.appendChild(cancelBtn);
  4255. }
  4256. mxEvent.addListener(nameInput, 'keypress', function(e)
  4257. {
  4258. if (e.keyCode == 13)
  4259. {
  4260. create((showButtons) ? App.MODE_DEVICE : serviceSelect.value);
  4261. }
  4262. else if (e.keyCode == 27)
  4263. {
  4264. editorUi.fileLoaded(null);
  4265. editorUi.hideDialog();
  4266. window.close();
  4267. }
  4268. });
  4269. div.appendChild(btns);
  4270. this.container = div;
  4271. };
  4272. /**
  4273. *
  4274. */
  4275. CreateDialog.showDownloadButton = urlParams['noDevice'] != '1';
  4276. /**
  4277. * Constructs a new popup dialog.
  4278. */
  4279. var PopupDialog = function(editorUi, url, pre, fallback, hideDialog)
  4280. {
  4281. hideDialog = (hideDialog != null) ? hideDialog : true;
  4282. var div = document.createElement('div');
  4283. div.style.textAlign = 'left';
  4284. div.style.height = '100%';
  4285. mxUtils.write(div, mxResources.get('fileOpenLocation'));
  4286. mxUtils.br(div);
  4287. mxUtils.br(div);
  4288. var replaceBtn = mxUtils.button(mxResources.get('openInThisWindow'), function()
  4289. {
  4290. if (hideDialog)
  4291. {
  4292. editorUi.hideDialog();
  4293. }
  4294. if (fallback != null)
  4295. {
  4296. fallback();
  4297. }
  4298. });
  4299. replaceBtn.className = 'geBtn';
  4300. replaceBtn.style.marginBottom = '8px';
  4301. replaceBtn.style.width = '280px';
  4302. div.appendChild(replaceBtn);
  4303. mxUtils.br(div);
  4304. var wndBtn = mxUtils.button(mxResources.get('openInNewWindow'), function()
  4305. {
  4306. if (hideDialog)
  4307. {
  4308. editorUi.hideDialog();
  4309. }
  4310. if (pre != null)
  4311. {
  4312. pre();
  4313. }
  4314. editorUi.openLink(url, null, true);
  4315. });
  4316. wndBtn.className = 'geBtn gePrimaryBtn';
  4317. wndBtn.style.width = replaceBtn.style.width;
  4318. div.appendChild(wndBtn);
  4319. mxUtils.br(div);
  4320. mxUtils.br(div);
  4321. mxUtils.write(div, mxResources.get('allowPopups'));
  4322. this.container = div;
  4323. };
  4324. /**
  4325. * Constructs a new image dialog.
  4326. */
  4327. var ImageDialog = function(editorUi, title, initialValue, fn, ignoreExisting, convertDataUri, withCrop, initClipPath)
  4328. {
  4329. convertDataUri = (convertDataUri != null) ? convertDataUri : true;
  4330. var graph = editorUi.editor.graph;
  4331. var div = document.createElement('div');
  4332. mxUtils.write(div, title);
  4333. var inner = document.createElement('div');
  4334. inner.className = 'geTitle';
  4335. inner.style.backgroundColor = 'transparent';
  4336. inner.style.borderColor = 'transparent';
  4337. inner.style.whiteSpace = 'nowrap';
  4338. inner.style.textOverflow = 'clip';
  4339. inner.style.cursor = 'default';
  4340. inner.style.paddingRight = '20px';
  4341. var linkInput = document.createElement('input');
  4342. linkInput.setAttribute('value', initialValue);
  4343. linkInput.setAttribute('type', 'text');
  4344. linkInput.setAttribute('spellcheck', 'false');
  4345. linkInput.setAttribute('autocorrect', 'off');
  4346. linkInput.setAttribute('autocomplete', 'off');
  4347. linkInput.setAttribute('autocapitalize', 'off');
  4348. linkInput.style.marginTop = '6px';
  4349. var realWidth = (Graph.fileSupport) ? 460 : 340;
  4350. linkInput.style.width = realWidth - 20 + 'px';
  4351. linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
  4352. linkInput.style.backgroundRepeat = 'no-repeat';
  4353. linkInput.style.backgroundPosition = '100% 50%';
  4354. linkInput.style.paddingRight = '14px';
  4355. var cross = document.createElement('div');
  4356. cross.setAttribute('title', mxResources.get('reset'));
  4357. cross.style.position = 'relative';
  4358. cross.style.left = '-16px';
  4359. cross.style.width = '12px';
  4360. cross.style.height = '14px';
  4361. cross.style.cursor = 'pointer';
  4362. // Workaround for inline-block not supported in IE
  4363. cross.style.display = 'inline-block';
  4364. cross.style.top = '3px';
  4365. // Needed to block event transparency in IE
  4366. cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')';
  4367. mxEvent.addListener(cross, 'click', function()
  4368. {
  4369. linkInput.value = '';
  4370. linkInput.focus();
  4371. });
  4372. inner.appendChild(linkInput);
  4373. inner.appendChild(cross);
  4374. div.appendChild(inner);
  4375. var clipPath = initClipPath, cW, cH;
  4376. var insertImage = function(newValue, w, h, resize)
  4377. {
  4378. var dataUri = newValue.substring(0, 5) == 'data:';
  4379. if (!editorUi.isOffline() || (dataUri && typeof chrome === 'undefined'))
  4380. {
  4381. if (newValue.length > 0 && editorUi.spinner.spin(document.body, mxResources.get('inserting')))
  4382. {
  4383. var maxSize = 520;
  4384. editorUi.loadImage(newValue, function(img)
  4385. {
  4386. editorUi.spinner.stop();
  4387. editorUi.hideDialog();
  4388. var s = (resize === false) ? 1 :
  4389. (w != null && h != null) ? Math.max(w / img.width, h / img.height) :
  4390. Math.min(1, Math.min(maxSize / img.width, maxSize / img.height));
  4391. // Handles special case of data URI which needs to be rewritten
  4392. // to be used in a cell style to remove the semicolon
  4393. if (convertDataUri)
  4394. {
  4395. newValue = editorUi.convertDataUri(newValue);
  4396. }
  4397. fn(newValue, Math.round(Number(img.width) * s), Math.round(Number(img.height) * s), clipPath, cW, cH);
  4398. }, function()
  4399. {
  4400. editorUi.spinner.stop();
  4401. fn(null);
  4402. editorUi.showError(mxResources.get('error'), mxResources.get('fileNotFound'), mxResources.get('ok'));
  4403. });
  4404. }
  4405. else
  4406. {
  4407. editorUi.hideDialog();
  4408. fn(newValue, null, null, clipPath, cW, cH);
  4409. }
  4410. }
  4411. else
  4412. {
  4413. newValue = editorUi.convertDataUri(newValue);
  4414. w = (w == null) ? 120 : w;
  4415. h = (h == null) ? 100 : h;
  4416. editorUi.hideDialog();
  4417. fn(newValue, w, h, clipPath, cW, cH);
  4418. }
  4419. };
  4420. var apply = function(newValue, resize)
  4421. {
  4422. if (newValue != null)
  4423. {
  4424. var geo = (ignoreExisting) ? null : graph.getModel().getGeometry(graph.getSelectionCell());
  4425. // Reuses width and height of existing cell
  4426. if (geo != null)
  4427. {
  4428. insertImage(newValue, geo.width, geo.height, resize);
  4429. }
  4430. else
  4431. {
  4432. insertImage(newValue, null, null, resize);
  4433. }
  4434. }
  4435. else
  4436. {
  4437. editorUi.hideDialog();
  4438. fn(null);
  4439. }
  4440. };
  4441. this.init = function()
  4442. {
  4443. linkInput.focus();
  4444. // Installs drag and drop handler for local images and links
  4445. if (Graph.fileSupport)
  4446. {
  4447. linkInput.setAttribute('placeholder', mxResources.get('dragImagesHere'));
  4448. // Setup the dnd listeners
  4449. var dlg = div.parentNode;
  4450. var graph = editorUi.editor.graph;
  4451. var dropElt = null;
  4452. mxEvent.addListener(dlg, 'dragleave', function(evt)
  4453. {
  4454. if (dropElt != null)
  4455. {
  4456. dropElt.parentNode.removeChild(dropElt);
  4457. dropElt = null;
  4458. }
  4459. evt.stopPropagation();
  4460. evt.preventDefault();
  4461. });
  4462. mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
  4463. {
  4464. // IE 10 does not implement pointer-events so it can't have a drop highlight
  4465. if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10))
  4466. {
  4467. dropElt = editorUi.highlightElement(dlg);
  4468. }
  4469. evt.stopPropagation();
  4470. evt.preventDefault();
  4471. }));
  4472. mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
  4473. {
  4474. if (dropElt != null)
  4475. {
  4476. dropElt.parentNode.removeChild(dropElt);
  4477. dropElt = null;
  4478. }
  4479. if (evt.dataTransfer.files.length > 0)
  4480. {
  4481. editorUi.importFiles(evt.dataTransfer.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h, fileName, resize)
  4482. {
  4483. apply(data, resize);
  4484. }, function()
  4485. {
  4486. // No post processing
  4487. }, function(file)
  4488. {
  4489. // Handles only images
  4490. return file.type.substring(0, 6) == 'image/';
  4491. }, function(queue)
  4492. {
  4493. // Invokes elements of queue in order
  4494. for (var i = 0; i < queue.length; i++)
  4495. {
  4496. queue[i]();
  4497. }
  4498. }, !mxEvent.isControlDown(evt), null, null, true);
  4499. }
  4500. else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
  4501. {
  4502. var uri = evt.dataTransfer.getData('text/uri-list');
  4503. if ((/\.(gif|jpg|jpeg|tiff|png|svg)($|\?)/i).test(uri))
  4504. {
  4505. apply(decodeURIComponent(uri));
  4506. }
  4507. }
  4508. evt.stopPropagation();
  4509. evt.preventDefault();
  4510. }), false);
  4511. }
  4512. };
  4513. var btns = document.createElement('div');
  4514. btns.style.marginTop = '14px';
  4515. btns.style.textAlign = 'center';
  4516. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  4517. {
  4518. // Just in case a spinner is spinning, has no effect otherwise
  4519. editorUi.spinner.stop();
  4520. editorUi.hideDialog();
  4521. });
  4522. cancelBtn.className = 'geBtn';
  4523. if (editorUi.editor.cancelFirst)
  4524. {
  4525. btns.appendChild(cancelBtn);
  4526. }
  4527. ImageDialog.filePicked = function(data)
  4528. {
  4529. if (data.action == google.picker.Action.PICKED)
  4530. {
  4531. if (data.docs[0].thumbnails != null)
  4532. {
  4533. var thumb = data.docs[0].thumbnails[data.docs[0].thumbnails.length - 1];
  4534. if (thumb != null)
  4535. {
  4536. linkInput.value = thumb.url;
  4537. }
  4538. }
  4539. }
  4540. linkInput.focus();
  4541. };
  4542. if (Graph.fileSupport)
  4543. {
  4544. if (editorUi.imgDlgFileInputElt == null)
  4545. {
  4546. var fileInput = document.createElement('input');
  4547. fileInput.setAttribute('multiple', 'multiple');
  4548. fileInput.setAttribute('type', 'file');
  4549. mxEvent.addListener(fileInput, 'change', function(evt)
  4550. {
  4551. if (fileInput.files != null)
  4552. {
  4553. editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h)
  4554. {
  4555. apply(data);
  4556. }, function()
  4557. {
  4558. // No post processing
  4559. }, function(file)
  4560. {
  4561. // Handles only images
  4562. return file.type.substring(0, 6) == 'image/';
  4563. }, function(queue)
  4564. {
  4565. // Invokes elements of queue in order
  4566. for (var i = 0; i < queue.length; i++)
  4567. {
  4568. queue[i]();
  4569. }
  4570. }, true);
  4571. // Resets input to force change event for same file (type reset required for IE)
  4572. fileInput.type = '';
  4573. fileInput.type = 'file';
  4574. fileInput.value = '';
  4575. }
  4576. });
  4577. fileInput.style.display = 'none';
  4578. document.body.appendChild(fileInput);
  4579. editorUi.imgDlgFileInputElt = fileInput;
  4580. }
  4581. var btn = mxUtils.button(mxResources.get('open'), function()
  4582. {
  4583. editorUi.imgDlgFileInputElt.click();
  4584. });
  4585. btn.className = 'geBtn';
  4586. btns.appendChild(btn);
  4587. }
  4588. mxEvent.addListener(linkInput, 'keypress', function(e)
  4589. {
  4590. if (e.keyCode == 13)
  4591. {
  4592. apply(linkInput.value);
  4593. }
  4594. });
  4595. var cropBtn = mxUtils.button(mxResources.get('crop'), function()
  4596. {
  4597. var dlg = new CropImageDialog(editorUi, linkInput.value, clipPath,
  4598. function(clipPath_p, width, height)
  4599. {
  4600. clipPath = clipPath_p;
  4601. cW = width;
  4602. cH = height;
  4603. });
  4604. editorUi.showDialog(dlg.container, 300, 390, true, true);
  4605. });
  4606. if (withCrop)
  4607. {
  4608. cropBtn.className = 'geBtn';
  4609. btns.appendChild(cropBtn);
  4610. }
  4611. function updateCropButton()
  4612. {
  4613. if (linkInput.value.length > 0)
  4614. {
  4615. cropBtn.removeAttribute('disabled');
  4616. }
  4617. else
  4618. {
  4619. cropBtn.setAttribute('disabled', 'disabled');
  4620. }
  4621. };
  4622. mxEvent.addListener(linkInput, 'change', function(e)
  4623. {
  4624. clipPath = null;
  4625. updateCropButton();
  4626. });
  4627. updateCropButton();
  4628. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  4629. {
  4630. apply(linkInput.value);
  4631. });
  4632. applyBtn.className = 'geBtn gePrimaryBtn';
  4633. btns.appendChild(applyBtn);
  4634. if (!editorUi.editor.cancelFirst)
  4635. {
  4636. btns.appendChild(cancelBtn);
  4637. }
  4638. // Shows drop icon in dialog background
  4639. if (Graph.fileSupport)
  4640. {
  4641. btns.style.marginTop = '120px';
  4642. div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')';
  4643. div.style.backgroundPosition = 'center 65%';
  4644. div.style.backgroundRepeat = 'no-repeat';
  4645. var bg = document.createElement('div');
  4646. bg.style.position = 'absolute';
  4647. bg.style.width = '420px';
  4648. bg.style.top = '58%';
  4649. bg.style.textAlign = 'center';
  4650. bg.style.fontSize = '18px';
  4651. bg.style.color = '#a0c3ff';
  4652. mxUtils.write(bg, mxResources.get('dragImagesHere'));
  4653. div.appendChild(bg);
  4654. }
  4655. div.appendChild(btns);
  4656. this.container = div;
  4657. };
  4658. /**
  4659. * Overrides link dialog to add Google Picker.
  4660. */
  4661. var LinkDialog = function(editorUi, initialValue, btnLabel, fn, showPages, showNewWindowOption, linkTarget)
  4662. {
  4663. var div = document.createElement('div');
  4664. div.style.height = '100%';
  4665. mxUtils.write(div, mxResources.get('editLink') + ':');
  4666. var inner = document.createElement('div');
  4667. inner.className = 'geTitle';
  4668. inner.style.backgroundColor = 'transparent';
  4669. inner.style.borderColor = 'transparent';
  4670. inner.style.whiteSpace = 'nowrap';
  4671. inner.style.textOverflow = 'clip';
  4672. inner.style.cursor = 'default';
  4673. inner.style.paddingRight = '20px';
  4674. var linkInput = document.createElement('input');
  4675. linkInput.setAttribute('placeholder', mxResources.get('dragUrlsHere'));
  4676. linkInput.setAttribute('type', 'text');
  4677. linkInput.style.marginTop = '6px';
  4678. linkInput.style.width = '97%';
  4679. linkInput.style.boxSizing = 'border-box';
  4680. linkInput.style.backgroundImage = 'url(\'' + Dialog.prototype.clearImage + '\')';
  4681. linkInput.style.backgroundRepeat = 'no-repeat';
  4682. linkInput.style.backgroundPosition = '100% 50%';
  4683. linkInput.style.paddingRight = '14px';
  4684. linkInput.style.marginBottom = '4px';
  4685. var cross = document.createElement('div');
  4686. cross.setAttribute('title', mxResources.get('reset'));
  4687. cross.style.position = 'relative';
  4688. cross.style.left = '-16px';
  4689. cross.style.width = '12px';
  4690. cross.style.height = '14px';
  4691. cross.style.cursor = 'pointer';
  4692. // Workaround for inline-block not supported in IE
  4693. cross.style.display = 'inline-block';
  4694. cross.style.top = '3px';
  4695. // Needed to block event transparency in IE
  4696. cross.style.background = 'url(\'' + editorUi.editor.transparentImage + '\')';
  4697. mxEvent.addListener(cross, 'click', function()
  4698. {
  4699. linkInput.value = '';
  4700. linkInput.focus();
  4701. });
  4702. var urlRadio = document.createElement('input');
  4703. urlRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  4704. urlRadio.setAttribute('value', 'url');
  4705. urlRadio.setAttribute('type', 'radio');
  4706. urlRadio.setAttribute('name', 'geLinkDialogOption');
  4707. var pageRadio = document.createElement('input');
  4708. pageRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  4709. pageRadio.setAttribute('value', 'url');
  4710. pageRadio.setAttribute('type', 'radio');
  4711. pageRadio.setAttribute('name', 'geLinkDialogOption');
  4712. var pageSelect = document.createElement('select');
  4713. pageSelect.style.width = '520px';
  4714. var newWindowCheckbox = document.createElement('input');
  4715. newWindowCheckbox.setAttribute('type', 'checkbox');
  4716. newWindowCheckbox.style.margin = '0 6p 0 6px';
  4717. if (linkTarget != null)
  4718. {
  4719. newWindowCheckbox.setAttribute('checked', 'checked');
  4720. newWindowCheckbox.defaultChecked = true;
  4721. }
  4722. linkTarget = (linkTarget != null) ? linkTarget : '_blank';
  4723. newWindowCheckbox.setAttribute('title', linkTarget);
  4724. if (showNewWindowOption)
  4725. {
  4726. linkInput.style.width = '340px';
  4727. }
  4728. if (showPages && editorUi.pages != null)
  4729. {
  4730. if (initialValue != null && Graph.isPageLink(initialValue))
  4731. {
  4732. pageRadio.setAttribute('checked', 'checked');
  4733. pageRadio.defaultChecked = true;
  4734. }
  4735. else
  4736. {
  4737. linkInput.setAttribute('value', initialValue);
  4738. urlRadio.setAttribute('checked', 'checked');
  4739. urlRadio.defaultChecked = true;
  4740. }
  4741. inner.appendChild(urlRadio);
  4742. inner.appendChild(linkInput);
  4743. inner.appendChild(cross);
  4744. if (showNewWindowOption)
  4745. {
  4746. inner.appendChild(newWindowCheckbox);
  4747. mxUtils.write(inner, mxResources.get('openInNewWindow'));
  4748. }
  4749. mxUtils.br(inner);
  4750. inner.appendChild(pageRadio);
  4751. var pageFound = false;
  4752. for (var i = 0; i < editorUi.pages.length; i++)
  4753. {
  4754. var pageOption = document.createElement('option');
  4755. mxUtils.write(pageOption, editorUi.pages[i].getName() ||
  4756. mxResources.get('pageWithNumber', [i + 1]));
  4757. pageOption.setAttribute('value', 'data:page/id,' +
  4758. editorUi.pages[i].getId());
  4759. if (initialValue == pageOption.getAttribute('value'))
  4760. {
  4761. pageOption.setAttribute('selected', 'selected');
  4762. pageFound = true;
  4763. }
  4764. pageSelect.appendChild(pageOption);
  4765. }
  4766. if (!pageFound && pageRadio.checked)
  4767. {
  4768. var notFoundOption = document.createElement('option');
  4769. mxUtils.write(notFoundOption, mxResources.get('pageNotFound'));
  4770. notFoundOption.setAttribute('disabled', 'disabled');
  4771. notFoundOption.setAttribute('selected', 'selected');
  4772. notFoundOption.setAttribute('value', 'pageNotFound');
  4773. pageSelect.appendChild(notFoundOption);
  4774. mxEvent.addListener(pageSelect, 'change', function()
  4775. {
  4776. if (notFoundOption.parentNode != null && !notFoundOption.selected)
  4777. {
  4778. notFoundOption.parentNode.removeChild(notFoundOption);
  4779. }
  4780. });
  4781. }
  4782. inner.appendChild(pageSelect);
  4783. }
  4784. else
  4785. {
  4786. linkInput.setAttribute('value', initialValue);
  4787. inner.appendChild(linkInput);
  4788. inner.appendChild(cross);
  4789. }
  4790. div.appendChild(inner);
  4791. var mainBtn = mxUtils.button(btnLabel, function()
  4792. {
  4793. editorUi.hideDialog();
  4794. var value = (pageRadio.checked) ? ((pageSelect.value !== 'pageNotFound') ?
  4795. pageSelect.value : initialValue) : linkInput.value;
  4796. fn(value, LinkDialog.selectedDocs, (newWindowCheckbox.checked) ? linkTarget : null);
  4797. });
  4798. mainBtn.style.verticalAlign = 'middle';
  4799. mainBtn.className = 'geBtn gePrimaryBtn';
  4800. this.init = function()
  4801. {
  4802. if (pageRadio.checked)
  4803. {
  4804. pageSelect.focus();
  4805. }
  4806. else
  4807. {
  4808. linkInput.focus();
  4809. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  4810. {
  4811. linkInput.select();
  4812. }
  4813. else
  4814. {
  4815. document.execCommand('selectAll', false, null);
  4816. }
  4817. }
  4818. mxEvent.addListener(pageSelect, 'focus', function()
  4819. {
  4820. urlRadio.removeAttribute('checked');
  4821. pageRadio.setAttribute('checked', 'checked');
  4822. pageRadio.checked = true;
  4823. });
  4824. mxEvent.addListener(linkInput, 'focus', function()
  4825. {
  4826. pageRadio.removeAttribute('checked');
  4827. urlRadio.setAttribute('checked', 'checked');
  4828. urlRadio.checked = true;
  4829. });
  4830. // Installs drag and drop handler for links
  4831. if (Graph.fileSupport)
  4832. {
  4833. // Setup the dnd listeners
  4834. var dlg = div.parentNode;
  4835. var graph = editorUi.editor.graph;
  4836. var dropElt = null;
  4837. mxEvent.addListener(dlg, 'dragleave', function(evt)
  4838. {
  4839. if (dropElt != null)
  4840. {
  4841. dropElt.parentNode.removeChild(dropElt);
  4842. dropElt = null;
  4843. }
  4844. evt.stopPropagation();
  4845. evt.preventDefault();
  4846. });
  4847. mxEvent.addListener(dlg, 'dragover', mxUtils.bind(this, function(evt)
  4848. {
  4849. // IE 10 does not implement pointer-events so it can't have a drop highlight
  4850. if (dropElt == null && (!mxClient.IS_IE || document.documentMode > 10))
  4851. {
  4852. dropElt = editorUi.highlightElement(dlg);
  4853. }
  4854. evt.stopPropagation();
  4855. evt.preventDefault();
  4856. }));
  4857. mxEvent.addListener(dlg, 'drop', mxUtils.bind(this, function(evt)
  4858. {
  4859. if (dropElt != null)
  4860. {
  4861. dropElt.parentNode.removeChild(dropElt);
  4862. dropElt = null;
  4863. }
  4864. if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
  4865. {
  4866. linkInput.value = decodeURIComponent(evt.dataTransfer.getData('text/uri-list'));
  4867. urlRadio.setAttribute('checked', 'checked');
  4868. urlRadio.checked = true;
  4869. mainBtn.click();
  4870. }
  4871. evt.stopPropagation();
  4872. evt.preventDefault();
  4873. }), false);
  4874. }
  4875. };
  4876. var btns = document.createElement('div');
  4877. btns.style.marginTop = '18px';
  4878. btns.style.textAlign = 'center';
  4879. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  4880. {
  4881. editorUi.openLink('https://www.diagrams.net/doc/faq/custom-links');
  4882. });
  4883. helpBtn.style.verticalAlign = 'middle';
  4884. helpBtn.className = 'geBtn';
  4885. btns.appendChild(helpBtn);
  4886. if (editorUi.isOffline() && !mxClient.IS_CHROMEAPP)
  4887. {
  4888. helpBtn.style.display = 'none';
  4889. }
  4890. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  4891. {
  4892. editorUi.hideDialog();
  4893. });
  4894. cancelBtn.style.verticalAlign = 'middle';
  4895. cancelBtn.className = 'geBtn';
  4896. if (editorUi.editor.cancelFirst)
  4897. {
  4898. btns.appendChild(cancelBtn);
  4899. }
  4900. LinkDialog.selectedDocs = null;
  4901. LinkDialog.filePicked = function(data)
  4902. {
  4903. if (data.action == google.picker.Action.PICKED)
  4904. {
  4905. LinkDialog.selectedDocs = data.docs;
  4906. var href = data.docs[0].url;
  4907. if (data.docs[0].mimeType == 'application/mxe' || (data.docs[0].mimeType != null &&
  4908. data.docs[0].mimeType.substring(0, 23) == 'application/vnd.jgraph.'))
  4909. {
  4910. href = 'https://www.draw.io/#G' + data.docs[0].id;
  4911. }
  4912. else if (data.docs[0].mimeType == 'application/vnd.google-apps.folder')
  4913. {
  4914. // Do not use folderview in data.docs[0].url link to Google Drive instead
  4915. href = 'https://drive.google.com/#folders/' + data.docs[0].id;
  4916. }
  4917. linkInput.value = href;
  4918. linkInput.focus();
  4919. }
  4920. else
  4921. {
  4922. LinkDialog.selectedDocs = null;
  4923. }
  4924. linkInput.focus();
  4925. };
  4926. function addButton(src, tooltip, fn)
  4927. {
  4928. var btn = mxUtils.button('', fn);
  4929. btn.className = 'geBtn';
  4930. btn.setAttribute('title', tooltip);
  4931. var img = document.createElement('img');
  4932. img.style.height = '26px';
  4933. img.style.width = '26px';
  4934. img.setAttribute('src', src);
  4935. btn.style.minWidth = '42px';
  4936. btn.style.verticalAlign = 'middle';
  4937. btn.appendChild(img);
  4938. btns.appendChild(btn);
  4939. };
  4940. if (typeof(google) != 'undefined' && typeof(google.picker) != 'undefined' && editorUi.drive != null)
  4941. {
  4942. addButton(IMAGE_PATH + '/google-drive-logo.svg', mxResources.get('googlePlus'), function()
  4943. {
  4944. if (editorUi.spinner.spin(document.body, mxResources.get('authorizing')))
  4945. {
  4946. editorUi.drive.checkToken(mxUtils.bind(this, function()
  4947. {
  4948. editorUi.spinner.stop();
  4949. // Creates one picker and reuses it to avoid polluting the DOM
  4950. if (editorUi.linkPicker == null)
  4951. {
  4952. var picker = editorUi.drive.createLinkPicker();
  4953. editorUi.linkPicker = picker.setCallback(function(data)
  4954. {
  4955. LinkDialog.filePicked(data);
  4956. }).build();
  4957. }
  4958. editorUi.linkPicker.setVisible(true);
  4959. }));
  4960. }
  4961. });
  4962. }
  4963. if (typeof(Dropbox) != 'undefined' && typeof(Dropbox.choose) != 'undefined')
  4964. {
  4965. addButton(IMAGE_PATH + '/dropbox-logo.svg', mxResources.get('dropbox'), function()
  4966. {
  4967. // Authentication will be carried out on open to make sure the
  4968. // autosave does not show an auth dialog. Showing it here will
  4969. // block the second dialog (the file picker) so it's too early.
  4970. Dropbox.choose(
  4971. {
  4972. linkType : 'direct',
  4973. cancel: function()
  4974. {
  4975. // do nothing
  4976. },
  4977. success : function(files)
  4978. {
  4979. linkInput.value = files[0].link;
  4980. linkInput.focus();
  4981. }
  4982. });
  4983. });
  4984. }
  4985. if (editorUi.oneDrive != null)
  4986. {
  4987. addButton(IMAGE_PATH + '/onedrive-logo.svg', mxResources.get('oneDrive'), function()
  4988. {
  4989. editorUi.oneDrive.pickFile(function(id, files)
  4990. {
  4991. if (files != null && files.value != null && files.value.length > 0)
  4992. {
  4993. linkInput.value = files.value[0].webUrl;
  4994. linkInput.focus();
  4995. }
  4996. }, true);
  4997. });
  4998. }
  4999. if (editorUi.gitHub != null)
  5000. {
  5001. addButton(IMAGE_PATH + '/github-logo.svg', mxResources.get('github'), function()
  5002. {
  5003. editorUi.gitHub.pickFile(function(path)
  5004. {
  5005. if (path != null)
  5006. {
  5007. var tokens = path.split('/');
  5008. var org = tokens[0];
  5009. var repo = tokens[1];
  5010. var ref = tokens[2];
  5011. var path = tokens.slice(3, tokens.length).join('/');
  5012. linkInput.value = 'https://github.com/' + org + '/' +
  5013. repo + '/blob/' + ref + '/' + path;
  5014. linkInput.focus();
  5015. }
  5016. });
  5017. });
  5018. }
  5019. if (editorUi.gitLab != null)
  5020. {
  5021. addButton(IMAGE_PATH + '/gitlab-logo.svg', mxResources.get('gitlab'), function()
  5022. {
  5023. editorUi.gitLab.pickFile(function(path)
  5024. {
  5025. if (path != null)
  5026. {
  5027. var tokens = path.split('/');
  5028. var org = tokens[0];
  5029. var repo = tokens[1];
  5030. var ref = tokens[2];
  5031. var path = tokens.slice(3, tokens.length).join('/');
  5032. linkInput.value = DRAWIO_GITLAB_URL + '/' + org + '/' +
  5033. repo + '/blob/' + ref + '/' + path;
  5034. linkInput.focus();
  5035. }
  5036. });
  5037. });
  5038. }
  5039. //TODO should Trello support this?
  5040. mxEvent.addListener(linkInput, 'keypress', function(e)
  5041. {
  5042. if (e.keyCode == 13)
  5043. {
  5044. editorUi.hideDialog();
  5045. var value = (pageRadio.checked) ? pageSelect.value : linkInput.value;
  5046. fn(value, LinkDialog.selectedDocs);
  5047. }
  5048. });
  5049. btns.appendChild(mainBtn);
  5050. if (!editorUi.editor.cancelFirst)
  5051. {
  5052. btns.appendChild(cancelBtn);
  5053. }
  5054. div.appendChild(btns);
  5055. this.container = div;
  5056. };
  5057. /**
  5058. * Constructs a new about dialog
  5059. */
  5060. var FeedbackDialog = function(editorUi, subject, emailOptional, diagramData)
  5061. {
  5062. var div = document.createElement('div');
  5063. var label = document.createElement('div');
  5064. mxUtils.write(label, mxResources.get('sendYourFeedback'));
  5065. label.style.fontSize = '18px';
  5066. label.style.marginBottom = '18px';
  5067. div.appendChild(label);
  5068. label = document.createElement('div');
  5069. mxUtils.write(label, mxResources.get('yourEmailAddress') +
  5070. ((emailOptional) ? '' : ' (' + mxResources.get('required') + ')'));
  5071. div.appendChild(label);
  5072. var email = document.createElement('input');
  5073. email.setAttribute('type', 'text');
  5074. email.style.marginTop = '6px';
  5075. email.style.width = '600px';
  5076. var sendButton = mxUtils.button(mxResources.get('sendMessage'), function()
  5077. {
  5078. var diagram = textarea.value +
  5079. ((cb.checked) ? '\nDiagram:\n' + ((diagramData != null) ?
  5080. diagramData : mxUtils.getXml(editorUi.getXmlFileData())) : '') +
  5081. '\nuserAgent:\n' + navigator.userAgent +
  5082. '\nappVersion:\n' + navigator.appVersion +
  5083. '\nappName:\n' + navigator.appName +
  5084. '\nplatform:\n' + navigator.platform;
  5085. if (diagram.length > FeedbackDialog.maxAttachmentSize)
  5086. {
  5087. editorUi.alert(mxResources.get('drawingTooLarge'));
  5088. }
  5089. else
  5090. {
  5091. editorUi.hideDialog();
  5092. if (editorUi.spinner.spin(document.body))
  5093. {
  5094. var postUrl = (FeedbackDialog.feedbackUrl != null) ? FeedbackDialog.feedbackUrl : '/email';
  5095. mxUtils.post(postUrl, 'email=' + encodeURIComponent(email.value) +
  5096. '&version=' + encodeURIComponent(EditorUi.VERSION) +
  5097. '&url=' + encodeURIComponent(window.location.href) +
  5098. '&body=' + encodeURIComponent(((subject != null) ?
  5099. subject : 'Feedback') + ':\n' + diagram),
  5100. function(req)
  5101. {
  5102. editorUi.spinner.stop();
  5103. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  5104. {
  5105. editorUi.alert(mxResources.get('feedbackSent'));
  5106. }
  5107. else
  5108. {
  5109. editorUi.alert(mxResources.get('errorSendingFeedback'));
  5110. }
  5111. },
  5112. function()
  5113. {
  5114. editorUi.spinner.stop();
  5115. editorUi.alert(mxResources.get('errorSendingFeedback'));
  5116. });
  5117. }
  5118. }
  5119. });
  5120. sendButton.className = 'geBtn gePrimaryBtn';
  5121. if (!emailOptional)
  5122. {
  5123. sendButton.setAttribute('disabled', 'disabled');
  5124. var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  5125. mxEvent.addListener(email, 'change', function()
  5126. {
  5127. if (email.value.length > 0 && re.test(email.value) > 0)
  5128. {
  5129. sendButton.removeAttribute('disabled');
  5130. }
  5131. else
  5132. {
  5133. sendButton.setAttribute('disabled', 'disabled');
  5134. }
  5135. });
  5136. mxEvent.addListener(email, 'keyup', function()
  5137. {
  5138. if (email.value.length > 0 && re.test(email.value))
  5139. {
  5140. sendButton.removeAttribute('disabled');
  5141. }
  5142. else
  5143. {
  5144. sendButton.setAttribute('disabled', 'disabled');
  5145. }
  5146. });
  5147. }
  5148. div.appendChild(email);
  5149. this.init = function()
  5150. {
  5151. email.focus();
  5152. };
  5153. var cb = document.createElement('input');
  5154. cb.setAttribute('type', 'checkbox');
  5155. cb.setAttribute('checked', 'checked');
  5156. cb.defaultChecked = true;
  5157. var p2 = document.createElement('p');
  5158. p2.style.marginTop = '14px';
  5159. p2.appendChild(cb);
  5160. var span = document.createElement('span');
  5161. mxUtils.write(span, ' ' + mxResources.get('includeCopyOfMyDiagram'));
  5162. p2.appendChild(span);
  5163. mxEvent.addListener(span, 'click', function(evt)
  5164. {
  5165. cb.checked = !cb.checked;
  5166. mxEvent.consume(evt);
  5167. });
  5168. div.appendChild(p2);
  5169. label = document.createElement('div');
  5170. mxUtils.write(label, mxResources.get('feedback'));
  5171. div.appendChild(label);
  5172. var textarea = document.createElement('textarea');
  5173. textarea.style.resize = 'none';
  5174. textarea.style.width = '600px';
  5175. textarea.style.height = '140px';
  5176. textarea.style.marginTop = '6px';
  5177. textarea.setAttribute('placeholder', mxResources.get('comments'));
  5178. div.appendChild(textarea);
  5179. var buttons = document.createElement('div');
  5180. buttons.style.marginTop = '26px';
  5181. buttons.style.textAlign = 'right';
  5182. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  5183. {
  5184. editorUi.hideDialog();
  5185. });
  5186. cancelBtn.className = 'geBtn';
  5187. if (editorUi.editor.cancelFirst)
  5188. {
  5189. buttons.appendChild(cancelBtn);
  5190. buttons.appendChild(sendButton);
  5191. }
  5192. else
  5193. {
  5194. buttons.appendChild(sendButton);
  5195. buttons.appendChild(cancelBtn);
  5196. }
  5197. div.appendChild(buttons);
  5198. this.container = div;
  5199. };
  5200. /**
  5201. * Maximum size of attachments in bytes. Default is 1000000.
  5202. */
  5203. FeedbackDialog.maxAttachmentSize = 1000000;
  5204. /**
  5205. * Constructs a new revision dialog
  5206. */
  5207. var RevisionDialog = function(editorUi, revs, restoreFn)
  5208. {
  5209. var div = document.createElement('div');
  5210. var title = document.createElement('h3');
  5211. title.style.marginTop = '0px';
  5212. mxUtils.write(title, mxResources.get('revisionHistory'));
  5213. div.appendChild(title);
  5214. var list = document.createElement('div');
  5215. list.style.position = 'absolute';
  5216. list.style.overflow = 'auto';
  5217. list.style.width = '170px';
  5218. list.style.height = '378px';
  5219. div.appendChild(list);
  5220. var container = document.createElement('div');
  5221. container.style.position = 'absolute';
  5222. container.style.border = '1px solid lightGray';
  5223. container.style.left = '200px';
  5224. container.style.width = '470px';
  5225. container.style.height = '376px';
  5226. container.style.overflow = 'hidden';
  5227. // Contains possible error messages
  5228. var errorNode = document.createElement('div');
  5229. errorNode.style.cssText = 'position:absolute;left:0;right:0;top:0;bottom:20px;text-align:center;transform:translate(0,50%);pointer-events:none;';
  5230. container.appendChild(errorNode);
  5231. mxEvent.disableContextMenu(container);
  5232. div.appendChild(container);
  5233. var graph = new Graph(container);
  5234. graph.setTooltips(false);
  5235. graph.setEnabled(false);
  5236. graph.setPanning(true);
  5237. graph.panningHandler.ignoreCell = true;
  5238. graph.panningHandler.useLeftButtonForPanning = true;
  5239. graph.minFitScale = null;
  5240. graph.maxFitScale = null;
  5241. graph.centerZoom = true;
  5242. // Handles placeholders for pages
  5243. var currentPage = 0;
  5244. var diagrams = null;
  5245. var realPage = 0;
  5246. var graphGetGlobalVariable = graph.getGlobalVariable;
  5247. graph.getGlobalVariable = function(name)
  5248. {
  5249. if (name == 'page' && diagrams != null && diagrams[realPage] != null)
  5250. {
  5251. return diagrams[realPage].getAttribute('name');
  5252. }
  5253. else if (name == 'pagenumber')
  5254. {
  5255. return realPage + 1;
  5256. }
  5257. else if (name == 'pagecount')
  5258. {
  5259. return (diagrams != null) ? diagrams.length : 1;
  5260. }
  5261. return graphGetGlobalVariable.apply(this, arguments);
  5262. };
  5263. // Disables hyperlinks
  5264. graph.getLinkForCell = function()
  5265. {
  5266. return null;
  5267. };
  5268. if (Editor.MathJaxRender)
  5269. {
  5270. graph.model.addListener(mxEvent.CHANGE, mxUtils.bind(this, function(sender, evt)
  5271. {
  5272. // LATER: Math support is used if current graph has math enabled
  5273. // should use switch from history instead but requires setting the
  5274. // global mxClient.NO_FO switch
  5275. if (editorUi.editor.graph.mathEnabled)
  5276. {
  5277. Editor.MathJaxRender(graph.container);
  5278. }
  5279. }));
  5280. }
  5281. var opts = {
  5282. lines: 11, // The number of lines to draw
  5283. length: 15, // The length of each line
  5284. width: 6, // The line thickness
  5285. radius: 10, // The radius of the inner circle
  5286. corners: 1, // Corner roundness (0..1)
  5287. rotate: 0, // The rotation offset
  5288. direction: 1, // 1: clockwise, -1: counterclockwise
  5289. color: Editor.isDarkMode() ? '#c0c0c0' : '#000', // #rgb or #rrggbb
  5290. speed: 1.4, // Rounds per second
  5291. trail: 60, // Afterglow percentage
  5292. shadow: false, // Whether to render a shadow
  5293. hwaccel: false, // Whether to use hardware acceleration
  5294. className: 'spinner', // The CSS class to assign to the spinner
  5295. zIndex: 2e9, // The z-index (defaults to 2000000000)
  5296. top: '50%', // Top position relative to parent
  5297. left: '50%' // Left position relative to parent
  5298. };
  5299. var spinner = new Spinner(opts);
  5300. var file = editorUi.getCurrentFile();
  5301. var fileNode = editorUi.getXmlFileData(true, false, true);
  5302. var tmp = fileNode.getElementsByTagName('diagram');
  5303. var currentDiagrams = {};
  5304. for (var i = 0; i < tmp.length; i++)
  5305. {
  5306. currentDiagrams[tmp[i].getAttribute('id')] = tmp[i];
  5307. }
  5308. var currentRow = null;
  5309. var currentRev = null;
  5310. var currentDoc = null;
  5311. var currentXml = null;
  5312. var zoomInBtn = editorUi.createToolbarButton(Editor.zoomInImage, mxResources.get('zoomIn'), function()
  5313. {
  5314. if (currentDoc != null)
  5315. {
  5316. graph.zoomIn();
  5317. }
  5318. }, 20);
  5319. zoomInBtn.setAttribute('disabled', 'disabled');
  5320. var zoomOutBtn = editorUi.createToolbarButton(Editor.zoomOutImage, mxResources.get('zoomOut'), function()
  5321. {
  5322. if (currentDoc != null)
  5323. {
  5324. graph.zoomOut();
  5325. }
  5326. }, 20);
  5327. zoomOutBtn.setAttribute('disabled', 'disabled');
  5328. var zoomFitBtn = editorUi.createToolbarButton(Editor.zoomFitImage, mxResources.get('fit'), function()
  5329. {
  5330. if (currentDoc != null)
  5331. {
  5332. if (graph.view.scale == 1)
  5333. {
  5334. graph.maxFitScale = 8;
  5335. graph.fit(8);
  5336. }
  5337. else
  5338. {
  5339. graph.zoomActual();
  5340. }
  5341. graph.center();
  5342. }
  5343. }, 20);
  5344. zoomFitBtn.setAttribute('disabled', 'disabled');
  5345. // Gesture listener added below to handle pressed state
  5346. var compareBtn = editorUi.createToolbarButton(Editor.compareImage, mxResources.get('compare'), null, 20);
  5347. compareBtn.setAttribute('disabled', 'disabled');
  5348. var mergeBtn = editorUi.createToolbarButton(Editor.thinDataImage, mxResources.get('merge'), null, 20);
  5349. mergeBtn.setAttribute('disabled', 'disabled');
  5350. var cmpContainer = container.cloneNode(false);
  5351. cmpContainer.style.pointerEvent = 'none';
  5352. container.parentNode.appendChild(cmpContainer);
  5353. var cmpGraph = new Graph(cmpContainer);
  5354. cmpGraph.setTooltips(false);
  5355. cmpGraph.setEnabled(false);
  5356. cmpGraph.setPanning(true);
  5357. cmpGraph.panningHandler.ignoreCell = true;
  5358. cmpGraph.panningHandler.useLeftButtonForPanning = true;
  5359. cmpGraph.minFitScale = null;
  5360. cmpGraph.maxFitScale = null;
  5361. cmpGraph.centerZoom = true;
  5362. var fileInfo = document.createElement('div');
  5363. fileInfo.style.position = 'absolute';
  5364. fileInfo.style.textAlign = 'left';
  5365. fileInfo.style.color = 'gray';
  5366. fileInfo.style.marginTop = '8px';
  5367. fileInfo.style.backgroundColor = 'transparent';
  5368. fileInfo.style.top = '440px';
  5369. fileInfo.style.left = '32px';
  5370. fileInfo.style.maxWidth = '380px';
  5371. fileInfo.style.cursor = 'default';
  5372. var prevFileInfo = null;
  5373. mxEvent.addGestureListeners(compareBtn, function(e)
  5374. {
  5375. // Gets current state of page with given ID
  5376. var curr = (diagrams[currentPage] != null) ? currentDiagrams[
  5377. diagrams[currentPage].getAttribute('id')] : null;
  5378. mxUtils.setOpacity(compareBtn, 20);
  5379. errorNode.innerText = '';
  5380. if (curr == null)
  5381. {
  5382. mxUtils.write(errorNode, mxResources.get('pageNotFound'));
  5383. }
  5384. else
  5385. {
  5386. prevFileInfo = fileInfo.innerHTML;
  5387. fileInfo.innerHTML = mxResources.get('current');
  5388. container.style.display = 'none';
  5389. cmpContainer.style.display = '';
  5390. cmpContainer.style.backgroundColor = container.style.backgroundColor;
  5391. var tempNode = Editor.parseDiagramNode(curr);
  5392. var codec = new mxCodec(tempNode.ownerDocument);
  5393. codec.decode(tempNode, cmpGraph.getModel());
  5394. cmpGraph.view.scaleAndTranslate(graph.view.scale,
  5395. graph.view.translate.x, graph.view.translate.y);
  5396. }
  5397. }, null, function()
  5398. {
  5399. mxUtils.setOpacity(compareBtn, 60);
  5400. errorNode.innerText = '';
  5401. if (container.style.display == 'none')
  5402. {
  5403. container.style.display = '';
  5404. fileInfo.innerHTML = prevFileInfo;
  5405. cmpContainer.style.display = 'none';
  5406. }
  5407. });
  5408. mxEvent.addListener(mergeBtn, 'click', mxUtils.bind(this, function(e)
  5409. {
  5410. if (currentDoc != null)
  5411. {
  5412. var pages = editorUi.getPagesForNode(currentDoc.documentElement);
  5413. var patch = editorUi.diffPages(editorUi.pages, pages);
  5414. var dlg = new TextareaDialog(editorUi, mxResources.get('merge') + ':',
  5415. JSON.stringify(patch, null, 2), function(newValue)
  5416. {
  5417. try
  5418. {
  5419. if (newValue.length > 0 && editorUi.editor.graph.isEnabled())
  5420. {
  5421. var patches = [JSON.parse(newValue)];
  5422. editorUi.confirm(mxResources.get('areYouSure'), function()
  5423. {
  5424. try
  5425. {
  5426. file.patch(patches, null, true, true);
  5427. // Hides compare dialog
  5428. editorUi.hideDialog();
  5429. // Hides revision history dialog
  5430. editorUi.hideDialog();
  5431. }
  5432. catch (e)
  5433. {
  5434. editorUi.handleError(e);
  5435. }
  5436. });
  5437. }
  5438. }
  5439. catch (e)
  5440. {
  5441. editorUi.handleError(e);
  5442. }
  5443. }, null, null, null, null, null, true, null, mxResources.get('merge'));
  5444. editorUi.showDialog(dlg.container, 620, 460, true, true);
  5445. dlg.init();
  5446. }
  5447. }));
  5448. var restoreBtn = mxUtils.button(mxResources.get('restore'), function(e)
  5449. {
  5450. if (currentDoc != null && currentXml != null)
  5451. {
  5452. editorUi.confirm(mxResources.get('areYouSure'), function()
  5453. {
  5454. if (restoreFn != null)
  5455. {
  5456. restoreFn(currentXml);
  5457. }
  5458. else
  5459. {
  5460. if (editorUi.spinner.spin(document.body, mxResources.get('restoring')))
  5461. {
  5462. restoreBtn.setAttribute('disabled', 'disabled');
  5463. file.save(true, function(resp)
  5464. {
  5465. editorUi.spinner.stop();
  5466. restoreBtn.removeAttribute('disabled');
  5467. editorUi.replaceFileData(currentXml);
  5468. editorUi.hideDialog();
  5469. }, function(resp)
  5470. {
  5471. editorUi.spinner.stop();
  5472. restoreBtn.removeAttribute('disabled');
  5473. editorUi.editor.setStatus('');
  5474. editorUi.handleError(resp, (resp != null) ? mxResources.get('errorSavingFile') : null);
  5475. });
  5476. }
  5477. }
  5478. });
  5479. }
  5480. });
  5481. restoreBtn.className = 'geBtn gePrimaryBtn';
  5482. restoreBtn.setAttribute('disabled', 'disabled');
  5483. var pageSelect = document.createElement('select');
  5484. pageSelect.setAttribute('disabled', 'disabled');
  5485. pageSelect.style.userSelect = 'none';
  5486. pageSelect.style.maxWidth = '100px';
  5487. pageSelect.style.position = 'relative';
  5488. pageSelect.style.top = '-2px';
  5489. pageSelect.style.verticalAlign = 'bottom';
  5490. pageSelect.style.marginLeft = '10px';
  5491. pageSelect.style.display = 'none';
  5492. var pageSelectFunction = null;
  5493. mxEvent.addListener(pageSelect, 'change', function(evt)
  5494. {
  5495. if (pageSelectFunction != null)
  5496. {
  5497. pageSelectFunction(evt);
  5498. mxEvent.consume(evt);
  5499. }
  5500. });
  5501. var newBtn = mxUtils.button(mxResources.get('open'), function()
  5502. {
  5503. if (currentDoc != null)
  5504. {
  5505. window.openFile = new OpenFile(function()
  5506. {
  5507. window.openFile = null;
  5508. });
  5509. window.openFile.setData(mxUtils.getXml(currentDoc.documentElement));
  5510. editorUi.openLink(editorUi.getUrl(), null, true);
  5511. }
  5512. });
  5513. newBtn.className = 'geBtn';
  5514. newBtn.setAttribute('disabled', 'disabled');
  5515. if (restoreFn != null)
  5516. {
  5517. newBtn.style.display = 'none';
  5518. }
  5519. var buttons = document.createElement('div');
  5520. buttons.style.position = 'absolute';
  5521. buttons.style.top = '482px';
  5522. buttons.style.right = '28px';
  5523. buttons.style.left = '32px';
  5524. buttons.style.textAlign = 'right';
  5525. var tb = document.createElement('div');
  5526. tb.className = 'geToolbarContainer';
  5527. tb.style.backgroundColor = 'transparent';
  5528. tb.style.padding = '2px';
  5529. tb.style.border = 'none';
  5530. tb.style.top = '442px';
  5531. tb.style.right = '28px';
  5532. var currentElt = null;
  5533. if (revs != null && revs.length > 0)
  5534. {
  5535. container.style.cursor = 'move';
  5536. var table = document.createElement('table');
  5537. table.style.border = '1px solid lightGray';
  5538. table.style.borderCollapse = 'collapse';
  5539. table.style.borderSpacing = '0px';
  5540. table.style.width = '100%';
  5541. var tbody = document.createElement('tbody');
  5542. var today = new Date().toDateString();
  5543. if (editorUi.currentPage != null && editorUi.pages != null)
  5544. {
  5545. currentPage = mxUtils.indexOf(editorUi.pages, editorUi.currentPage);
  5546. }
  5547. for (var i = revs.length - 1; i >= 0; i--)
  5548. {
  5549. var elt = (function(item)
  5550. {
  5551. var ts = new Date(item.modifiedDate);
  5552. var row = null;
  5553. var pd = '6px';
  5554. // Workaround for negative timestamps in Dropbox
  5555. if (ts.getTime() >= 0)
  5556. {
  5557. row = document.createElement('tr');
  5558. row.style.borderBottom = '1px solid lightGray';
  5559. row.style.fontSize = '12px';
  5560. row.style.cursor = 'pointer';
  5561. var date = document.createElement('td');
  5562. date.style.padding = pd;
  5563. date.style.whiteSpace = 'nowrap';
  5564. if (item == revs[revs.length - 1])
  5565. {
  5566. mxUtils.write(date, mxResources.get('current'));
  5567. }
  5568. else
  5569. {
  5570. if (ts.toDateString() === today)
  5571. {
  5572. mxUtils.write(date, ts.toLocaleTimeString());
  5573. }
  5574. else
  5575. {
  5576. mxUtils.write(date, ts.toLocaleDateString() + ' ' +
  5577. ts.toLocaleTimeString());
  5578. }
  5579. }
  5580. row.appendChild(date);
  5581. row.setAttribute('title', ts.toLocaleDateString() + ' ' +
  5582. ts.toLocaleTimeString() +
  5583. ((item.fileSize != null)? ' ' + editorUi.formatFileSize(parseInt(item.fileSize)) : '') +
  5584. ((item.lastModifyingUserName != null) ? ' ' + item.lastModifyingUserName : ''));
  5585. function updateGraph(xml)
  5586. {
  5587. spinner.stop();
  5588. errorNode.innerText = '';
  5589. var doc = mxUtils.parseXml(xml);
  5590. var node = editorUi.editor.extractGraphModel(doc.documentElement, true);
  5591. if (node != null)
  5592. {
  5593. pageSelect.style.display = 'none';
  5594. pageSelect.innerText = '';
  5595. currentDoc = doc;
  5596. currentXml = xml;
  5597. parseSelectFunction = null;
  5598. diagrams = null;
  5599. realPage = 0;
  5600. function parseGraphModel(dataNode)
  5601. {
  5602. var bg = dataNode.getAttribute('background');
  5603. if (bg == null || bg == '' || bg == mxConstants.NONE)
  5604. {
  5605. bg = graph.defaultPageBackgroundColor;
  5606. }
  5607. container.style.backgroundColor = bg;
  5608. var codec = new mxCodec(dataNode.ownerDocument);
  5609. codec.decode(dataNode, graph.getModel());
  5610. graph.maxFitScale = 1;
  5611. graph.fit(8);
  5612. graph.center();
  5613. return dataNode;
  5614. }
  5615. function parseDiagram(diagramNode)
  5616. {
  5617. if (diagramNode != null)
  5618. {
  5619. diagramNode = parseGraphModel(Editor.parseDiagramNode(diagramNode));
  5620. }
  5621. return diagramNode;
  5622. }
  5623. if (node.nodeName == 'mxfile')
  5624. {
  5625. // Workaround for "invalid calling object" error in IE
  5626. var tmp = node.getElementsByTagName('diagram');
  5627. diagrams = [];
  5628. for (var i = 0; i < tmp.length; i++)
  5629. {
  5630. diagrams.push(tmp[i]);
  5631. }
  5632. realPage = Math.min(currentPage, diagrams.length - 1);
  5633. if (diagrams.length > 0)
  5634. {
  5635. parseDiagram(diagrams[realPage]);
  5636. }
  5637. if (diagrams.length > 1)
  5638. {
  5639. pageSelect.removeAttribute('disabled');
  5640. pageSelect.style.display = '';
  5641. for (var i = 0; i < diagrams.length; i++)
  5642. {
  5643. var pageOption = document.createElement('option');
  5644. var name = diagrams[i].getAttribute('name') ||
  5645. mxResources.get('pageWithNumber', [i + 1]);
  5646. mxUtils.write(pageOption, name);
  5647. pageOption.setAttribute('title', name + ' (' +
  5648. diagrams[i].getAttribute('id') + ')');
  5649. pageOption.setAttribute('value', i);
  5650. if (i == realPage)
  5651. {
  5652. pageOption.setAttribute('selected', 'selected');
  5653. }
  5654. pageSelect.appendChild(pageOption);
  5655. }
  5656. }
  5657. pageSelectFunction = function()
  5658. {
  5659. try
  5660. {
  5661. var temp = parseInt(pageSelect.value);
  5662. currentPage = temp;
  5663. realPage = currentPage;
  5664. parseDiagram(diagrams[temp]);
  5665. }
  5666. catch (e)
  5667. {
  5668. pageSelect.value = currentPage;
  5669. editorUi.handleError(e);
  5670. }
  5671. };
  5672. }
  5673. else
  5674. {
  5675. parseGraphModel(node);
  5676. }
  5677. var shortUser = item.lastModifyingUserName;
  5678. if (shortUser != null && shortUser.length > 20)
  5679. {
  5680. shortUser = shortUser.substring(0, 20) + '...';
  5681. }
  5682. fileInfo.innerText = '';
  5683. mxUtils.write(fileInfo, ((shortUser != null) ?
  5684. (shortUser + ' ') : '') + ts.toLocaleDateString() +
  5685. ' ' + ts.toLocaleTimeString());
  5686. fileInfo.setAttribute('title', row.getAttribute('title'));
  5687. zoomInBtn.removeAttribute('disabled');
  5688. zoomOutBtn.removeAttribute('disabled');
  5689. zoomFitBtn.removeAttribute('disabled');
  5690. compareBtn.removeAttribute('disabled');
  5691. mergeBtn.removeAttribute('disabled');
  5692. if (file == null || !file.isRestricted())
  5693. {
  5694. if (editorUi.editor.graph.isEnabled())
  5695. {
  5696. restoreBtn.removeAttribute('disabled');
  5697. }
  5698. newBtn.removeAttribute('disabled');
  5699. }
  5700. mxUtils.setOpacity(zoomInBtn, 60);
  5701. mxUtils.setOpacity(zoomOutBtn, 60);
  5702. mxUtils.setOpacity(zoomFitBtn, 60);
  5703. mxUtils.setOpacity(compareBtn, 60);
  5704. mxUtils.setOpacity(mergeBtn, 60);
  5705. }
  5706. else
  5707. {
  5708. pageSelect.style.display = 'none';
  5709. pageSelect.innerText = '';
  5710. fileInfo.innerText = '';
  5711. errorNode.innerText = '';
  5712. mxUtils.write(fileInfo, mxResources.get('errorLoadingFile'));
  5713. mxUtils.write(errorNode, mxResources.get('errorLoadingFile'));
  5714. }
  5715. };
  5716. mxEvent.addListener(row, 'click', function(evt)
  5717. {
  5718. if (currentRev != item)
  5719. {
  5720. spinner.stop();
  5721. if (currentRow != null)
  5722. {
  5723. currentRow.style.backgroundColor = '';
  5724. }
  5725. currentRev = item;
  5726. currentRow = row;
  5727. currentRow.style.backgroundColor = Editor.isDarkMode() ? '#000000' : '#ebf2f9';
  5728. currentDoc = null;
  5729. currentXml = null;
  5730. fileInfo.removeAttribute('title');
  5731. fileInfo.innerText = mxResources.get('loading') + '...';
  5732. container.style.backgroundColor = graph.defaultPageBackgroundColor;
  5733. errorNode.innerText = '';
  5734. graph.getModel().clear();
  5735. restoreBtn.setAttribute('disabled', 'disabled');
  5736. zoomInBtn.setAttribute('disabled', 'disabled');
  5737. zoomOutBtn.setAttribute('disabled', 'disabled');
  5738. zoomFitBtn.setAttribute('disabled', 'disabled');
  5739. compareBtn.setAttribute('disabled', 'disabled');
  5740. mergeBtn.setAttribute('disabled', 'disabled');
  5741. newBtn.setAttribute('disabled', 'disabled');
  5742. pageSelect.setAttribute('disabled', 'disabled');
  5743. mxUtils.setOpacity(zoomInBtn, 20);
  5744. mxUtils.setOpacity(zoomOutBtn, 20);
  5745. mxUtils.setOpacity(zoomFitBtn, 20);
  5746. mxUtils.setOpacity(compareBtn, 20);
  5747. mxUtils.setOpacity(mergeBtn, 20);
  5748. spinner.spin(container);
  5749. item.getXml(function(xml)
  5750. {
  5751. if (currentRev == item)
  5752. {
  5753. try
  5754. {
  5755. updateGraph(xml);
  5756. }
  5757. catch (e)
  5758. {
  5759. fileInfo.innerText = mxResources.get('error') + ': ' + e.message;
  5760. }
  5761. }
  5762. }, function(err)
  5763. {
  5764. spinner.stop();
  5765. pageSelect.style.display = 'none';
  5766. pageSelect.innerText = '';
  5767. fileInfo.innerText = '';
  5768. mxUtils.write(fileInfo, mxResources.get('errorLoadingFile'));
  5769. mxUtils.write(errorNode, mxResources.get('errorLoadingFile'));
  5770. });
  5771. mxEvent.consume(evt);
  5772. }
  5773. });
  5774. mxEvent.addListener(row, 'dblclick', function(evt)
  5775. {
  5776. newBtn.click();
  5777. if (window.getSelection)
  5778. {
  5779. window.getSelection().removeAllRanges();
  5780. }
  5781. else if (document.selection)
  5782. {
  5783. document.selection.empty();
  5784. }
  5785. mxEvent.consume(evt);
  5786. }, false);
  5787. tbody.appendChild(row);
  5788. }
  5789. return row;
  5790. })(revs[i]);
  5791. // Selects and loads first element in list (ie current version) after
  5792. // graph container was initialized since there is no loading delay
  5793. if (elt != null && i == revs.length - 1)
  5794. {
  5795. currentElt = elt;
  5796. }
  5797. }
  5798. table.appendChild(tbody);
  5799. list.appendChild(table);
  5800. }
  5801. else if (file == null || (editorUi.drive == null && file.constructor == window.DriveFile) ||
  5802. (editorUi.dropbox == null && file.constructor == window.DropboxFile))
  5803. {
  5804. container.style.display = 'none';
  5805. tb.style.display = 'none';
  5806. mxUtils.write(list, mxResources.get('notAvailable'));
  5807. }
  5808. else
  5809. {
  5810. container.style.display = 'none';
  5811. tb.style.display = 'none';
  5812. mxUtils.write(list, mxResources.get('noRevisions'));
  5813. }
  5814. this.init = function()
  5815. {
  5816. if (currentElt != null)
  5817. {
  5818. currentElt.click();
  5819. }
  5820. };
  5821. var closeBtn = mxUtils.button(mxResources.get('cancel'), function()
  5822. {
  5823. editorUi.hideDialog();
  5824. });
  5825. closeBtn.className = 'geBtn';
  5826. tb.appendChild(compareBtn);
  5827. tb.appendChild(zoomOutBtn);
  5828. tb.appendChild(zoomFitBtn);
  5829. tb.appendChild(zoomInBtn);
  5830. tb.appendChild(pageSelect);
  5831. tb.appendChild(mergeBtn);
  5832. if (editorUi.editor.cancelFirst)
  5833. {
  5834. buttons.appendChild(closeBtn);
  5835. }
  5836. buttons.appendChild(newBtn);
  5837. buttons.appendChild(restoreBtn);
  5838. if (!editorUi.editor.cancelFirst)
  5839. {
  5840. buttons.appendChild(closeBtn);
  5841. }
  5842. div.appendChild(buttons);
  5843. div.appendChild(tb);
  5844. div.appendChild(fileInfo);
  5845. this.container = div;
  5846. };
  5847. /**
  5848. * Constructs a new revision dialog
  5849. */
  5850. var DraftDialog = function(editorUi, title, xml, editFn, discardFn, editLabel, discardLabel, ignoreFn, drafts)
  5851. {
  5852. var div = document.createElement('div');
  5853. var titleDiv = document.createElement('div');
  5854. titleDiv.style.marginTop = '0px';
  5855. titleDiv.style.whiteSpace = 'nowrap';
  5856. titleDiv.style.overflow = 'auto';
  5857. titleDiv.style.lineHeight = 'normal';
  5858. mxUtils.write(titleDiv, title);
  5859. div.appendChild(titleDiv);
  5860. var select = document.createElement('select');
  5861. var draftSelected = mxUtils.bind(this, function()
  5862. {
  5863. doc = mxUtils.parseXml(drafts[select.value].data);
  5864. node = editorUi.editor.extractGraphModel(doc.documentElement, true);
  5865. currentPage = 0;
  5866. this.init();
  5867. });
  5868. if (drafts != null)
  5869. {
  5870. select.style.marginLeft = '4px';
  5871. for (var i = 0; i < drafts.length; i++)
  5872. {
  5873. var opt = document.createElement('option');
  5874. opt.setAttribute('value', i);
  5875. var ts0 = new Date(drafts[i].created);
  5876. var ts1 = new Date(drafts[i].modified);
  5877. mxUtils.write(opt, ts0.toLocaleDateString() + ' ' +
  5878. ts0.toLocaleTimeString() + ' - ' +
  5879. ((ts0.toDateString() != ts1.toDateString() || true) ?
  5880. ts1.toLocaleDateString() : ' ') +
  5881. ' ' + ts1.toLocaleTimeString());
  5882. select.appendChild(opt);
  5883. }
  5884. titleDiv.appendChild(select);
  5885. mxEvent.addListener(select, 'change', draftSelected);
  5886. }
  5887. if (xml == null)
  5888. {
  5889. xml = drafts[0].data;
  5890. }
  5891. var container = document.createElement('div');
  5892. container.style.position = 'absolute';
  5893. container.style.border = '1px solid lightGray';
  5894. container.style.marginTop = '10px';
  5895. container.style.left = '40px';
  5896. container.style.right = '40px';
  5897. container.style.top = '46px';
  5898. container.style.bottom = '74px';
  5899. container.style.overflow = 'hidden';
  5900. mxEvent.disableContextMenu(container);
  5901. div.appendChild(container);
  5902. var graph = new Graph(container);
  5903. graph.setEnabled(false);
  5904. graph.setPanning(true);
  5905. graph.shapeBackgroundColor = (Editor.isDarkMode() ? '#2a252f' : '#ffffff');
  5906. graph.panningHandler.ignoreCell = true;
  5907. graph.panningHandler.useLeftButtonForPanning = true;
  5908. graph.minFitScale = null;
  5909. graph.maxFitScale = null;
  5910. graph.centerZoom = true;
  5911. // Handles placeholders for pages
  5912. var doc = mxUtils.parseXml(xml);
  5913. var node = editorUi.editor.extractGraphModel(doc.documentElement, true);
  5914. var currentPage = 0;
  5915. var diagrams = null;
  5916. var graphGetGlobalVariable = graph.getGlobalVariable;
  5917. graph.getGlobalVariable = function(name)
  5918. {
  5919. if (name == 'page' && diagrams != null && diagrams[currentPage] != null)
  5920. {
  5921. return diagrams[currentPage].getAttribute('name');
  5922. }
  5923. else if (name == 'pagenumber')
  5924. {
  5925. return currentPage + 1;
  5926. }
  5927. else if (name == 'pagecount')
  5928. {
  5929. return (diagrams != null) ? diagrams.length : 1;
  5930. }
  5931. return graphGetGlobalVariable.apply(this, arguments);
  5932. };
  5933. // Disables hyperlinks
  5934. graph.getLinkForCell = function()
  5935. {
  5936. return null;
  5937. };
  5938. var zoomInBtn = editorUi.createToolbarButton(Editor.zoomInImage, mxResources.get('zoomIn'), function()
  5939. {
  5940. graph.zoomIn();
  5941. }, 20);
  5942. var zoomOutBtn = editorUi.createToolbarButton(Editor.zoomInImage, mxResources.get('zoomOut'), function()
  5943. {
  5944. graph.zoomOut();
  5945. }, 20);
  5946. var zoomFitBtn = editorUi.createToolbarButton(Editor.zoomFitImage, mxResources.get('fit'), function()
  5947. {
  5948. if (graph.view.scale == 1)
  5949. {
  5950. graph.maxFitScale = 8;
  5951. graph.fit(8);
  5952. }
  5953. else
  5954. {
  5955. graph.zoomActual();
  5956. }
  5957. graph.center();
  5958. }, 20);
  5959. var restoreBtn = mxUtils.button(discardLabel || mxResources.get('discard'), function()
  5960. {
  5961. discardFn.apply(this, [select.value, mxUtils.bind(this, function()
  5962. {
  5963. if (select.parentNode != null)
  5964. {
  5965. select.options[select.selectedIndex].parentNode.removeChild(select.options[select.selectedIndex]);
  5966. if (select.options.length > 0)
  5967. {
  5968. select.value = select.options[0].value;
  5969. draftSelected();
  5970. }
  5971. else
  5972. {
  5973. editorUi.hideDialog(true);
  5974. }
  5975. }
  5976. })]);
  5977. });
  5978. restoreBtn.className = 'geBtn';
  5979. var pageSelect = document.createElement('select');
  5980. pageSelect.style.maxWidth = '80px';
  5981. pageSelect.style.position = 'relative';
  5982. pageSelect.style.top = '-2px';
  5983. pageSelect.style.verticalAlign = 'bottom';
  5984. pageSelect.style.marginRight = '6px';
  5985. pageSelect.style.display = 'none';
  5986. var showBtn = mxUtils.button(editLabel || mxResources.get('edit'), function()
  5987. {
  5988. editFn.apply(this, [select.value])
  5989. });
  5990. showBtn.className = 'geBtn gePrimaryBtn';
  5991. var buttons = document.createElement('div');
  5992. buttons.style.position = 'absolute';
  5993. buttons.style.bottom = '30px';
  5994. buttons.style.right = '40px';
  5995. buttons.style.textAlign = 'right';
  5996. var tb = document.createElement('div');
  5997. tb.className = 'geToolbarContainer';
  5998. tb.style.cssText = 'box-shadow:none !important;background-color:transparent;' +
  5999. 'padding:2px;border-style:none !important;bottom:30px;';
  6000. this.init = function()
  6001. {
  6002. function parseGraphModel(dataNode)
  6003. {
  6004. if (dataNode != null)
  6005. {
  6006. var bg = dataNode.getAttribute('background');
  6007. if (bg == null || bg == '' || bg == mxConstants.NONE)
  6008. {
  6009. bg = Editor.isDarkMode() ? 'transparent' : '#ffffff';
  6010. }
  6011. container.style.backgroundColor = bg;
  6012. var codec = new mxCodec(dataNode.ownerDocument);
  6013. codec.decode(dataNode, graph.getModel());
  6014. graph.maxFitScale = 1;
  6015. graph.fit(8);
  6016. graph.center();
  6017. }
  6018. return dataNode;
  6019. };
  6020. function parseDiagram(diagramNode)
  6021. {
  6022. if (diagramNode != null)
  6023. {
  6024. diagramNode = parseGraphModel(Editor.parseDiagramNode(diagramNode));
  6025. }
  6026. return diagramNode;
  6027. };
  6028. mxEvent.addListener(pageSelect, 'change', function(evt)
  6029. {
  6030. currentPage = parseInt(pageSelect.value);
  6031. parseDiagram(diagrams[currentPage]);
  6032. mxEvent.consume(evt);
  6033. });
  6034. if (node.nodeName == 'mxfile')
  6035. {
  6036. // Workaround for "invalid calling object" error in IE
  6037. var tmp = node.getElementsByTagName('diagram');
  6038. diagrams = [];
  6039. for (var i = 0; i < tmp.length; i++)
  6040. {
  6041. diagrams.push(tmp[i]);
  6042. }
  6043. if (diagrams.length > 0)
  6044. {
  6045. parseDiagram(diagrams[currentPage]);
  6046. }
  6047. pageSelect.innerText = '';
  6048. if (diagrams.length > 1)
  6049. {
  6050. pageSelect.style.display = '';
  6051. for (var i = 0; i < diagrams.length; i++)
  6052. {
  6053. var pageOption = document.createElement('option');
  6054. mxUtils.write(pageOption, diagrams[i].getAttribute('name') ||
  6055. mxResources.get('pageWithNumber', [i + 1]));
  6056. pageOption.setAttribute('value', i);
  6057. if (i == currentPage)
  6058. {
  6059. pageOption.setAttribute('selected', 'selected');
  6060. }
  6061. pageSelect.appendChild(pageOption);
  6062. }
  6063. }
  6064. else
  6065. {
  6066. pageSelect.style.display = 'none';
  6067. }
  6068. }
  6069. else
  6070. {
  6071. parseGraphModel(node);
  6072. }
  6073. };
  6074. tb.appendChild(pageSelect);
  6075. tb.appendChild(zoomInBtn);
  6076. tb.appendChild(zoomOutBtn);
  6077. tb.appendChild(zoomFitBtn);
  6078. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  6079. {
  6080. editorUi.hideDialog(true);
  6081. });
  6082. cancelBtn.className = 'geBtn';
  6083. var ignoreBtn = (ignoreFn != null) ? mxUtils.button(mxResources.get('ignore'), ignoreFn) : null;
  6084. if (ignoreBtn != null)
  6085. {
  6086. ignoreBtn.className = 'geBtn';
  6087. }
  6088. if (editorUi.editor.cancelFirst)
  6089. {
  6090. buttons.appendChild(cancelBtn);
  6091. if (ignoreBtn != null)
  6092. {
  6093. buttons.appendChild(ignoreBtn);
  6094. }
  6095. buttons.appendChild(restoreBtn);
  6096. buttons.appendChild(showBtn);
  6097. }
  6098. else
  6099. {
  6100. buttons.appendChild(showBtn);
  6101. buttons.appendChild(restoreBtn);
  6102. if (ignoreBtn != null)
  6103. {
  6104. buttons.appendChild(ignoreBtn);
  6105. }
  6106. buttons.appendChild(cancelBtn);
  6107. }
  6108. div.appendChild(buttons);
  6109. div.appendChild(tb);
  6110. this.container = div;
  6111. };
  6112. /**
  6113. *
  6114. */
  6115. var FindWindow = function(ui, x, y, w, h, withReplace)
  6116. {
  6117. var action = ui.actions.get('findReplace');
  6118. var graph = ui.editor.graph;
  6119. var lastSearch = null;
  6120. var lastFound = null;
  6121. var lastSearchSuccessful = false;
  6122. var allChecked = false;
  6123. var lblMatch = null;
  6124. var lblMatchPos = 0;
  6125. var marker = 1;
  6126. var div = document.createElement('div');
  6127. div.style.userSelect = 'none';
  6128. div.style.overflow = 'hidden';
  6129. div.style.padding = '10px';
  6130. div.style.height = '100%';
  6131. var txtWidth = withReplace? '260px' : '200px';
  6132. var searchInput = document.createElement('input');
  6133. searchInput.setAttribute('placeholder', mxResources.get('find'));
  6134. searchInput.setAttribute('type', 'text');
  6135. searchInput.style.marginTop = '4px';
  6136. searchInput.style.marginBottom = '6px';
  6137. searchInput.style.width = txtWidth;
  6138. searchInput.style.fontSize = '12px';
  6139. searchInput.style.borderRadius = '4px';
  6140. searchInput.style.padding = '6px';
  6141. div.appendChild(searchInput);
  6142. mxUtils.br(div);
  6143. var replaceInput;
  6144. if (withReplace)
  6145. {
  6146. replaceInput = document.createElement('input');
  6147. replaceInput.setAttribute('placeholder', mxResources.get('replaceWith'));
  6148. replaceInput.setAttribute('type', 'text');
  6149. replaceInput.style.marginTop = '4px';
  6150. replaceInput.style.marginBottom = '6px';
  6151. replaceInput.style.width = txtWidth;
  6152. replaceInput.style.fontSize = '12px';
  6153. replaceInput.style.borderRadius = '4px';
  6154. replaceInput.style.padding = '6px';
  6155. div.appendChild(replaceInput);
  6156. mxUtils.br(div);
  6157. mxEvent.addListener(replaceInput, 'input', updateReplBtns);
  6158. }
  6159. var regexInput = document.createElement('input');
  6160. regexInput.setAttribute('id', 'geFindWinRegExChck');
  6161. regexInput.setAttribute('type', 'checkbox');
  6162. regexInput.style.marginRight = '4px';
  6163. div.appendChild(regexInput);
  6164. var regexLabel = document.createElement('label');
  6165. regexLabel.setAttribute('for', 'geFindWinRegExChck');
  6166. div.appendChild(regexLabel);
  6167. mxUtils.write(regexLabel, mxResources.get('regularExpression'));
  6168. div.appendChild(regexLabel);
  6169. var help = ui.menus.createHelpLink('https://www.diagrams.net/doc/faq/find-shapes');
  6170. help.style.position = 'relative';
  6171. help.style.marginLeft = '6px';
  6172. help.style.top = '-1px';
  6173. div.appendChild(help);
  6174. mxUtils.br(div);
  6175. var allPagesInput = document.createElement('input');
  6176. allPagesInput.setAttribute('id', 'geFindWinAllPagesChck');
  6177. allPagesInput.setAttribute('type', 'checkbox');
  6178. allPagesInput.style.marginRight = '4px';
  6179. div.appendChild(allPagesInput);
  6180. var allPagesLabel = document.createElement('label');
  6181. allPagesLabel.setAttribute('for', 'geFindWinAllPagesChck');
  6182. div.appendChild(allPagesLabel);
  6183. mxUtils.write(allPagesLabel, mxResources.get('allPages'));
  6184. div.appendChild(allPagesLabel);
  6185. var tmp = document.createElement('div');
  6186. function testMeta(re, cell, search, checkIndex)
  6187. {
  6188. if (typeof cell.value === 'object' && cell.value.attributes != null)
  6189. {
  6190. var attrs = cell.value.attributes;
  6191. for (var i = 0; i < attrs.length; i++)
  6192. {
  6193. if (attrs[i].nodeName != 'label')
  6194. {
  6195. var value = mxUtils.trim(attrs[i].nodeValue.replace(/[\x00-\x1F\x7F-\x9F]|\s+/g, ' ')).toLowerCase();
  6196. if ((re == null && ((checkIndex && value.indexOf(search) >= 0) ||
  6197. (!checkIndex && value.substring(0, search.length) === search))) ||
  6198. (re != null && re.test(value)))
  6199. {
  6200. return true;
  6201. }
  6202. }
  6203. }
  6204. }
  6205. return false;
  6206. };
  6207. function updateReplBtns()
  6208. {
  6209. if (lastSearchSuccessful && replaceInput.value)
  6210. {
  6211. replaceFindBtn.removeAttribute('disabled');
  6212. replaceBtn.removeAttribute('disabled');
  6213. }
  6214. else
  6215. {
  6216. replaceFindBtn.setAttribute('disabled', 'disabled');
  6217. replaceBtn.setAttribute('disabled', 'disabled');
  6218. }
  6219. if (replaceInput.value && searchInput.value)
  6220. {
  6221. replaceAllBtn.removeAttribute('disabled');
  6222. }
  6223. else
  6224. {
  6225. replaceAllBtn.setAttribute('disabled', 'disabled');
  6226. }
  6227. }
  6228. function search(internalCall, trySameCell, stayOnPage)
  6229. {
  6230. replAllNotif.innerText = '';
  6231. var cells = graph.model.getDescendants(graph.model.getRoot());
  6232. var searchStr = searchInput.value.toLowerCase();
  6233. var re = (regexInput.checked) ? new RegExp(searchStr) : null;
  6234. var firstMatch = null;
  6235. lblMatch = null;
  6236. if (lastSearch != searchStr)
  6237. {
  6238. lastSearch = searchStr;
  6239. lastFound = null;
  6240. allChecked = false;
  6241. }
  6242. var active = lastFound == null;
  6243. if (searchStr.length > 0)
  6244. {
  6245. if (allChecked)
  6246. {
  6247. allChecked = false;
  6248. //Find current page index
  6249. var currentPageIndex;
  6250. for (var i = 0; i < ui.pages.length; i++)
  6251. {
  6252. if (ui.currentPage == ui.pages[i])
  6253. {
  6254. currentPageIndex = i;
  6255. break;
  6256. }
  6257. }
  6258. var nextPageIndex = (currentPageIndex + 1) % ui.pages.length, nextPage;
  6259. lastFound = null;
  6260. do
  6261. {
  6262. allChecked = false;
  6263. nextPage = ui.pages[nextPageIndex];
  6264. graph = ui.createTemporaryGraph(graph.getStylesheet());
  6265. ui.updatePageRoot(nextPage);
  6266. graph.model.setRoot(nextPage.root);
  6267. nextPageIndex = (nextPageIndex + 1) % ui.pages.length;
  6268. }
  6269. while(!search(true, trySameCell, stayOnPage) && nextPageIndex != currentPageIndex);
  6270. if (lastFound)
  6271. {
  6272. lastFound = null;
  6273. if (!stayOnPage)
  6274. {
  6275. ui.selectPage(nextPage);
  6276. }
  6277. else
  6278. {
  6279. ui.editor.graph.model.execute(new SelectPage(ui, nextPage));
  6280. }
  6281. }
  6282. allChecked = false;
  6283. graph = ui.editor.graph;
  6284. return search(true, trySameCell, stayOnPage);
  6285. }
  6286. var i;
  6287. for (i = 0; i < cells.length; i++)
  6288. {
  6289. var state = graph.view.getState(cells[i]);
  6290. //Try the same cell with replace to find other occurances
  6291. if (trySameCell && re != null)
  6292. {
  6293. active = active || state == lastFound;
  6294. }
  6295. if (state != null && state.cell.value != null && (active || firstMatch == null) &&
  6296. (graph.model.isVertex(state.cell) || graph.model.isEdge(state.cell)))
  6297. {
  6298. if (state.style != null && state.style['html'] == '1')
  6299. {
  6300. tmp.innerHTML = graph.sanitizeHtml(graph.getLabel(state.cell));
  6301. label = mxUtils.extractTextWithWhitespace([tmp]);
  6302. }
  6303. else
  6304. {
  6305. label = graph.getLabel(state.cell);
  6306. }
  6307. label = mxUtils.trim(label.replace(/[\x00-\x1F\x7F-\x9F]|\s+/g, ' ')).toLowerCase();
  6308. var lblPosShift = 0;
  6309. if (trySameCell && withReplace && re != null && state == lastFound)
  6310. {
  6311. label = label.substr(lblMatchPos);
  6312. lblPosShift = lblMatchPos;
  6313. }
  6314. var checkMeta = replaceInput.value == '';
  6315. var checkIndex = checkMeta;
  6316. if ((re == null && ((checkIndex && label.indexOf(searchStr) >= 0) ||
  6317. (!checkIndex && label.substring(0, searchStr.length) === searchStr) ||
  6318. (checkMeta && testMeta(re, state.cell, searchStr, checkIndex)))) ||
  6319. (re != null && (re.test(label) || (checkMeta &&
  6320. testMeta(re, state.cell, searchStr, checkIndex)))))
  6321. {
  6322. if (withReplace)
  6323. {
  6324. if (re != null)
  6325. {
  6326. var result = label.match(re);
  6327. if (result != null && result.length > 0)
  6328. {
  6329. lblMatch = result[0].toLowerCase();
  6330. lblMatchPos = lblPosShift + result.index + lblMatch.length;
  6331. }
  6332. }
  6333. else
  6334. {
  6335. lblMatch = searchStr;
  6336. lblMatchPos = lblMatch.length;
  6337. }
  6338. }
  6339. if (active)
  6340. {
  6341. firstMatch = state;
  6342. break;
  6343. }
  6344. else if (firstMatch == null)
  6345. {
  6346. firstMatch = state;
  6347. }
  6348. }
  6349. }
  6350. active = active || state == lastFound;
  6351. }
  6352. }
  6353. if (firstMatch != null)
  6354. {
  6355. if (i == cells.length && allPagesInput.checked)
  6356. {
  6357. lastFound = null;
  6358. allChecked = true;
  6359. return search(true, trySameCell, stayOnPage);
  6360. }
  6361. lastFound = firstMatch;
  6362. graph.scrollCellToVisible(lastFound.cell);
  6363. if (graph.isEnabled() && !graph.isCellLocked(lastFound.cell))
  6364. {
  6365. if (!stayOnPage &&
  6366. (graph.getSelectionCell() != lastFound.cell ||
  6367. graph.getSelectionCount() != 1))
  6368. {
  6369. graph.setSelectionCell(lastFound.cell);
  6370. }
  6371. }
  6372. else
  6373. {
  6374. graph.highlightCell(lastFound.cell);
  6375. }
  6376. }
  6377. //Check other pages
  6378. else if (!internalCall && allPagesInput.checked)
  6379. {
  6380. allChecked = true;
  6381. return search(true, trySameCell, stayOnPage);
  6382. }
  6383. else if (graph.isEnabled() && !stayOnPage)
  6384. {
  6385. graph.clearSelection();
  6386. }
  6387. lastSearchSuccessful = firstMatch != null;
  6388. if (withReplace && !internalCall)
  6389. {
  6390. updateReplBtns();
  6391. }
  6392. return searchStr.length == 0 || firstMatch != null;
  6393. };
  6394. mxUtils.br(div);
  6395. var btnsCont = document.createElement('div');
  6396. btnsCont.style.left = '0px';
  6397. btnsCont.style.right = '0px';
  6398. btnsCont.style.marginTop = '6px';
  6399. btnsCont.style.padding = '0 6px 0 6px';
  6400. btnsCont.style.textAlign = 'center';
  6401. div.appendChild(btnsCont);
  6402. var resetBtn = mxUtils.button(mxResources.get('reset'), function()
  6403. {
  6404. replAllNotif.innerText = '';
  6405. searchInput.value = '';
  6406. searchInput.style.backgroundColor = '';
  6407. if (withReplace)
  6408. {
  6409. replaceInput.value = '';
  6410. updateReplBtns();
  6411. }
  6412. lastFound = null;
  6413. lastSearch = null;
  6414. allChecked = false;
  6415. searchInput.focus();
  6416. });
  6417. resetBtn.setAttribute('title', mxResources.get('reset'));
  6418. resetBtn.style.float = 'none';
  6419. resetBtn.style.width = '120px';
  6420. resetBtn.style.marginTop = '6px';
  6421. resetBtn.style.marginLeft = '8px';
  6422. resetBtn.style.overflow = 'hidden';
  6423. resetBtn.style.textOverflow = 'ellipsis';
  6424. resetBtn.className = 'geBtn';
  6425. if (!withReplace)
  6426. {
  6427. btnsCont.appendChild(resetBtn);
  6428. }
  6429. var btn = mxUtils.button(mxResources.get('find'), function()
  6430. {
  6431. try
  6432. {
  6433. searchInput.style.backgroundColor = search() ? '' :
  6434. (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf');
  6435. }
  6436. catch (e)
  6437. {
  6438. ui.handleError(e);
  6439. }
  6440. });
  6441. // TODO: Reset state after selection change
  6442. btn.setAttribute('title', mxResources.get('find') + ' (Enter)');
  6443. btn.style.float = 'none';
  6444. btn.style.width = '120px';
  6445. btn.style.marginTop = '6px';
  6446. btn.style.marginLeft = '8px';
  6447. btn.style.overflow = 'hidden';
  6448. btn.style.textOverflow = 'ellipsis';
  6449. btn.className = 'geBtn gePrimaryBtn';
  6450. btnsCont.appendChild(btn);
  6451. var replAllNotif = document.createElement('div');
  6452. replAllNotif.style.marginTop = '10px';
  6453. if (!withReplace)
  6454. {
  6455. resetBtn.style.width = '90px';
  6456. btn.style.width = '90px';
  6457. }
  6458. else
  6459. {
  6460. function replaceInLabel(str, substr, newSubstr, startIndex, style)
  6461. {
  6462. if (style == null || style['html'] != '1')
  6463. {
  6464. var replStart = str.toLowerCase().indexOf(substr, startIndex);
  6465. return replStart < 0? str : str.substr(0, replStart) + newSubstr + str.substr(replStart + substr.length);
  6466. }
  6467. var origStr = str;
  6468. substr = mxUtils.htmlEntities(substr);
  6469. var tagPos = [], p = -1;
  6470. //Original position (startIndex) counts for \n which is removed when tags are removed, so handle <br> separately
  6471. str = str.replace(/<br>/ig, '\n');
  6472. while((p = str.indexOf('<', p + 1)) > -1)
  6473. {
  6474. tagPos.push(p);
  6475. }
  6476. var tags = str.match(/<[^>]*>/g);
  6477. str = str.replace(/<[^>]*>/g, '');
  6478. var lStr = str.toLowerCase();
  6479. var replStart = lStr.indexOf(substr, startIndex);
  6480. if (replStart < 0)
  6481. {
  6482. return origStr;
  6483. }
  6484. var replEnd = replStart + substr.length;
  6485. var newSubstr = mxUtils.htmlEntities(newSubstr);
  6486. //Tags within the replaced text is added before it
  6487. var newStr = str.substr(0, replStart) + newSubstr + str.substr(replEnd);
  6488. var tagDiff = 0;
  6489. for (var i = 0; i < tagPos.length; i++)
  6490. {
  6491. if (tagPos[i] - tagDiff < replStart)
  6492. {
  6493. newStr = newStr.substr(0, tagPos[i]) + tags[i] + newStr.substr(tagPos[i]);
  6494. }
  6495. else if (tagPos[i] - tagDiff < replEnd)
  6496. {
  6497. var inPos = replStart + tagDiff;
  6498. newStr = newStr.substr(0, inPos) + tags[i] + newStr.substr(inPos);
  6499. }
  6500. else
  6501. {
  6502. var inPos = tagPos[i] + (newSubstr.length - substr.length);
  6503. newStr = newStr.substr(0, inPos) + tags[i] + newStr.substr(inPos);
  6504. }
  6505. tagDiff += tags[i].length;
  6506. }
  6507. return newStr.replace(/\n/g, '<br>');
  6508. };
  6509. var replaceFindBtn = mxUtils.button(mxResources.get('replFind'), function()
  6510. {
  6511. try
  6512. {
  6513. if (lblMatch != null && lastFound != null && replaceInput.value)
  6514. {
  6515. var cell = lastFound.cell, lbl = graph.getLabel(cell);
  6516. if (graph.isCellEditable(cell))
  6517. {
  6518. graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value,
  6519. lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell)));
  6520. }
  6521. searchInput.style.backgroundColor = search(false, true) ? '' :
  6522. (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf');
  6523. }
  6524. }
  6525. catch (e)
  6526. {
  6527. ui.handleError(e);
  6528. }
  6529. });
  6530. replaceFindBtn.setAttribute('title', mxResources.get('replFind'));
  6531. replaceFindBtn.style.float = 'none';
  6532. replaceFindBtn.style.width = '120px';
  6533. replaceFindBtn.style.marginTop = '6px';
  6534. replaceFindBtn.style.marginLeft = '8px';
  6535. replaceFindBtn.style.overflow = 'hidden';
  6536. replaceFindBtn.style.textOverflow = 'ellipsis';
  6537. replaceFindBtn.className = 'geBtn gePrimaryBtn';
  6538. replaceFindBtn.setAttribute('disabled', 'disabled');
  6539. btnsCont.appendChild(replaceFindBtn);
  6540. mxUtils.br(btnsCont);
  6541. var replaceBtn = mxUtils.button(mxResources.get('replace'), function()
  6542. {
  6543. try
  6544. {
  6545. if (lblMatch != null && lastFound != null && replaceInput.value)
  6546. {
  6547. var cell = lastFound.cell, lbl = graph.getLabel(cell);
  6548. graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value, lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell)));
  6549. replaceFindBtn.setAttribute('disabled', 'disabled');
  6550. replaceBtn.setAttribute('disabled', 'disabled');
  6551. }
  6552. }
  6553. catch (e)
  6554. {
  6555. ui.handleError(e);
  6556. }
  6557. });
  6558. replaceBtn.setAttribute('title', mxResources.get('replace'));
  6559. replaceBtn.style.float = 'none';
  6560. replaceBtn.style.width = '120px';
  6561. replaceBtn.style.marginTop = '6px';
  6562. replaceBtn.style.marginLeft = '8px';
  6563. replaceBtn.style.overflow = 'hidden';
  6564. replaceBtn.style.textOverflow = 'ellipsis';
  6565. replaceBtn.className = 'geBtn gePrimaryBtn';
  6566. replaceBtn.setAttribute('disabled', 'disabled');
  6567. btnsCont.appendChild(replaceBtn);
  6568. var replaceAllBtn = mxUtils.button(mxResources.get('replaceAll'), function()
  6569. {
  6570. replAllNotif.innerText = '';
  6571. if (replaceInput.value)
  6572. {
  6573. lastSearch = null; // Reset last search to check all matches
  6574. var currentPage = ui.currentPage;
  6575. var cells = ui.editor.graph.getSelectionCells();
  6576. ui.editor.graph.rendering = false;
  6577. graph.getModel().beginUpdate();
  6578. try
  6579. {
  6580. var safeguard = 0;
  6581. var seen = {};
  6582. while (search(false, true, true) && safeguard < 100)
  6583. {
  6584. var cell = lastFound.cell, lbl = graph.getLabel(cell);
  6585. var oldSeen = seen[cell.id];
  6586. if (oldSeen && oldSeen.replAllMrk == marker && oldSeen.replAllPos >= lblMatchPos)
  6587. {
  6588. break;
  6589. }
  6590. seen[cell.id] = {replAllMrk: marker, replAllPos: lblMatchPos};
  6591. if (graph.isCellEditable(cell))
  6592. {
  6593. graph.model.setValue(cell, replaceInLabel(lbl, lblMatch, replaceInput.value,
  6594. lblMatchPos - lblMatch.length, graph.getCurrentCellStyle(cell)));
  6595. safeguard++;
  6596. }
  6597. }
  6598. if (currentPage != ui.currentPage)
  6599. {
  6600. ui.editor.graph.model.execute(new SelectPage(ui, currentPage));
  6601. }
  6602. mxUtils.write(replAllNotif, mxResources.get('matchesRepl', [safeguard]));
  6603. }
  6604. catch (e)
  6605. {
  6606. ui.handleError(e);
  6607. }
  6608. finally
  6609. {
  6610. graph.getModel().endUpdate();
  6611. ui.editor.graph.setSelectionCells(cells);
  6612. ui.editor.graph.rendering = true;
  6613. }
  6614. marker++;
  6615. }
  6616. });
  6617. replaceAllBtn.setAttribute('title', mxResources.get('replaceAll'));
  6618. replaceAllBtn.style.float = 'none';
  6619. replaceAllBtn.style.width = '120px';
  6620. replaceAllBtn.style.marginTop = '6px';
  6621. replaceAllBtn.style.marginLeft = '8px';
  6622. replaceAllBtn.style.overflow = 'hidden';
  6623. replaceAllBtn.style.textOverflow = 'ellipsis';
  6624. replaceAllBtn.className = 'geBtn gePrimaryBtn';
  6625. replaceAllBtn.setAttribute('disabled', 'disabled');
  6626. btnsCont.appendChild(replaceAllBtn);
  6627. mxUtils.br(btnsCont);
  6628. btnsCont.appendChild(resetBtn);
  6629. var closeBtn = mxUtils.button(mxResources.get('close'), mxUtils.bind(this, function()
  6630. {
  6631. this.window.setVisible(false);
  6632. }));
  6633. closeBtn.setAttribute('title', mxResources.get('close'));
  6634. closeBtn.style.float = 'none';
  6635. closeBtn.style.width = '120px';
  6636. closeBtn.style.marginTop = '6px';
  6637. closeBtn.style.marginLeft = '8px';
  6638. closeBtn.style.overflow = 'hidden';
  6639. closeBtn.style.textOverflow = 'ellipsis';
  6640. closeBtn.className = 'geBtn';
  6641. btnsCont.appendChild(closeBtn);
  6642. mxUtils.br(btnsCont);
  6643. btnsCont.appendChild(replAllNotif);
  6644. }
  6645. mxEvent.addListener(searchInput, 'keyup', function(evt)
  6646. {
  6647. // Ctrl or Cmd keys
  6648. if (evt.keyCode == 91 || evt.keyCode == 93 || evt.keyCode == 17)
  6649. {
  6650. // Workaround for lost focus on show
  6651. mxEvent.consume(evt);
  6652. }
  6653. else if (evt.keyCode == 27)
  6654. {
  6655. // Escape closes window
  6656. action.funct();
  6657. }
  6658. else if (lastSearch != searchInput.value.toLowerCase() || evt.keyCode == 13)
  6659. {
  6660. try
  6661. {
  6662. searchInput.style.backgroundColor = search() ? '' :
  6663. (Editor.isDarkMode() ? '#ff0000' : '#ffcfcf');
  6664. }
  6665. catch (e)
  6666. {
  6667. searchInput.style.backgroundColor = Editor.isDarkMode() ? '#ff0000' : '#ffcfcf';
  6668. }
  6669. }
  6670. });
  6671. // Ctrl+F closes window
  6672. mxEvent.addListener(div, 'keydown', function(evt)
  6673. {
  6674. if (evt.keyCode == 70 && ui.keyHandler.isControlDown(evt) && !mxEvent.isShiftDown(evt))
  6675. {
  6676. action.funct();
  6677. mxEvent.consume(evt);
  6678. }
  6679. });
  6680. this.window = new mxWindow(mxResources.get('find') + ((withReplace) ?
  6681. '/' + mxResources.get('replace') : ''),
  6682. div, x, y, w, h, true, true);
  6683. this.window.destroyOnClose = false;
  6684. this.window.setMaximizable(false);
  6685. this.window.setResizable(false);
  6686. this.window.setClosable(true);
  6687. this.window.addListener('show', mxUtils.bind(this, function()
  6688. {
  6689. this.window.fit();
  6690. if (this.window.isVisible())
  6691. {
  6692. searchInput.focus();
  6693. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  6694. {
  6695. searchInput.select();
  6696. }
  6697. else
  6698. {
  6699. document.execCommand('selectAll', false, null);
  6700. }
  6701. if (ui.pages != null && ui.pages.length > 1)
  6702. {
  6703. allPagesInput.removeAttribute('disabled');
  6704. }
  6705. else
  6706. {
  6707. allPagesInput.checked = false;
  6708. allPagesInput.setAttribute('disabled', 'disabled');
  6709. }
  6710. }
  6711. else
  6712. {
  6713. graph.container.focus();
  6714. }
  6715. }));
  6716. ui.installResizeHandler(this, false);
  6717. };
  6718. /**
  6719. *
  6720. */
  6721. var FreehandWindow = function(editorUi, x, y, w, h, withBrush)
  6722. {
  6723. var graph = editorUi.editor.graph;
  6724. var div = document.createElement('div');
  6725. div.style.textAlign = 'center';
  6726. div.style.userSelect = 'none';
  6727. div.style.overflow = 'hidden';
  6728. div.style.height = '100%';
  6729. if (withBrush)
  6730. {
  6731. var brushInput = document.createElement('input');
  6732. brushInput.setAttribute('id', 'geFreehandBrush');
  6733. brushInput.setAttribute('type', 'checkbox');
  6734. brushInput.checked = graph.freehand.isPerfectFreehandMode();
  6735. brushInput.style.margin = '10px 5px 0px 10px';
  6736. brushInput.style.float = 'left';
  6737. div.appendChild(brushInput);
  6738. var brushLabel = document.createElement('label');
  6739. brushLabel.setAttribute('for', 'geFreehandBrush');
  6740. brushLabel.style.float = 'left';
  6741. brushLabel.style.marginTop = '10px';
  6742. div.appendChild(brushLabel);
  6743. mxUtils.write(brushLabel, mxResources.get('brush'));
  6744. div.appendChild(brushLabel);
  6745. mxUtils.br(div);
  6746. var brushSize = document.createElement('input');
  6747. brushSize.setAttribute('type', 'range');
  6748. brushSize.setAttribute('min', '2');
  6749. brushSize.setAttribute('max', '30');
  6750. brushSize.setAttribute('value', graph.freehand.getBrushSize());
  6751. brushSize.style.width = '90%';
  6752. brushSize.style.visibility = 'hidden';
  6753. div.appendChild(brushSize);
  6754. mxUtils.br(div);
  6755. var updateBrushState = function()
  6756. {
  6757. graph.freehand.setPerfectFreehandMode(brushInput.checked)
  6758. brushSize.style.visibility = brushInput.checked? 'visible' : 'hidden';
  6759. };
  6760. mxEvent.addListener(brushInput, 'change', updateBrushState);
  6761. updateBrushState();
  6762. mxEvent.addListener(brushSize, 'change', function()
  6763. {
  6764. graph.freehand.setBrushSize(parseInt(this.value));
  6765. });
  6766. }
  6767. var startBtn = mxUtils.button(mxResources.get('startDrawing'), function()
  6768. {
  6769. if (graph.freehand.isDrawing())
  6770. {
  6771. graph.freehand.stopDrawing();
  6772. }
  6773. else
  6774. {
  6775. graph.freehand.startDrawing();
  6776. }
  6777. });
  6778. startBtn.setAttribute('title', mxResources.get('startDrawing') + ' (X)');
  6779. startBtn.style.marginTop = withBrush? '5px' : '10px';
  6780. startBtn.style.width = '90%';
  6781. startBtn.style.boxSizing = 'border-box';
  6782. startBtn.style.overflow = 'hidden';
  6783. startBtn.style.textOverflow = 'ellipsis';
  6784. startBtn.style.textAlign = 'center';
  6785. startBtn.className = 'geBtn gePrimaryBtn';
  6786. div.appendChild(startBtn);
  6787. this.window = new mxWindow(mxResources.get('freehand'), div, x, y, w, h, true, true);
  6788. this.window.destroyOnClose = false;
  6789. this.window.setMaximizable(false);
  6790. this.window.setResizable(false);
  6791. this.window.setClosable(true);
  6792. graph.addListener('freehandStateChanged', mxUtils.bind(this, function()
  6793. {
  6794. startBtn.innerText = '';
  6795. mxUtils.write(startBtn, mxResources.get(graph.freehand.isDrawing() ? 'stopDrawing' : 'startDrawing'));
  6796. var shortcut = document.createElement('span');
  6797. shortcut.style.opacity = '0.7';
  6798. shortcut.style['float'] = 'right';
  6799. mxUtils.write(shortcut, 'X');
  6800. startBtn.appendChild(shortcut);
  6801. startBtn.setAttribute('title', mxResources.get(graph.freehand.isDrawing() ? 'stopDrawing' : 'startDrawing') + ' (X)');
  6802. startBtn.className = 'geBtn' + (graph.freehand.isDrawing() ? ' gePrimaryBtn' : '');
  6803. }));
  6804. this.window.addListener('show', mxUtils.bind(this, function()
  6805. {
  6806. this.window.fit();
  6807. }));
  6808. this.window.addListener('hide', mxUtils.bind(this, function()
  6809. {
  6810. if (graph.freehand.isDrawing())
  6811. {
  6812. graph.freehand.stopDrawing();
  6813. }
  6814. }));
  6815. editorUi.installResizeHandler(this, false);
  6816. };
  6817. /**
  6818. *
  6819. */
  6820. var TagsWindow = function(editorUi, x, y, w, h)
  6821. {
  6822. var graph = editorUi.editor.graph;
  6823. var tagsComponent = editorUi.editor.graph.createTagsDialog(mxUtils.bind(this, function()
  6824. {
  6825. return this.window.isVisible();
  6826. }), null, function(allTags, updateFn)
  6827. {
  6828. if (graph.isEnabled())
  6829. {
  6830. var dlg = new FilenameDialog(editorUi, '', mxResources.get('add'), function(newValue)
  6831. {
  6832. editorUi.hideDialog();
  6833. if (newValue != null && newValue.length > 0)
  6834. {
  6835. var temp = newValue.split(' ');
  6836. var tags = [];
  6837. for (var i = 0; i < temp.length; i++)
  6838. {
  6839. var token = mxUtils.trim(temp[i]);
  6840. if (token != '' && mxUtils.indexOf(
  6841. allTags, token) < 0)
  6842. {
  6843. tags.push(token);
  6844. }
  6845. }
  6846. if (tags.length > 0)
  6847. {
  6848. if (graph.isSelectionEmpty())
  6849. {
  6850. updateFn(allTags.concat(tags));
  6851. }
  6852. else
  6853. {
  6854. graph.addTagsForCells(graph.getSelectionCells(), tags);
  6855. }
  6856. }
  6857. }
  6858. }, mxResources.get('enterValue') + ' (' + mxResources.get('tags') + ')');
  6859. editorUi.showDialog(dlg.container, 300, 80, true, true);
  6860. dlg.init();
  6861. }
  6862. });
  6863. var div = tagsComponent.div;
  6864. this.window = new mxWindow(mxResources.get('tags'), div, x, y, w, h, true, true);
  6865. this.window.minimumSize = new mxRectangle(0, 0, 212, 120);
  6866. this.window.destroyOnClose = false;
  6867. this.window.setMaximizable(false);
  6868. this.window.setResizable(true);
  6869. this.window.setClosable(true);
  6870. this.window.addListener('show', mxUtils.bind(this, function()
  6871. {
  6872. tagsComponent.refresh();
  6873. this.window.fit();
  6874. }));
  6875. editorUi.installResizeHandler(this, true);
  6876. };
  6877. /**
  6878. * Constructs a new auth dialog.
  6879. */
  6880. var AuthDialog = function(editorUi, peer, showRememberOption, fn)
  6881. {
  6882. var div = document.createElement('div');
  6883. div.style.textAlign = 'center';
  6884. var hd = document.createElement('p');
  6885. hd.style.fontSize = '16pt';
  6886. hd.style.padding = '0px';
  6887. hd.style.margin = '0px';
  6888. hd.style.color = 'gray';
  6889. mxUtils.write(hd, mxResources.get('authorizationRequired'));
  6890. var service = 'Unknown';
  6891. var img = document.createElement('img');
  6892. img.setAttribute('border', '0');
  6893. img.setAttribute('align', 'absmiddle');
  6894. img.style.marginRight = '10px';
  6895. if (peer == editorUi.drive)
  6896. {
  6897. service = mxResources.get('googleDrive');
  6898. img.src = IMAGE_PATH + '/google-drive-logo-white.svg';
  6899. }
  6900. else if (peer == editorUi.dropbox)
  6901. {
  6902. service = mxResources.get('dropbox');
  6903. img.src = IMAGE_PATH + '/dropbox-logo-white.svg';
  6904. }
  6905. else if (peer == editorUi.oneDrive)
  6906. {
  6907. service = mxResources.get('oneDrive');
  6908. img.src = IMAGE_PATH + '/onedrive-logo-white.svg';
  6909. }
  6910. else if (peer == editorUi.gitHub)
  6911. {
  6912. service = mxResources.get('github');
  6913. img.src = IMAGE_PATH + '/github-logo-white.svg';
  6914. }
  6915. else if (peer == editorUi.gitLab)
  6916. {
  6917. service = mxResources.get('gitlab');
  6918. img.src = IMAGE_PATH + '/gitlab-logo.svg';
  6919. img.style.width = '32px';
  6920. }
  6921. else if (peer == editorUi.trello)
  6922. {
  6923. service = mxResources.get('trello');
  6924. img.src = IMAGE_PATH + '/trello-logo-white.svg';
  6925. }
  6926. var p = document.createElement('p');
  6927. mxUtils.write(p, mxResources.get('authorizeThisAppIn', [service]));
  6928. var cb = document.createElement('input');
  6929. cb.setAttribute('type', 'checkbox');
  6930. var button = mxUtils.button(mxResources.get('authorize'), function()
  6931. {
  6932. fn(cb.checked);
  6933. });
  6934. button.insertBefore(img, button.firstChild);
  6935. button.style.marginTop = '6px';
  6936. button.className = 'geBigButton';
  6937. button.style.fontSize = '18px';
  6938. button.style.padding = '14px';
  6939. div.appendChild(hd);
  6940. div.appendChild(p);
  6941. div.appendChild(button);
  6942. if (showRememberOption)
  6943. {
  6944. var p2 = document.createElement('p');
  6945. p2.style.marginTop = '20px';
  6946. p2.appendChild(cb);
  6947. var span = document.createElement('span');
  6948. mxUtils.write(span, ' ' + mxResources.get('rememberMe'));
  6949. p2.appendChild(span);
  6950. div.appendChild(p2);
  6951. cb.checked = true;
  6952. cb.defaultChecked = true;
  6953. mxEvent.addListener(span, 'click', function(evt)
  6954. {
  6955. cb.checked = !cb.checked;
  6956. mxEvent.consume(evt);
  6957. });
  6958. }
  6959. this.container = div;
  6960. };
  6961. var MoreShapesDialog = function(editorUi, expanded, entries)
  6962. {
  6963. entries = (entries != null) ? entries : editorUi.sidebar.entries;
  6964. var div = document.createElement('div');
  6965. var newEntries = [];
  6966. // Adds custom sections first
  6967. if (editorUi.sidebar.customEntries != null)
  6968. {
  6969. for (var i = 0; i < editorUi.sidebar.customEntries.length; i++)
  6970. {
  6971. var section = editorUi.sidebar.customEntries[i];
  6972. var tmp = {title: editorUi.getResource(section.title), entries: []};
  6973. for (var j = 0; j < section.entries.length; j++)
  6974. {
  6975. var entry = section.entries[j];
  6976. tmp.entries.push({id: entry.id, title:
  6977. editorUi.getResource(entry.title),
  6978. desc: editorUi.getResource(entry.desc),
  6979. image: entry.preview});
  6980. }
  6981. newEntries.push(tmp);
  6982. }
  6983. }
  6984. // Adds built-in sections and filter entries
  6985. for (var i = 0; i < entries.length; i++)
  6986. {
  6987. if (editorUi.sidebar.enabledLibraries == null)
  6988. {
  6989. newEntries.push(entries[i]);
  6990. }
  6991. else
  6992. {
  6993. var tmp = {title: entries[i].title, entries: []};
  6994. for (var j = 0; j < entries[i].entries.length; j++)
  6995. {
  6996. if (mxUtils.indexOf(editorUi.sidebar.enabledLibraries,
  6997. entries[i].entries[j].id) >= 0)
  6998. {
  6999. tmp.entries.push(entries[i].entries[j]);
  7000. }
  7001. }
  7002. if (tmp.entries.length > 0)
  7003. {
  7004. newEntries.push(tmp);
  7005. }
  7006. }
  7007. }
  7008. entries = newEntries;
  7009. if (expanded)
  7010. {
  7011. var addEntries = mxUtils.bind(this, function(e)
  7012. {
  7013. for (var i = 0; i < e.length; i++)
  7014. {
  7015. (function(section)
  7016. {
  7017. var title = listEntry.cloneNode(false);
  7018. title.style.fontWeight = 'bold';
  7019. title.style.backgroundColor = Editor.isDarkMode() ? '#505759' : '#e5e5e5';
  7020. title.style.padding = '6px 0px 6px 20px';
  7021. mxUtils.write(title, section.title);
  7022. list.appendChild(title);
  7023. for (var j = 0; j < section.entries.length; j++)
  7024. {
  7025. (function(entry)
  7026. {
  7027. var option = listEntry.cloneNode(false);
  7028. option.style.cursor = 'pointer';
  7029. option.style.padding = '4px 0px 4px 20px';
  7030. option.style.whiteSpace = 'nowrap';
  7031. option.style.overflow = 'hidden';
  7032. option.style.textOverflow = 'ellipsis';
  7033. option.setAttribute('title', entry.title + ' (' + entry.id + ')');
  7034. var checkbox = document.createElement('input');
  7035. checkbox.setAttribute('type', 'checkbox');
  7036. checkbox.checked = editorUi.sidebar.isEntryVisible(entry.id);
  7037. checkbox.defaultChecked = checkbox.checked;
  7038. option.appendChild(checkbox);
  7039. mxUtils.write(option, ' ' + entry.title);
  7040. list.appendChild(option);
  7041. var itemClicked = function(evt)
  7042. {
  7043. if (evt == null || mxEvent.getSource(evt).nodeName != 'INPUT')
  7044. {
  7045. preview.style.textAlign = 'center';
  7046. preview.style.padding = '0px';
  7047. preview.style.color = '';
  7048. preview.innerText = '';
  7049. if (entry.desc != null)
  7050. {
  7051. var pre = document.createElement('pre');
  7052. pre.style.boxSizing = 'border-box';
  7053. pre.style.fontFamily = 'inherit';
  7054. pre.style.margin = '20px';
  7055. pre.style.right = '0px';
  7056. pre.style.textAlign = 'left';
  7057. mxUtils.write(pre, entry.desc);
  7058. preview.appendChild(pre);
  7059. }
  7060. if (entry.imageCallback != null)
  7061. {
  7062. entry.imageCallback(preview);
  7063. }
  7064. else if (entry.image != null)
  7065. {
  7066. preview.innerHTML += '<img border="0" style="max-width:100%;" src="' + entry.image + '"/>';
  7067. }
  7068. else if (entry.desc == null)
  7069. {
  7070. preview.style.padding = '20px';
  7071. preview.style.color = 'rgb(179, 179, 179)';
  7072. mxUtils.write(preview, mxResources.get('noPreview'));
  7073. }
  7074. if (currentListItem != null)
  7075. {
  7076. currentListItem.style.backgroundColor = '';
  7077. }
  7078. currentListItem = option;
  7079. currentListItem.style.backgroundColor = Editor.isDarkMode() ? '#000000' : '#ebf2f9';
  7080. if (evt != null)
  7081. {
  7082. mxEvent.consume(evt);
  7083. }
  7084. }
  7085. };
  7086. mxEvent.addListener(option, 'click', itemClicked);
  7087. mxEvent.addListener(option, 'dblclick', function(evt)
  7088. {
  7089. checkbox.checked = !checkbox.checked;
  7090. mxEvent.consume(evt);
  7091. });
  7092. applyFunctions.push(function()
  7093. {
  7094. return (checkbox.checked) ? entry.id : null;
  7095. });
  7096. // Selects first entry
  7097. if (i == 0 && j == 0)
  7098. {
  7099. itemClicked();
  7100. }
  7101. })(section.entries[j]);
  7102. }
  7103. })(e[i]);
  7104. }
  7105. });
  7106. var hd = document.createElement('div');
  7107. hd.className = 'geDialogTitle';
  7108. mxUtils.write(hd, mxResources.get('shapes'));
  7109. hd.style.position = 'absolute';
  7110. hd.style.top = '0px';
  7111. hd.style.left = '0px';
  7112. hd.style.lineHeight = '40px';
  7113. hd.style.height = '40px';
  7114. hd.style.right = '0px';
  7115. var list = document.createElement('div');
  7116. var preview = document.createElement('div');
  7117. list.style.position = 'absolute';
  7118. list.style.top = '40px';
  7119. list.style.left = '0px';
  7120. list.style.width = '202px';
  7121. list.style.bottom = '60px';
  7122. list.style.overflow = 'auto';
  7123. preview.style.position = 'absolute';
  7124. preview.style.left = '202px';
  7125. preview.style.right = '0px';
  7126. preview.style.top = '40px';
  7127. preview.style.bottom = '60px';
  7128. preview.style.overflow = 'auto';
  7129. preview.style.borderLeftStyle = 'solid';
  7130. preview.style.borderLeftWidth = '1px';
  7131. preview.style.textAlign = 'center';
  7132. var currentListItem = null;
  7133. var applyFunctions = [];
  7134. var listEntry = document.createElement('div');
  7135. listEntry.style.position = 'relative';
  7136. listEntry.style.left = '0px';
  7137. listEntry.style.right = '0px';
  7138. addEntries(entries);
  7139. div.style.padding = '30px';
  7140. div.appendChild(hd);
  7141. div.appendChild(list);
  7142. div.appendChild(preview);
  7143. var buttons = document.createElement('div');
  7144. buttons.className = 'geDialogFooter';
  7145. buttons.style.position = 'absolute';
  7146. buttons.style.paddingRight = '16px';
  7147. buttons.style.color = 'gray';
  7148. buttons.style.left = '0px';
  7149. buttons.style.right = '0px';
  7150. buttons.style.bottom = '0px';
  7151. buttons.style.height = '60px';
  7152. buttons.style.lineHeight = '52px';
  7153. var labels = document.createElement('input');
  7154. labels.setAttribute('type', 'checkbox');
  7155. labels.style.position = 'relative';
  7156. labels.style.top = '1px';
  7157. labels.checked = editorUi.sidebar.sidebarTitles;
  7158. labels.defaultChecked = labels.checked;
  7159. buttons.appendChild(labels);
  7160. var span = document.createElement('span');
  7161. mxUtils.write(span, ' ' + mxResources.get('labels'));
  7162. span.style.paddingRight = '20px';
  7163. buttons.appendChild(span);
  7164. mxEvent.addListener(span, 'click', function(evt)
  7165. {
  7166. labels.checked = !labels.checked;
  7167. mxEvent.consume(evt);
  7168. });
  7169. var cb = document.createElement('input');
  7170. cb.setAttribute('type', 'checkbox');
  7171. if (isLocalStorage || mxClient.IS_CHROMEAPP)
  7172. {
  7173. var span = document.createElement('span');
  7174. span.style.paddingRight = '20px';
  7175. span.appendChild(cb);
  7176. mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting'));
  7177. cb.style.position = 'relative';
  7178. cb.style.top = '1px';
  7179. cb.checked = true;
  7180. cb.defaultChecked = true;
  7181. mxEvent.addListener(span, 'click', function(evt)
  7182. {
  7183. if (mxEvent.getSource(evt) != cb)
  7184. {
  7185. cb.checked = !cb.checked;
  7186. mxEvent.consume(evt);
  7187. }
  7188. });
  7189. buttons.appendChild(span);
  7190. }
  7191. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  7192. {
  7193. editorUi.hideDialog();
  7194. });
  7195. cancelBtn.className = 'geBtn';
  7196. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  7197. {
  7198. editorUi.hideDialog();
  7199. var libs = [];
  7200. for (var i = 0; i < applyFunctions.length; i++)
  7201. {
  7202. var lib = applyFunctions[i].apply(this, arguments);
  7203. if (lib != null)
  7204. {
  7205. libs.push(lib);
  7206. }
  7207. }
  7208. // Redirects scratchpad and search entries
  7209. if ((Editor.currentTheme == 'sketch' ||
  7210. Editor.currentTheme == 'min') &&
  7211. Editor.isSettingsEnabled())
  7212. {
  7213. var idx = mxUtils.indexOf(libs, '.scratchpad');
  7214. if ((editorUi.scratchpad != null) != (idx >= 0 && libs.splice(idx, 1).length > 0))
  7215. {
  7216. editorUi.toggleScratchpad();
  7217. }
  7218. // Handles search after scratchpad
  7219. idx = mxUtils.indexOf(libs, 'search');
  7220. mxSettings.settings.search = (idx >= 0 && libs.splice(idx, 1).length > 0);
  7221. editorUi.sidebar.showPalette('search', mxSettings.settings.search);
  7222. if (cb.checked)
  7223. {
  7224. mxSettings.save();
  7225. }
  7226. }
  7227. editorUi.sidebar.showEntries(libs.join(';'), cb.checked, true);
  7228. editorUi.setSidebarTitles(labels.checked, cb.checked);
  7229. });
  7230. applyBtn.className = 'geBtn gePrimaryBtn';
  7231. if (editorUi.editor.cancelFirst)
  7232. {
  7233. buttons.appendChild(cancelBtn);
  7234. buttons.appendChild(applyBtn);
  7235. }
  7236. else
  7237. {
  7238. buttons.appendChild(applyBtn);
  7239. buttons.appendChild(cancelBtn);
  7240. }
  7241. div.appendChild(buttons);
  7242. }
  7243. else
  7244. {
  7245. var libFS = document.createElement('table');
  7246. var tbody = document.createElement('tbody');
  7247. div.style.height = '100%';
  7248. div.style.overflow = 'auto';
  7249. var row = document.createElement('tr');
  7250. libFS.style.width = '100%';
  7251. var leftDiv = document.createElement('td');
  7252. var midDiv = document.createElement('td');
  7253. var rightDiv = document.createElement('td');
  7254. var addLibCB = mxUtils.bind(this, function(wrapperDiv, title, key)
  7255. {
  7256. var libCB = document.createElement('input');
  7257. libCB.type = 'checkbox';
  7258. libFS.appendChild(libCB);
  7259. libCB.checked = editorUi.sidebar.isEntryVisible(key);
  7260. var libSpan = document.createElement('span');
  7261. mxUtils.write(libSpan, title);
  7262. var label = document.createElement('div');
  7263. label.style.display = 'block';
  7264. label.appendChild(libCB);
  7265. label.appendChild(libSpan);
  7266. mxEvent.addListener(libSpan, 'click', function(evt)
  7267. {
  7268. libCB.checked = !libCB.checked;
  7269. mxEvent.consume(evt);
  7270. });
  7271. wrapperDiv.appendChild(label);
  7272. return function()
  7273. {
  7274. return (libCB.checked) ? key : null;
  7275. };
  7276. });
  7277. row.appendChild(leftDiv);
  7278. row.appendChild(midDiv);
  7279. row.appendChild(rightDiv);
  7280. tbody.appendChild(row);
  7281. libFS.appendChild(tbody);
  7282. var applyFunctions = [];
  7283. var count = 0;
  7284. // Counts total number of entries
  7285. for (var i = 0; i < entries.length; i++)
  7286. {
  7287. for (var j = 0; j < entries[i].entries.length; j++)
  7288. {
  7289. count++;
  7290. }
  7291. }
  7292. // Distributes entries on columns
  7293. var cols = [leftDiv, midDiv, rightDiv];
  7294. var counter = 0;
  7295. for (var i = 0; i < entries.length; i++)
  7296. {
  7297. (function(section)
  7298. {
  7299. for (var j = 0; j < section.entries.length; j++)
  7300. {
  7301. (function(entry)
  7302. {
  7303. var index = Math.floor(counter / (count / 3));
  7304. applyFunctions.push(addLibCB(cols[index], entry.title, entry.id));
  7305. counter++;
  7306. })(section.entries[j]);
  7307. }
  7308. })(entries[i]);
  7309. }
  7310. div.appendChild(libFS);
  7311. var remember = document.createElement('div');
  7312. remember.style.marginTop = '18px';
  7313. remember.style.textAlign = 'center';
  7314. var cb = document.createElement('input');
  7315. if (isLocalStorage)
  7316. {
  7317. cb.setAttribute('type', 'checkbox');
  7318. cb.checked = true;
  7319. cb.defaultChecked = true;
  7320. remember.appendChild(cb);
  7321. var span = document.createElement('span');
  7322. mxUtils.write(span, ' ' + mxResources.get('rememberThisSetting'));
  7323. remember.appendChild(span);
  7324. mxEvent.addListener(span, 'click', function(evt)
  7325. {
  7326. cb.checked = !cb.checked;
  7327. mxEvent.consume(evt);
  7328. });
  7329. }
  7330. div.appendChild(remember);
  7331. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  7332. {
  7333. editorUi.hideDialog();
  7334. });
  7335. cancelBtn.className = 'geBtn';
  7336. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  7337. {
  7338. var libs = ['search'];
  7339. for (var i = 0; i < applyFunctions.length; i++)
  7340. {
  7341. var lib = applyFunctions[i].apply(this, arguments);
  7342. if (lib != null)
  7343. {
  7344. libs.push(lib);
  7345. }
  7346. }
  7347. editorUi.sidebar.showEntries((libs.length > 0) ? libs.join(';') : '', cb.checked);
  7348. editorUi.hideDialog();
  7349. });
  7350. applyBtn.className = 'geBtn gePrimaryBtn';
  7351. var buttons = document.createElement('div');
  7352. buttons.style.marginTop = '26px';
  7353. buttons.style.textAlign = 'right';
  7354. if (editorUi.editor.cancelFirst)
  7355. {
  7356. buttons.appendChild(cancelBtn);
  7357. buttons.appendChild(applyBtn);
  7358. }
  7359. else
  7360. {
  7361. buttons.appendChild(applyBtn);
  7362. buttons.appendChild(cancelBtn);
  7363. }
  7364. div.appendChild(buttons);
  7365. }
  7366. this.container = div;
  7367. };
  7368. var PluginsDialog = function(editorUi, addFn, delFn, closeOnly)
  7369. {
  7370. var div = document.createElement('div');
  7371. var inner = document.createElement('div');
  7372. inner.style.height = '180px';
  7373. inner.style.overflow = 'auto';
  7374. var plugins = mxSettings.getPlugins().slice();
  7375. var changed = false;
  7376. function refresh()
  7377. {
  7378. changed = true;
  7379. if (plugins.length == 0)
  7380. {
  7381. inner.innerText = mxResources.get('noPlugins');
  7382. }
  7383. else
  7384. {
  7385. inner.innerText = '';
  7386. for (var i = 0; i < plugins.length; i++)
  7387. {
  7388. var span = document.createElement('span');
  7389. span.style.whiteSpace = 'nowrap';
  7390. var img = document.createElement('span');
  7391. img.className = 'geSprite geSprite-delete';
  7392. img.style.position = 'relative';
  7393. img.style.cursor = 'pointer';
  7394. img.style.top = '5px';
  7395. img.style.marginRight = '4px';
  7396. img.style.display = 'inline-block';
  7397. span.appendChild(img);
  7398. mxUtils.write(span, plugins[i]);
  7399. inner.appendChild(span);
  7400. mxUtils.br(inner);
  7401. mxEvent.addListener(img, 'click', (function(index)
  7402. {
  7403. return function()
  7404. {
  7405. editorUi.confirm(mxResources.get('delete') + ' "' + plugins[index] + '"?', function()
  7406. {
  7407. if (delFn != null)
  7408. {
  7409. delFn(plugins[index]);
  7410. }
  7411. plugins.splice(index, 1);
  7412. refresh();
  7413. });
  7414. };
  7415. })(i));
  7416. }
  7417. }
  7418. }
  7419. div.appendChild(inner);
  7420. refresh();
  7421. changed = false;
  7422. var addBtn = mxUtils.button(mxResources.get('add'), addFn != null? function()
  7423. {
  7424. addFn(function(newPlugin)
  7425. {
  7426. if (newPlugin && mxUtils.indexOf(plugins, newPlugin) < 0)
  7427. {
  7428. plugins.push(newPlugin);
  7429. }
  7430. refresh();
  7431. });
  7432. }
  7433. : function()
  7434. {
  7435. var div = document.createElement('div');
  7436. var title = document.createElement('span');
  7437. title.style.marginTop = '6px';
  7438. mxUtils.write(title, mxResources.get('builtinPlugins') + ': ');
  7439. div.appendChild(title);
  7440. var pluginsSelect = document.createElement('select');
  7441. pluginsSelect.style.width = '150px';
  7442. for (var i = 0; i < App.publicPlugin.length; i++)
  7443. {
  7444. var option = document.createElement('option');
  7445. mxUtils.write(option, App.publicPlugin[i]);
  7446. option.value = App.publicPlugin[i];
  7447. pluginsSelect.appendChild(option);
  7448. }
  7449. div.appendChild(pluginsSelect);
  7450. mxUtils.br(div);
  7451. mxUtils.br(div);
  7452. var customBtn = mxUtils.button(mxResources.get('custom') + '...', function()
  7453. {
  7454. var dlg = new FilenameDialog(editorUi, '', mxResources.get('add'), function(newValue)
  7455. {
  7456. editorUi.hideDialog();
  7457. if (newValue != null && newValue.length > 0)
  7458. {
  7459. var tokens = newValue.split(';');
  7460. for (var i = 0; i < tokens.length; i++)
  7461. {
  7462. var token = tokens[i];
  7463. var url = App.pluginRegistry[token];
  7464. if (url != null)
  7465. {
  7466. token = url;
  7467. }
  7468. if (token.length > 0 && mxUtils.indexOf(plugins, token) < 0)
  7469. {
  7470. plugins.push(token);
  7471. }
  7472. }
  7473. refresh();
  7474. }
  7475. }, mxResources.get('enterValue') + ' (' + mxResources.get('url') + ')');
  7476. editorUi.showDialog(dlg.container, 300, 80, true, true);
  7477. dlg.init();
  7478. });
  7479. customBtn.className = 'geBtn';
  7480. if (!ALLOW_CUSTOM_PLUGINS)
  7481. {
  7482. customBtn.style.display = 'none';
  7483. }
  7484. var dlg = new CustomDialog(editorUi, div, mxUtils.bind(this, function()
  7485. {
  7486. var token = App.pluginRegistry[pluginsSelect.value];
  7487. if (mxUtils.indexOf(plugins, token) < 0)
  7488. {
  7489. plugins.push(token);
  7490. refresh();
  7491. }
  7492. }), null, null, null, customBtn);
  7493. editorUi.showDialog(dlg.container, 360, 100, true, true);
  7494. });
  7495. addBtn.className = 'geBtn';
  7496. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  7497. {
  7498. editorUi.hideDialog();
  7499. });
  7500. cancelBtn.className = 'geBtn';
  7501. var applyBtn = mxUtils.button(closeOnly? mxResources.get('close') : mxResources.get('apply'), function()
  7502. {
  7503. if (changed)
  7504. {
  7505. mxSettings.setPlugins(plugins);
  7506. mxSettings.save();
  7507. editorUi.hideDialog();
  7508. editorUi.alert(mxResources.get('restartForChangeRequired'));
  7509. }
  7510. else
  7511. {
  7512. editorUi.hideDialog();
  7513. }
  7514. });
  7515. applyBtn.className = 'geBtn gePrimaryBtn';
  7516. var buttons = document.createElement('div');
  7517. buttons.style.marginTop = '14px';
  7518. buttons.style.textAlign = 'right';
  7519. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  7520. {
  7521. editorUi.openLink('https://www.diagrams.net/doc/faq/plugins');
  7522. });
  7523. helpBtn.className = 'geBtn';
  7524. if (editorUi.isOffline() && !mxClient.IS_CHROMEAPP)
  7525. {
  7526. helpBtn.style.display = 'none';
  7527. }
  7528. buttons.appendChild(helpBtn);
  7529. if (editorUi.editor.cancelFirst)
  7530. {
  7531. if (!closeOnly)
  7532. {
  7533. buttons.appendChild(cancelBtn);
  7534. }
  7535. buttons.appendChild(addBtn);
  7536. buttons.appendChild(applyBtn);
  7537. }
  7538. else
  7539. {
  7540. buttons.appendChild(addBtn);
  7541. buttons.appendChild(applyBtn);
  7542. if (!closeOnly)
  7543. {
  7544. buttons.appendChild(cancelBtn);
  7545. }
  7546. }
  7547. div.appendChild(buttons);
  7548. this.container = div;
  7549. };
  7550. var CropImageDialog = function(editorUi, image, clipPath, fn)
  7551. {
  7552. var IMAGE_SIZE = 300;
  7553. var div = document.createElement('div');
  7554. var elt = document.createElement('div');
  7555. elt.style.height = IMAGE_SIZE + 'px';
  7556. elt.style.width = IMAGE_SIZE + 'px';
  7557. elt.style.display = 'inline-flex';
  7558. elt.style.justifyContent = 'center';
  7559. elt.style.alignItems = 'center';
  7560. elt.style.position = 'absolute';
  7561. var img = document.createElement('img');
  7562. img.onload = init;
  7563. img.onerror = function ()
  7564. {
  7565. img.onload = null;
  7566. img.src = Editor.errorImage;
  7567. }
  7568. img.setAttribute('src', image);
  7569. img.style.maxWidth = IMAGE_SIZE + 'px';
  7570. img.style.maxHeight = IMAGE_SIZE + 'px';
  7571. elt.appendChild(img);
  7572. div.appendChild(elt);
  7573. var croppingDiv = document.createElement('div');
  7574. croppingDiv.style.width = IMAGE_SIZE + 'px';
  7575. croppingDiv.style.height = IMAGE_SIZE + 'px';
  7576. croppingDiv.style.overflow = 'hidden';
  7577. croppingDiv.style.backgroundColor = '#fff9';
  7578. div.appendChild(croppingDiv);
  7579. var cropGraph = null, initGeo = new mxGeometry(100, 100, 100, 100),
  7580. arcSizeVal = 5, cropCell = new mxCell('', initGeo.clone(), ''),
  7581. commonStyle = 'shape=image;fillColor=none;rotatable=0;cloneable=0;deletable=0;image=' +
  7582. image.replace(';base64', '') + ';clipPath=';
  7583. function init()
  7584. {
  7585. cropGraph = new Graph(croppingDiv);
  7586. cropGraph.autoExtend = false;
  7587. cropGraph.autoScroll = false;
  7588. cropGraph.setGridEnabled(false);
  7589. cropGraph.setEnabled(true);
  7590. cropGraph.setPanning(false);
  7591. cropGraph.setConnectable(false);
  7592. cropGraph.getRubberband().setEnabled(false);
  7593. cropGraph.graphHandler.allowLivePreview = false;
  7594. var origCreateVertexHandler = cropGraph.createVertexHandler;
  7595. cropGraph.createVertexHandler = function()
  7596. {
  7597. var handler = origCreateVertexHandler.apply(this, arguments);
  7598. handler.livePreview = false;
  7599. return handler;
  7600. }
  7601. if (clipPath != null)
  7602. {
  7603. //Find position and size of cropCell
  7604. try
  7605. {
  7606. if (clipPath.substring(0, 5) == 'inset')
  7607. {
  7608. var geo = cropCell.geometry;
  7609. var imgW = img.width;
  7610. var imgH = img.height;
  7611. var imgX = (IMAGE_SIZE - imgW) / 2;
  7612. var imgY = (IMAGE_SIZE - imgH) / 2;
  7613. var tokens = clipPath.match(/\(([^)]+)\)/)[1].split(/[ ,]+/);
  7614. var top = parseFloat(tokens[0]);
  7615. var right = parseFloat(tokens[1]);
  7616. var bottom = parseFloat(tokens[2]);
  7617. var left = parseFloat(tokens[3]);
  7618. if (isFinite(top) && isFinite(right) && isFinite(bottom) && isFinite(left))
  7619. {
  7620. geo.x = left / 100 * imgW + imgX;
  7621. geo.y = top / 100 * imgH + imgY;
  7622. geo.width = (100 - right) / 100 * imgW + imgX - geo.x;
  7623. geo.height = (100 - bottom) / 100 * imgH + imgY - geo.y;
  7624. if (tokens[4] == 'round')
  7625. {
  7626. if (tokens[5] == '50%')
  7627. {
  7628. ellipseInput.setAttribute('checked', 'checked');
  7629. }
  7630. else
  7631. {
  7632. arcSizeVal = parseInt(tokens[5]);
  7633. arcSize.value = arcSizeVal;
  7634. roundedInput.setAttribute('checked', 'checked');
  7635. arcSizeDiv.style.visibility = 'visible';
  7636. }
  7637. }
  7638. else
  7639. {
  7640. rectInput.setAttribute('checked', 'checked');
  7641. }
  7642. }
  7643. else //Invalid clipPath
  7644. {
  7645. clipPath = null;
  7646. }
  7647. }
  7648. else //The dialog supports inset only
  7649. {
  7650. clipPath = null;
  7651. }
  7652. }
  7653. catch (e){} //Ignore
  7654. }
  7655. cropCell.style = getCropCellStyle(clipPath);
  7656. cropCell.vertex = true;
  7657. cropGraph.addCell(cropCell, null, null, null, null);
  7658. cropGraph.selectAll();
  7659. function updateCropCell()
  7660. {
  7661. cropGraph.model.setStyle(cropCell, getCropCellStyle());
  7662. };
  7663. cropGraph.addListener(mxEvent.CELLS_MOVED, updateCropCell);
  7664. cropGraph.addListener(mxEvent.CELLS_RESIZED, updateCropCell);
  7665. var origMouseUp = cropGraph.graphHandler.mouseUp;
  7666. var origMouseDown = cropGraph.graphHandler.mouseDown;
  7667. cropGraph.graphHandler.mouseUp = function()
  7668. {
  7669. origMouseUp.apply(this, arguments);
  7670. croppingDiv.style.backgroundColor = '#fff9';
  7671. };
  7672. cropGraph.graphHandler.mouseDown = function()
  7673. {
  7674. origMouseDown.apply(this, arguments);
  7675. croppingDiv.style.backgroundColor = '';
  7676. };
  7677. cropGraph.dblClick = function(){} //Disable text adding
  7678. var origChangeSelection = cropGraph.getSelectionModel().changeSelection;
  7679. //Prevent deselection
  7680. cropGraph.getSelectionModel().changeSelection = function()
  7681. {
  7682. origChangeSelection.call(this, [cropCell], [cropCell]);
  7683. };
  7684. };
  7685. var rectInput = document.createElement('input');
  7686. rectInput.setAttribute('type', 'radio');
  7687. rectInput.setAttribute('id', 'croppingRect');
  7688. rectInput.setAttribute('name', 'croppingShape');
  7689. rectInput.setAttribute('checked', 'checked');
  7690. rectInput.style.margin = '5px';
  7691. div.appendChild(rectInput);
  7692. var rectLbl = document.createElement('label');
  7693. rectLbl.setAttribute('for', 'croppingRect');
  7694. mxUtils.write(rectLbl, mxResources.get('rectangle'));
  7695. div.appendChild(rectLbl);
  7696. var roundedInput = document.createElement('input');
  7697. roundedInput.setAttribute('type', 'radio');
  7698. roundedInput.setAttribute('id', 'croppingRounded');
  7699. roundedInput.setAttribute('name', 'croppingShape');
  7700. roundedInput.style.margin = '5px';
  7701. div.appendChild(roundedInput);
  7702. var roundedLbl = document.createElement('label');
  7703. roundedLbl.setAttribute('for', 'croppingRounded');
  7704. mxUtils.write(roundedLbl, mxResources.get('rounded'));
  7705. div.appendChild(roundedLbl);
  7706. var ellipseInput = document.createElement('input');
  7707. ellipseInput.setAttribute('type', 'radio');
  7708. ellipseInput.setAttribute('id', 'croppingEllipse');
  7709. ellipseInput.setAttribute('name', 'croppingShape');
  7710. ellipseInput.style.margin = '5px';
  7711. div.appendChild(ellipseInput);
  7712. var ellipseLbl = document.createElement('label');
  7713. ellipseLbl.setAttribute('for', 'croppingEllipse');
  7714. mxUtils.write(ellipseLbl, mxResources.get('ellipse'));
  7715. div.appendChild(ellipseLbl);
  7716. function calcClipPath()
  7717. {
  7718. var isRounded = roundedInput.checked;
  7719. var isEllipse = ellipseInput.checked;
  7720. var geo = cropCell.geometry;
  7721. var imgW = img.width;
  7722. var imgH = img.height;
  7723. var imgX = (IMAGE_SIZE - imgW) / 2;
  7724. var imgY = (IMAGE_SIZE - imgH) / 2;
  7725. var left, right, top, bottom;
  7726. //prevent coords outside the image
  7727. if (geo.x < imgX)
  7728. {
  7729. geo.width -= (imgX - geo.x);
  7730. geo.x = imgX;
  7731. }
  7732. else if (geo.x + geo.width > imgX + imgW)
  7733. {
  7734. geo.width = imgX + imgW - geo.x;
  7735. geo.x = Math.min(geo.x, imgX + imgW);
  7736. }
  7737. if (geo.y < imgY)
  7738. {
  7739. geo.height -= (imgY - geo.y);
  7740. geo.y = imgY;
  7741. }
  7742. else if (geo.y + geo.height > imgY + imgH)
  7743. {
  7744. geo.height = imgY + imgH - geo.y;
  7745. geo.y = Math.min(geo.y, imgY + imgH);
  7746. }
  7747. var left = (geo.x - imgX) / imgW * 100;
  7748. var right = 100 - (geo.x + geo.width - imgX) / imgW * 100;
  7749. var top = (geo.y - imgY) / imgH * 100;
  7750. var bottom = 100 - (geo.y + geo.height - imgY) / imgH * 100;
  7751. //Use inset for circle also since it uses percentages from 4 sides and this scales no matter the shape of the image
  7752. //Using circle which is based on a single point to position (center) moves when the image is scaled and/or aspect is changed
  7753. return 'inset(' + mxUtils.format(top) + '% ' + mxUtils.format(right) + '% ' + mxUtils.format(bottom) + '% ' + mxUtils.format(left) + '%' +
  7754. (isRounded? ' round ' + arcSizeVal + '%' : (isEllipse? ' round 50%' : '')) + ')';
  7755. }
  7756. function typeChanged(noGeoReset)
  7757. {
  7758. if (cropGraph == null) return; //Image is not loaded yet. Graph had to wait for the image to load to be on-top
  7759. if (noGeoReset !== true)
  7760. {
  7761. cropGraph.model.setGeometry(cropCell, initGeo.clone());
  7762. arcSizeVal = 5;
  7763. arcSize.value = arcSizeVal;
  7764. }
  7765. cropGraph.model.setStyle(cropCell, getCropCellStyle());
  7766. cropGraph.selectAll();
  7767. arcSizeDiv.style.visibility = roundedInput.checked ? 'visible' : 'hidden';
  7768. }
  7769. function getCropCellStyle(clipPath)
  7770. {
  7771. return commonStyle + (clipPath? clipPath : calcClipPath());
  7772. }
  7773. mxEvent.addListener(rectInput, 'change', typeChanged);
  7774. mxEvent.addListener(roundedInput, 'change', typeChanged);
  7775. mxEvent.addListener(ellipseInput, 'change', typeChanged);
  7776. //Arc size slider
  7777. var arcSizeDiv = document.createElement('div');
  7778. arcSizeDiv.style.textAlign = 'center';
  7779. arcSizeDiv.style.visibility = 'hidden';
  7780. var arcSize = document.createElement('input');
  7781. arcSize.setAttribute('type', 'range');
  7782. arcSize.setAttribute('min', '1');
  7783. arcSize.setAttribute('max', '49');
  7784. arcSize.setAttribute('value', arcSizeVal);
  7785. arcSize.setAttribute('title', mxResources.get('arcSize'));
  7786. arcSizeDiv.appendChild(arcSize);
  7787. div.appendChild(arcSizeDiv);
  7788. mxEvent.addListener(arcSize, 'change', function()
  7789. {
  7790. arcSizeVal = this.value;
  7791. typeChanged(true);
  7792. });
  7793. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  7794. {
  7795. editorUi.hideDialog();
  7796. });
  7797. cancelBtn.className = 'geBtn';
  7798. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  7799. {
  7800. fn(calcClipPath(), cropCell.geometry.width, cropCell.geometry.height);
  7801. editorUi.hideDialog();
  7802. });
  7803. applyBtn.className = 'geBtn gePrimaryBtn';
  7804. var resetBtn = mxUtils.button(mxResources.get('reset'), function()
  7805. {
  7806. fn(null, img.width, img.height);
  7807. editorUi.hideDialog();
  7808. });
  7809. resetBtn.className = 'geBtn';
  7810. var buttons = document.createElement('div');
  7811. buttons.style.marginTop = '10px';
  7812. buttons.style.textAlign = 'right';
  7813. if (editorUi.editor.cancelFirst)
  7814. {
  7815. buttons.appendChild(cancelBtn);
  7816. buttons.appendChild(resetBtn);
  7817. buttons.appendChild(applyBtn);
  7818. }
  7819. else
  7820. {
  7821. buttons.appendChild(resetBtn);
  7822. buttons.appendChild(applyBtn);
  7823. buttons.appendChild(cancelBtn);
  7824. }
  7825. div.appendChild(buttons);
  7826. this.container = div;
  7827. };
  7828. var EditGeometryDialog = function(editorUi, vertices)
  7829. {
  7830. var graph = editorUi.editor.graph;
  7831. var geo = (vertices.length == 1) ? graph.getCellGeometry(vertices[0]) : null;
  7832. var div = document.createElement('div');
  7833. var table = document.createElement('table');
  7834. var tbody = document.createElement('tbody');
  7835. var row = document.createElement('tr');
  7836. var left = document.createElement('td');
  7837. var right = document.createElement('td');
  7838. table.style.paddingLeft = '6px';
  7839. mxUtils.write(left, mxResources.get('relative') + ':');
  7840. var relInput = document.createElement('input');
  7841. relInput.setAttribute('type', 'checkbox');
  7842. if (geo != null && geo.relative)
  7843. {
  7844. relInput.setAttribute('checked', 'checked');
  7845. relInput.defaultChecked = true;
  7846. }
  7847. this.init = function()
  7848. {
  7849. relInput.focus();
  7850. };
  7851. right.appendChild(relInput);
  7852. row.appendChild(left);
  7853. row.appendChild(right);
  7854. tbody.appendChild(row);
  7855. row = document.createElement('tr');
  7856. left = document.createElement('td');
  7857. right = document.createElement('td');
  7858. mxUtils.write(left, mxResources.get('left') + ':');
  7859. var xInput = document.createElement('input');
  7860. xInput.setAttribute('type', 'text');
  7861. xInput.style.width = '100px';
  7862. xInput.value = (geo != null) ? geo.x : '';
  7863. right.appendChild(xInput);
  7864. row.appendChild(left);
  7865. row.appendChild(right);
  7866. tbody.appendChild(row);
  7867. row = document.createElement('tr');
  7868. left = document.createElement('td');
  7869. right = document.createElement('td');
  7870. mxUtils.write(left, mxResources.get('top') + ':');
  7871. var yInput = document.createElement('input');
  7872. yInput.setAttribute('type', 'text');
  7873. yInput.style.width = '100px';
  7874. yInput.value = (geo != null) ? geo.y : '';
  7875. right.appendChild(yInput);
  7876. row.appendChild(left);
  7877. row.appendChild(right);
  7878. tbody.appendChild(row);
  7879. row = document.createElement('tr');
  7880. left = document.createElement('td');
  7881. right = document.createElement('td');
  7882. mxUtils.write(left, mxResources.get('dx') + ':');
  7883. var dxInput = document.createElement('input');
  7884. dxInput.setAttribute('type', 'text');
  7885. dxInput.style.width = '100px';
  7886. dxInput.value = (geo != null && geo.offset != null) ? geo.offset.x : '';
  7887. right.appendChild(dxInput);
  7888. row.appendChild(left);
  7889. row.appendChild(right);
  7890. tbody.appendChild(row);
  7891. row = document.createElement('tr');
  7892. left = document.createElement('td');
  7893. right = document.createElement('td');
  7894. mxUtils.write(left, mxResources.get('dy') + ':');
  7895. var dyInput = document.createElement('input');
  7896. dyInput.setAttribute('type', 'text');
  7897. dyInput.style.width = '100px';
  7898. dyInput.value = (geo != null && geo.offset != null) ? geo.offset.y : '';
  7899. right.appendChild(dyInput);
  7900. row.appendChild(left);
  7901. row.appendChild(right);
  7902. tbody.appendChild(row);
  7903. row = document.createElement('tr');
  7904. left = document.createElement('td');
  7905. right = document.createElement('td');
  7906. mxUtils.write(left, mxResources.get('width') + ':');
  7907. var wInput = document.createElement('input');
  7908. wInput.setAttribute('type', 'text');
  7909. wInput.style.width = '100px';
  7910. wInput.value = (geo != null) ? geo.width : '';
  7911. right.appendChild(wInput);
  7912. row.appendChild(left);
  7913. row.appendChild(right);
  7914. tbody.appendChild(row);
  7915. row = document.createElement('tr');
  7916. left = document.createElement('td');
  7917. right = document.createElement('td');
  7918. mxUtils.write(left, mxResources.get('height') + ':');
  7919. var hInput = document.createElement('input');
  7920. hInput.setAttribute('type', 'text');
  7921. hInput.style.width = '100px';
  7922. hInput.value = (geo != null) ? geo.height : '';
  7923. right.appendChild(hInput);
  7924. row.appendChild(left);
  7925. row.appendChild(right);
  7926. tbody.appendChild(row);
  7927. row = document.createElement('tr');
  7928. left = document.createElement('td');
  7929. right = document.createElement('td');
  7930. mxUtils.write(left, mxResources.get('rotation') + ':');
  7931. var rotInput = document.createElement('input');
  7932. rotInput.setAttribute('type', 'text');
  7933. rotInput.style.width = '100px';
  7934. rotInput.value = (vertices.length == 1) ? mxUtils.getValue(graph.getCellStyle(vertices[0]),
  7935. mxConstants.STYLE_ROTATION, 0) : '';
  7936. right.appendChild(rotInput);
  7937. row.appendChild(left);
  7938. row.appendChild(right);
  7939. tbody.appendChild(row);
  7940. table.appendChild(tbody);
  7941. div.appendChild(table);
  7942. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  7943. {
  7944. editorUi.hideDialog();
  7945. });
  7946. cancelBtn.className = 'geBtn';
  7947. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  7948. {
  7949. editorUi.hideDialog();
  7950. graph.getModel().beginUpdate();
  7951. try
  7952. {
  7953. for (var i = 0; i < vertices.length; i++)
  7954. {
  7955. var g = graph.getCellGeometry(vertices[i]);
  7956. if (g != null)
  7957. {
  7958. g = g.clone();
  7959. if (graph.isCellMovable(vertices[i]))
  7960. {
  7961. g.relative = relInput.checked;
  7962. if (mxUtils.trim(xInput.value).length > 0)
  7963. {
  7964. g.x = Number(xInput.value);
  7965. }
  7966. if (mxUtils.trim(yInput.value).length > 0)
  7967. {
  7968. g.y = Number(yInput.value);
  7969. }
  7970. if (mxUtils.trim(dxInput.value).length > 0)
  7971. {
  7972. if (g.offset == null)
  7973. {
  7974. g.offset = new mxPoint();
  7975. }
  7976. g.offset.x = Number(dxInput.value);
  7977. }
  7978. if (mxUtils.trim(dyInput.value).length > 0)
  7979. {
  7980. if (g.offset == null)
  7981. {
  7982. g.offset = new mxPoint();
  7983. }
  7984. g.offset.y = Number(dyInput.value);
  7985. }
  7986. }
  7987. if (graph.isCellResizable(vertices[i]))
  7988. {
  7989. if (mxUtils.trim(wInput.value).length > 0)
  7990. {
  7991. g.width = Number(wInput.value);
  7992. }
  7993. if (mxUtils.trim(hInput.value).length > 0)
  7994. {
  7995. g.height = Number(hInput.value);
  7996. }
  7997. }
  7998. graph.getModel().setGeometry(vertices[i], g);
  7999. }
  8000. if (mxUtils.trim(rotInput.value).length > 0)
  8001. {
  8002. graph.setCellStyles(mxConstants.STYLE_ROTATION, Number(rotInput.value), [vertices[i]]);
  8003. }
  8004. }
  8005. }
  8006. finally
  8007. {
  8008. graph.getModel().endUpdate();
  8009. }
  8010. });
  8011. applyBtn.className = 'geBtn gePrimaryBtn';
  8012. mxEvent.addListener(div, 'keypress', function(e)
  8013. {
  8014. if (e.keyCode == 13)
  8015. {
  8016. applyBtn.click();
  8017. }
  8018. });
  8019. var buttons = document.createElement('div');
  8020. buttons.style.marginTop = '20px';
  8021. buttons.style.textAlign = 'right';
  8022. if (editorUi.editor.cancelFirst)
  8023. {
  8024. buttons.appendChild(cancelBtn);
  8025. buttons.appendChild(applyBtn);
  8026. }
  8027. else
  8028. {
  8029. buttons.appendChild(applyBtn);
  8030. buttons.appendChild(cancelBtn);
  8031. }
  8032. div.appendChild(buttons);
  8033. this.container = div;
  8034. };
  8035. /**
  8036. * Constructs a new dialog for creating files from templates.
  8037. */
  8038. var LibraryDialog = function(editorUi, name, library, initialImages, file, mode)
  8039. {
  8040. var images = [];
  8041. var graph = editorUi.editor.graph;
  8042. var outer = document.createElement('div');
  8043. outer.style.height = '100%';
  8044. var header = document.createElement('div');
  8045. header.style.whiteSpace = 'nowrap';
  8046. header.style.height = '40px';
  8047. outer.appendChild(header);
  8048. mxUtils.write(header, mxResources.get('filename') + ':');
  8049. var nameValue = name;
  8050. if (nameValue == null)
  8051. {
  8052. nameValue = editorUi.defaultLibraryName + '.xml';
  8053. }
  8054. var nameInput = document.createElement('input');
  8055. nameInput.setAttribute('value', nameValue);
  8056. nameInput.style.marginRight = '20px';
  8057. nameInput.style.marginLeft = '10px';
  8058. nameInput.style.width = '500px';
  8059. if (file != null && !file.isRenamable())
  8060. {
  8061. nameInput.setAttribute('disabled', 'true');
  8062. }
  8063. this.init = function()
  8064. {
  8065. if (file == null || file.isRenamable())
  8066. {
  8067. nameInput.focus();
  8068. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  8069. {
  8070. nameInput.select();
  8071. }
  8072. else
  8073. {
  8074. document.execCommand('selectAll', false, null);
  8075. }
  8076. }
  8077. };
  8078. header.appendChild(nameInput);
  8079. if (Editor.enableUncompressedLibraries)
  8080. {
  8081. nameInput.style.width = '420px';
  8082. var compressedInput = document.createElement('input');
  8083. compressedInput.setAttribute('type', 'checkbox');
  8084. compressedInput.style.marginRight = '10px';
  8085. header.appendChild(compressedInput);
  8086. mxUtils.write(header, mxResources.get('compressed'));
  8087. }
  8088. var div = document.createElement('div');
  8089. div.style.borderWidth = '1px 0px 1px 0px';
  8090. div.style.borderColor = '#d3d3d3';
  8091. div.style.borderStyle = 'solid';
  8092. div.style.marginTop = '6px';
  8093. div.style.overflow = 'auto';
  8094. div.style.height = '340px';
  8095. div.style.backgroundPosition = 'center center';
  8096. div.style.backgroundRepeat = 'no-repeat';
  8097. if (images.length == 0 && Graph.fileSupport)
  8098. {
  8099. div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')';
  8100. }
  8101. var bg = document.createElement('div');
  8102. bg.style.position = 'absolute';
  8103. bg.style.width = '640px';
  8104. bg.style.top = '260px';
  8105. bg.style.textAlign = 'center';
  8106. bg.style.fontSize = '22px';
  8107. bg.style.color = '#a0c3ff';
  8108. mxUtils.write(bg, mxResources.get('dragImagesHere'));
  8109. outer.appendChild(bg);
  8110. var entries = {};
  8111. var ew = 100;
  8112. var eh = 100;
  8113. var dragSourceIndex = null;
  8114. var dropTargetIndex = null;
  8115. function getIndexForEvent(evt)
  8116. {
  8117. var dropTarget = document.elementFromPoint(evt.clientX, evt.clientY);
  8118. while (dropTarget != null && dropTarget.parentNode != div)
  8119. {
  8120. dropTarget = dropTarget.parentNode;
  8121. }
  8122. var result = null;
  8123. if (dropTarget != null)
  8124. {
  8125. var tmp = div.firstChild;
  8126. result = 0;
  8127. while (tmp != null && tmp != dropTarget)
  8128. {
  8129. tmp = tmp.nextSibling;
  8130. result++;
  8131. }
  8132. }
  8133. return result;
  8134. };
  8135. var stopEditing = null;
  8136. var stopWrapper = function(evt)
  8137. {
  8138. var source = mxEvent.getSource(evt);
  8139. if (source.getAttribute('contentEditable') != 'true' && stopEditing != null)
  8140. {
  8141. stopEditing();
  8142. stopEditing = null;
  8143. mxEvent.consume(evt);
  8144. }
  8145. };
  8146. mxEvent.addListener(div, 'mousedown', stopWrapper);
  8147. mxEvent.addListener(div, 'pointerdown', stopWrapper);
  8148. mxEvent.addListener(div, 'touchstart', stopWrapper);
  8149. // For converting image URLs
  8150. var converter = new mxUrlConverter();
  8151. var errorShowed = false;
  8152. function addButton(data, mimeType, x, y, w, h, img, aspect, title)
  8153. {
  8154. // Ignores duplicates
  8155. try
  8156. {
  8157. editorUi.spinner.stop();
  8158. if (mimeType == null || mimeType.substring(0, 6) == 'image/')
  8159. {
  8160. if ((data == null && img != null) || entries[data] == null)
  8161. {
  8162. div.style.backgroundImage = '';
  8163. bg.style.display = 'none';
  8164. var iw = w;
  8165. var ih = h;
  8166. if (w > editorUi.maxImageSize || h > editorUi.maxImageSize)
  8167. {
  8168. var s = Math.min(1, Math.min(editorUi.maxImageSize / Math.max(1, w)),
  8169. editorUi.maxImageSize / Math.max(1, h));
  8170. w *= s;
  8171. h *= s;
  8172. }
  8173. if (iw > ih)
  8174. {
  8175. ih = Math.round(ih * ew / iw);
  8176. iw = ew;
  8177. }
  8178. else
  8179. {
  8180. iw = Math.round(iw * eh / ih);
  8181. ih = eh;
  8182. }
  8183. var wrapper = document.createElement('div');
  8184. wrapper.setAttribute('draggable', 'true');
  8185. wrapper.style.display = 'inline-block';
  8186. wrapper.style.position = 'relative';
  8187. wrapper.style.padding = '0 12px';
  8188. wrapper.style.cursor = 'move';
  8189. mxUtils.setPrefixedStyle(wrapper.style, 'transition', 'transform .1s ease-in-out');
  8190. if (data != null)
  8191. {
  8192. var elt = document.createElement('img');
  8193. elt.setAttribute('src', converter.convert(data));
  8194. elt.style.width = iw + 'px';
  8195. elt.style.height = ih + 'px';
  8196. elt.style.margin = '10px';
  8197. elt.style.paddingBottom = Math.floor((eh - ih) / 2) + 'px';
  8198. elt.style.paddingLeft = Math.floor((ew - iw) / 2) + 'px';
  8199. wrapper.appendChild(elt);
  8200. }
  8201. else if (img != null)
  8202. {
  8203. var cells = editorUi.stringToCells((img.xml.charAt(0) == '<') ?
  8204. img.xml : Graph.decompress(img.xml));
  8205. if (cells.length > 0)
  8206. {
  8207. editorUi.sidebar.createThumb(cells, ew, eh, wrapper, null,
  8208. true, false, null, null, (Editor.isDarkMode()) ?
  8209. '#2a252f' : '#ffffff');
  8210. // Needs inline block on SVG for delete icon to appear on same line
  8211. wrapper.firstChild.style.display = 'inline-block';
  8212. wrapper.firstChild.style.cursor = '';
  8213. }
  8214. }
  8215. var rem = document.createElement('img');
  8216. rem.setAttribute('src', Editor.closeBlackImage);
  8217. rem.setAttribute('border', '0');
  8218. rem.setAttribute('title', mxResources.get('delete'));
  8219. rem.setAttribute('align', 'top');
  8220. rem.style.paddingTop = '4px';
  8221. rem.style.position = 'absolute';
  8222. rem.style.marginLeft = '-12px';
  8223. rem.style.zIndex = '1';
  8224. rem.style.cursor = 'pointer';
  8225. // Blocks dragging of remove icon
  8226. mxEvent.addListener(rem, 'dragstart', function(evt)
  8227. {
  8228. mxEvent.consume(evt);
  8229. });
  8230. (function(wrapperDiv, dataParam, imgParam)
  8231. {
  8232. mxEvent.addListener(rem, 'click', function(evt)
  8233. {
  8234. entries[dataParam] = null;
  8235. for (var i = 0; i < images.length; i++)
  8236. {
  8237. if ((images[i].data != null && images[i].data == dataParam) ||
  8238. (images[i].xml != null && imgParam != null &&
  8239. images[i].xml == imgParam.xml))
  8240. {
  8241. images.splice(i, 1);
  8242. break;
  8243. }
  8244. }
  8245. wrapper.parentNode.removeChild(wrapperDiv);
  8246. if (images.length == 0)
  8247. {
  8248. div.style.backgroundImage = 'url(\'' + IMAGE_PATH + '/droptarget.png\')';
  8249. bg.style.display = '';
  8250. }
  8251. mxEvent.consume(evt);
  8252. });
  8253. // Workaround for accidental select all
  8254. mxEvent.addListener(rem, 'dblclick', function(evt)
  8255. {
  8256. mxEvent.consume(evt);
  8257. });
  8258. })(wrapper, data, img);
  8259. wrapper.appendChild(rem);
  8260. wrapper.style.marginBottom = '30px';
  8261. var label = document.createElement('div');
  8262. label.style.position = 'absolute';
  8263. label.style.boxSizing = 'border-box';
  8264. label.style.bottom = '-18px';
  8265. label.style.left = '10px';
  8266. label.style.right = '10px';
  8267. label.style.backgroundColor = Editor.isDarkMode() ?
  8268. 'transparent' : '#ffffff';
  8269. label.style.overflow = 'hidden';
  8270. label.style.textAlign = 'center';
  8271. label.setAttribute('title', mxResources.get('rename'));
  8272. var entry = null;
  8273. if (data != null)
  8274. {
  8275. entry = {data: data, w: w, h: h, title: title};
  8276. if (aspect != null)
  8277. {
  8278. entry.aspect = aspect;
  8279. }
  8280. entries[data] = elt;
  8281. images.push(entry);
  8282. }
  8283. else if (img != null)
  8284. {
  8285. img.aspect = 'fixed';
  8286. images.push(img);
  8287. entry = img;
  8288. }
  8289. function updateLabel()
  8290. {
  8291. label.innerText = '';
  8292. label.style.cursor = 'pointer';
  8293. label.style.whiteSpace = 'nowrap';
  8294. label.style.textOverflow = 'ellipsis';
  8295. mxUtils.write(label, (entry.title != null && entry.title.length > 0) ?
  8296. entry.title : mxResources.get('untitled'));
  8297. if (entry.title == null || entry.title.length == 0)
  8298. {
  8299. label.style.color = '#d0d0d0';
  8300. }
  8301. else
  8302. {
  8303. label.style.color = '';
  8304. }
  8305. };
  8306. mxEvent.addListener(label, 'keydown', function(evt)
  8307. {
  8308. if (evt.keyCode == 13 && stopEditing != null)
  8309. {
  8310. stopEditing();
  8311. stopEditing = null;
  8312. mxEvent.consume(evt);
  8313. }
  8314. });
  8315. updateLabel();
  8316. wrapper.appendChild(label);
  8317. // Blocks dragging of label
  8318. mxEvent.addListener(label, 'mousedown', function(evt)
  8319. {
  8320. if (label.getAttribute('contentEditable') != 'true')
  8321. {
  8322. mxEvent.consume(evt);
  8323. }
  8324. });
  8325. var startEditing = function(evt)
  8326. {
  8327. // Workaround for various issues in IE
  8328. if (!mxClient.IS_IOS && !mxClient.IS_FF &&
  8329. (document.documentMode == null || document.documentMode > 9))
  8330. {
  8331. if (label.getAttribute('contentEditable') != 'true')
  8332. {
  8333. if (stopEditing != null)
  8334. {
  8335. stopEditing();
  8336. stopEditing = null;
  8337. }
  8338. if (entry.title == null || entry.title.length == 0)
  8339. {
  8340. label.innerText = '';
  8341. }
  8342. label.style.textOverflow = '';
  8343. label.style.whiteSpace = '';
  8344. label.style.cursor = 'text';
  8345. label.style.color = '';
  8346. label.setAttribute('contentEditable', 'true');
  8347. mxUtils.setPrefixedStyle(label.style, 'user-select', 'text');
  8348. label.focus();
  8349. document.execCommand('selectAll', false, null);
  8350. stopEditing = function()
  8351. {
  8352. label.removeAttribute('contentEditable');
  8353. label.style.cursor = 'pointer';
  8354. entry.title = label.innerHTML;
  8355. updateLabel();
  8356. }
  8357. mxEvent.consume(evt);
  8358. }
  8359. }
  8360. else
  8361. {
  8362. var dlg = new FilenameDialog(editorUi, entry.title || '', mxResources.get('ok'), function(newTitle)
  8363. {
  8364. if (newTitle != null)
  8365. {
  8366. entry.title = newTitle;
  8367. updateLabel();
  8368. }
  8369. }, mxResources.get('enterValue'));
  8370. editorUi.showDialog(dlg.container, 300, 80, true, true);
  8371. dlg.init();
  8372. mxEvent.consume(evt);
  8373. }
  8374. };
  8375. mxEvent.addListener(label, 'click', startEditing);
  8376. mxEvent.addListener(wrapper, 'dblclick', startEditing);
  8377. div.appendChild(wrapper);
  8378. mxEvent.addListener(wrapper, 'dragstart', function(evt)
  8379. {
  8380. if (data == null && img != null)
  8381. {
  8382. rem.style.visibility = 'hidden';
  8383. label.style.visibility = 'hidden';
  8384. }
  8385. // Workaround for no DnD on DIV in FF
  8386. if (mxClient.IS_FF && img.xml != null)
  8387. {
  8388. evt.dataTransfer.setData('Text', img.xml);
  8389. }
  8390. dragSourceIndex = getIndexForEvent(evt);
  8391. // Workaround for missing drag preview in Google Chrome
  8392. if (mxClient.IS_GC)
  8393. {
  8394. wrapper.style.opacity = '0.9';
  8395. }
  8396. window.setTimeout(function()
  8397. {
  8398. mxUtils.setPrefixedStyle(wrapper.style, 'transform', 'scale(0.5,0.5)');
  8399. mxUtils.setOpacity(wrapper, 30);
  8400. rem.style.visibility = '';
  8401. label.style.visibility = '';
  8402. }, 0);
  8403. });
  8404. mxEvent.addListener(wrapper, 'dragend', function(evt)
  8405. {
  8406. if (rem.style.visibility == 'hidden')
  8407. {
  8408. rem.style.visibility = '';
  8409. label.style.visibility = '';
  8410. }
  8411. dragSourceIndex = null;
  8412. mxUtils.setOpacity(wrapper, 100);
  8413. mxUtils.setPrefixedStyle(wrapper.style, 'transform', null);
  8414. });
  8415. }
  8416. else if (!errorShowed)
  8417. {
  8418. errorShowed = true;
  8419. editorUi.handleError({message: mxResources.get('fileExists')})
  8420. }
  8421. }
  8422. else
  8423. {
  8424. var done = false;
  8425. try
  8426. {
  8427. var doc = mxUtils.parseXml(data);
  8428. if (doc.documentElement.nodeName == 'mxlibrary')
  8429. {
  8430. var temp = JSON.parse(mxUtils.getTextContent(doc.documentElement));
  8431. if (temp != null && temp.length > 0)
  8432. {
  8433. for (var i = 0; i < temp.length; i++)
  8434. {
  8435. if (temp[i].xml != null)
  8436. {
  8437. addButton(null, null, 0, 0, 0, 0, temp[i]);
  8438. }
  8439. else
  8440. {
  8441. addButton(temp[i].data, null, 0, 0, temp[i].w, temp[i].h, null, 'fixed', temp[i].title);
  8442. }
  8443. }
  8444. }
  8445. done = true;
  8446. }
  8447. else if (doc.documentElement.nodeName == 'mxfile')
  8448. {
  8449. var pages = doc.documentElement.getElementsByTagName('diagram');
  8450. for (var i = 0; i < pages.length; i++)
  8451. {
  8452. var temp = mxUtils.getTextContent(pages[i]);
  8453. var cells = editorUi.stringToCells(Graph.decompress(temp));
  8454. var size = editorUi.editor.graph.getBoundingBoxFromGeometry(cells);
  8455. addButton(null, null, 0, 0, 0, 0, {xml: temp, w: size.width, h: size.height});
  8456. }
  8457. done = true;
  8458. }
  8459. }
  8460. catch (e)
  8461. {
  8462. if (window.console != null)
  8463. {
  8464. console.log('Error in library dialog: ' + e);
  8465. }
  8466. }
  8467. if (!done)
  8468. {
  8469. editorUi.spinner.stop();
  8470. editorUi.handleError({message: mxResources.get('errorLoadingFile')})
  8471. }
  8472. }
  8473. }
  8474. catch (e)
  8475. {
  8476. if (window.console != null)
  8477. {
  8478. console.log('Error in library dialog: ' + e);
  8479. }
  8480. }
  8481. return null;
  8482. };
  8483. if (initialImages != null)
  8484. {
  8485. for (var i = 0; i < initialImages.length; i++)
  8486. {
  8487. var img = initialImages[i];
  8488. addButton(img.data, null, 0, 0, img.w, img.h, img, img.aspect, img.title);
  8489. }
  8490. }
  8491. // Setup the dnd listeners
  8492. mxEvent.addListener(div, 'dragleave', function(evt)
  8493. {
  8494. bg.style.cursor = '';
  8495. var source = mxEvent.getSource(evt);
  8496. while (source != null)
  8497. {
  8498. if (source == div || source == bg)
  8499. {
  8500. evt.stopPropagation();
  8501. evt.preventDefault();
  8502. break;
  8503. }
  8504. source = source.parentNode;
  8505. }
  8506. });
  8507. function dragOver(evt)
  8508. {
  8509. evt.dataTransfer.dropEffect = (dragSourceIndex != null) ? 'move' : 'copy';
  8510. evt.stopPropagation();
  8511. evt.preventDefault();
  8512. };
  8513. var createImportHandler = function(evt)
  8514. {
  8515. return function(data, mimeType, x, y, w, h, img, doneFn, file)
  8516. {
  8517. if (file != null && (/(\.v(dx|sdx?))($|\?)/i.test(file.name) || /(\.vs(x|sx?))($|\?)/i.test(file.name)))
  8518. {
  8519. editorUi.importVisio(file, mxUtils.bind(this, function(xml)
  8520. {
  8521. addButton(xml, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ?
  8522. null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' '));
  8523. }));
  8524. }
  8525. else if (file != null && new XMLHttpRequest().upload && editorUi.isRemoteFileFormat(data, file.name))
  8526. {
  8527. if (editorUi.isExternalDataComms())
  8528. {
  8529. editorUi.parseFile(file, mxUtils.bind(this, function(xhr)
  8530. {
  8531. if (xhr.readyState == 4)
  8532. {
  8533. editorUi.spinner.stop();
  8534. if (xhr.status >= 200 && xhr.status <= 299)
  8535. {
  8536. var xml = xhr.responseText;
  8537. addButton(xml, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ?
  8538. null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' '));
  8539. div.scrollTop = div.scrollHeight;
  8540. }
  8541. }
  8542. }));
  8543. }
  8544. else
  8545. {
  8546. editorUi.spinner.stop();
  8547. editorUi.showError(mxResources.get('error'), mxResources.get('notInOffline'));
  8548. }
  8549. }
  8550. else
  8551. {
  8552. addButton(data, mimeType, x, y, w, h, img, 'fixed', (mxEvent.isAltDown(evt)) ?
  8553. null : img.substring(0, img.lastIndexOf('.')).replace(/_/g, ' '));
  8554. div.scrollTop = div.scrollHeight;
  8555. }
  8556. };
  8557. };
  8558. function dropHandler(evt)
  8559. {
  8560. evt.stopPropagation();
  8561. evt.preventDefault();
  8562. errorShowed = false;
  8563. dropTargetIndex = getIndexForEvent(evt);
  8564. if (dragSourceIndex != null)
  8565. {
  8566. if (dropTargetIndex != null && dropTargetIndex < div.children.length)
  8567. {
  8568. images.splice((dropTargetIndex > dragSourceIndex) ? dropTargetIndex - 1 : dropTargetIndex,
  8569. 0, images.splice(dragSourceIndex, 1)[0]);
  8570. div.insertBefore(div.children[dragSourceIndex], div.children[dropTargetIndex]);
  8571. }
  8572. else
  8573. {
  8574. images.push(images.splice(dragSourceIndex, 1)[0]);
  8575. div.appendChild(div.children[dragSourceIndex]);
  8576. }
  8577. }
  8578. else if (evt.dataTransfer.files.length > 0)
  8579. {
  8580. editorUi.importFiles(evt.dataTransfer.files, 0, 0, editorUi.maxImageSize, createImportHandler(evt));
  8581. }
  8582. else if (mxUtils.indexOf(evt.dataTransfer.types, 'text/uri-list') >= 0)
  8583. {
  8584. var uri = decodeURIComponent(evt.dataTransfer.getData('text/uri-list'));
  8585. if (/(\.jpg)($|\?)/i.test(uri) || /(\.png)($|\?)/i.test(uri) ||
  8586. /(\.gif)($|\?)/i.test(uri) || /(\.svg)($|\?)/i.test(uri))
  8587. {
  8588. editorUi.loadImage(uri, function(img)
  8589. {
  8590. addButton(uri, null, 0, 0, img.width, img.height);
  8591. div.scrollTop = div.scrollHeight;
  8592. });
  8593. }
  8594. }
  8595. evt.stopPropagation();
  8596. evt.preventDefault();
  8597. };
  8598. mxEvent.addListener(div, 'dragover', dragOver);
  8599. mxEvent.addListener(div, 'drop', dropHandler);
  8600. mxEvent.addListener(bg, 'dragover', dragOver);
  8601. mxEvent.addListener(bg, 'drop', dropHandler);
  8602. outer.appendChild(div);
  8603. var btns = document.createElement('div');
  8604. btns.style.textAlign = 'right';
  8605. btns.style.marginTop = '20px';
  8606. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  8607. {
  8608. editorUi.hideDialog(true);
  8609. });
  8610. cancelBtn.setAttribute('id', 'btnCancel');
  8611. cancelBtn.className = 'geBtn';
  8612. if (editorUi.editor.cancelFirst)
  8613. {
  8614. btns.appendChild(cancelBtn);
  8615. }
  8616. if (editorUi.getServiceName() == 'draw.io' && file != null &&
  8617. // Limits button to ibraries which are known to have public URLs
  8618. (file.constructor == DriveLibrary || file.constructor == GitHubLibrary))
  8619. {
  8620. var btn = mxUtils.button(mxResources.get('link'), function()
  8621. {
  8622. if (editorUi.spinner.spin(document.body, mxResources.get('loading')))
  8623. {
  8624. file.getPublicUrl(function(url)
  8625. {
  8626. editorUi.spinner.stop();
  8627. if (url != null)
  8628. {
  8629. var search = editorUi.getSearch(['create', 'title', 'mode', 'url', 'drive', 'splash', 'state', 'clibs', 'ui']);
  8630. search += ((search.length == 0) ? '?' : '&') + 'splash=0&clibs=U' + encodeURIComponent(url);
  8631. var dlg = new EmbedDialog(editorUi, window.location.protocol + '//' +
  8632. window.location.host + '/' + search, null, null, null, null,
  8633. 'Check out the library I made using @drawio');
  8634. editorUi.showDialog(dlg.container, 450, 240, true);
  8635. dlg.init();
  8636. }
  8637. else if (file.constructor == DriveLibrary)
  8638. {
  8639. editorUi.showError(mxResources.get('error'), mxResources.get('diagramIsNotPublic'),
  8640. mxResources.get('share'), mxUtils.bind(this, function()
  8641. {
  8642. editorUi.drive.showPermissions(file.getId());
  8643. }), null, mxResources.get('ok'), mxUtils.bind(this, function()
  8644. {
  8645. // Hides dialog
  8646. })
  8647. );
  8648. }
  8649. else
  8650. {
  8651. editorUi.handleError({message: mxResources.get('diagramIsNotPublic')});
  8652. }
  8653. });
  8654. }
  8655. });
  8656. btn.className = 'geBtn';
  8657. btns.appendChild(btn);
  8658. }
  8659. var btn = mxUtils.button(mxResources.get('export'), function()
  8660. {
  8661. var data = editorUi.createLibraryDataFromImages(images);
  8662. var filename = nameInput.value;
  8663. if (!/(\.xml)$/i.test(filename))
  8664. {
  8665. filename += '.xml';
  8666. }
  8667. if (editorUi.isLocalFileSave())
  8668. {
  8669. editorUi.saveLocalFile(data, filename, 'text/xml', null, null, true, null, 'xml');
  8670. }
  8671. else
  8672. {
  8673. new mxXmlRequest(SAVE_URL, 'filename=' + encodeURIComponent(filename) +
  8674. '&format=xml&xml=' + encodeURIComponent(data)).simulate(document, '_blank');
  8675. }
  8676. });
  8677. btn.setAttribute('id', 'btnDownload');
  8678. btn.className = 'geBtn';
  8679. btns.appendChild(btn);
  8680. if (Graph.fileSupport)
  8681. {
  8682. if (editorUi.libDlgFileInputElt == null)
  8683. {
  8684. var fileInput = document.createElement('input');
  8685. fileInput.setAttribute('multiple', 'multiple');
  8686. fileInput.setAttribute('type', 'file');
  8687. mxEvent.addListener(fileInput, 'change', function(evt)
  8688. {
  8689. errorShowed = false;
  8690. editorUi.importFiles(fileInput.files, 0, 0, editorUi.maxImageSize, function(data, mimeType, x, y, w, h, img, doneFn, file)
  8691. {
  8692. if (fileInput.files != null)
  8693. {
  8694. createImportHandler(evt)(data, mimeType, x, y, w, h, img, doneFn, file);
  8695. // Resets input to force change event for same file (type reset required for IE)
  8696. fileInput.type = '';
  8697. fileInput.type = 'file';
  8698. fileInput.value = '';
  8699. }
  8700. });
  8701. div.scrollTop = div.scrollHeight;
  8702. });
  8703. fileInput.style.display = 'none';
  8704. document.body.appendChild(fileInput);
  8705. editorUi.libDlgFileInputElt = fileInput;
  8706. }
  8707. var btn = mxUtils.button(mxResources.get('import'), function()
  8708. {
  8709. if (stopEditing != null)
  8710. {
  8711. stopEditing();
  8712. stopEditing = null;
  8713. }
  8714. editorUi.libDlgFileInputElt.click();
  8715. });
  8716. btn.setAttribute('id', 'btnAddImage');
  8717. btn.className = 'geBtn';
  8718. btns.appendChild(btn);
  8719. }
  8720. var btn = mxUtils.button(mxResources.get('addImages'), function()
  8721. {
  8722. if (stopEditing != null)
  8723. {
  8724. stopEditing();
  8725. stopEditing = null;
  8726. }
  8727. editorUi.showImageDialog(mxResources.get('addImageUrl'), '', function(url, w, h)
  8728. {
  8729. errorShowed = false;
  8730. if (url != null)
  8731. {
  8732. // Image dialog returns modified data URLs which
  8733. // must be converted back to real data URL
  8734. if (url.substring(0, 11) == 'data:image/')
  8735. {
  8736. var comma = url.indexOf(',');
  8737. if (comma > 0)
  8738. {
  8739. url = url.substring(0, comma) + ';base64,' + url.substring(comma + 1);
  8740. }
  8741. }
  8742. addButton(url, null, 0, 0, w, h);
  8743. div.scrollTop = div.scrollHeight;
  8744. }
  8745. });
  8746. });
  8747. btn.setAttribute('id', 'btnAddImageUrl');
  8748. btn.className = 'geBtn';
  8749. btns.appendChild(btn);
  8750. // Indirection for overriding
  8751. this.saveBtnClickHandler = function(name, images, file, mode)
  8752. {
  8753. editorUi.saveLibrary(name, images, file, mode);
  8754. };
  8755. var btn = mxUtils.button(mxResources.get('save'),mxUtils.bind(this, function()
  8756. {
  8757. if (stopEditing != null)
  8758. {
  8759. stopEditing();
  8760. stopEditing = null;
  8761. }
  8762. this.saveBtnClickHandler(nameInput.value, images, file, mode);
  8763. }));
  8764. btn.setAttribute('id', 'btnSave');
  8765. btn.className = 'geBtn gePrimaryBtn';
  8766. btns.appendChild(btn);
  8767. if (!editorUi.editor.cancelFirst)
  8768. {
  8769. btns.appendChild(cancelBtn);
  8770. }
  8771. outer.appendChild(btns);
  8772. this.container = outer;
  8773. };
  8774. /**
  8775. * Constructs a new textarea dialog.
  8776. */
  8777. var EditShapeDialog = function(editorUi, cell, title, w, h)
  8778. {
  8779. w = (w != null) ? w : 300;
  8780. h = (h != null) ? h : 120;
  8781. var row, td;
  8782. var table = document.createElement('table');
  8783. var tbody = document.createElement('tbody');
  8784. table.style.cellPadding = '4px';
  8785. row = document.createElement('tr');
  8786. td = document.createElement('td');
  8787. td.setAttribute('colspan', '2');
  8788. td.style.fontSize = '10pt';
  8789. mxUtils.write(td, title);
  8790. row.appendChild(td);
  8791. tbody.appendChild(row);
  8792. row = document.createElement('tr');
  8793. td = document.createElement('td');
  8794. var nameInput = document.createElement('textarea');
  8795. nameInput.style.outline = 'none';
  8796. nameInput.style.resize = 'none';
  8797. nameInput.style.width = (w - 200) + 'px';
  8798. nameInput.style.height = h + 'px';
  8799. this.textarea = nameInput;
  8800. this.init = function()
  8801. {
  8802. nameInput.focus();
  8803. nameInput.scrollTop = 0;
  8804. };
  8805. td.appendChild(nameInput);
  8806. row.appendChild(td);
  8807. td = document.createElement('td');
  8808. var container = document.createElement('div');
  8809. container.style.position = 'relative';
  8810. container.style.border = '1px solid gray';
  8811. container.style.top = '6px';
  8812. container.style.width = '200px';
  8813. container.style.height = (h + 4) + 'px';
  8814. container.style.overflow = 'hidden';
  8815. container.style.marginBottom = '16px';
  8816. mxEvent.disableContextMenu(container);
  8817. td.appendChild(container);
  8818. var graph = new Graph(container);
  8819. graph.setEnabled(false);
  8820. var clone = editorUi.editor.graph.cloneCell(cell);
  8821. graph.addCells([clone]);
  8822. var state = graph.view.getState(clone);
  8823. var stencil = '';
  8824. if (state.shape != null && state.shape.stencil != null)
  8825. {
  8826. stencil = mxUtils.getPrettyXml(state.shape.stencil.desc);
  8827. }
  8828. mxUtils.write(nameInput, stencil || '');
  8829. var b = graph.getGraphBounds();
  8830. var ns = Math.min((200 - 40) / b.width, (h - 40) / b.height);
  8831. graph.view.scaleAndTranslate(ns, 20 / ns - b.x, 20 / ns - b.y);
  8832. row.appendChild(td);
  8833. tbody.appendChild(row);
  8834. row = document.createElement('tr');
  8835. td = document.createElement('td');
  8836. td.setAttribute('colspan', '2');
  8837. td.style.paddingTop = '2px';
  8838. td.style.whiteSpace = 'nowrap';
  8839. td.setAttribute('align', 'right');
  8840. if (!editorUi.isOffline())
  8841. {
  8842. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  8843. {
  8844. editorUi.openLink('https://www.diagrams.net/doc/faq/shape-complex-create-edit');
  8845. });
  8846. helpBtn.className = 'geBtn';
  8847. td.appendChild(helpBtn);
  8848. }
  8849. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  8850. {
  8851. editorUi.hideDialog();
  8852. });
  8853. cancelBtn.className = 'geBtn';
  8854. if (editorUi.editor.cancelFirst)
  8855. {
  8856. td.appendChild(cancelBtn);
  8857. }
  8858. var updateShape = function(targetGraph, targetCell, hide)
  8859. {
  8860. var newValue = nameInput.value;
  8861. // Checks if XML has changed (getPrettyXml "normalizes" DOM)
  8862. var doc = mxUtils.parseXml(newValue);
  8863. newValue = mxUtils.getPrettyXml(doc.documentElement);
  8864. // Checks for validation errors
  8865. // LATER: Validate against XSD
  8866. var errors = doc.documentElement.getElementsByTagName('parsererror');
  8867. if (errors != null && errors.length > 0)
  8868. {
  8869. editorUi.showError(mxResources.get('error'), mxResources.get('containsValidationErrors'), mxResources.get('ok'));
  8870. }
  8871. else
  8872. {
  8873. if (hide)
  8874. {
  8875. editorUi.hideDialog();
  8876. }
  8877. var isNew = !targetGraph.model.contains(targetCell);
  8878. if (!hide || isNew || newValue != stencil)
  8879. {
  8880. // Transform XML value to be used in cell style
  8881. newValue = Graph.compress(newValue);
  8882. targetGraph.getModel().beginUpdate();
  8883. try
  8884. {
  8885. // Inserts cell if required
  8886. if (isNew)
  8887. {
  8888. var pt = editorUi.editor.graph.getFreeInsertPoint();
  8889. targetCell.geometry.x = pt.x;
  8890. targetCell.geometry.y = pt.y;
  8891. targetGraph.addCell(targetCell)
  8892. }
  8893. targetGraph.setCellStyles(mxConstants.STYLE_SHAPE, 'stencil(' + newValue + ')', [targetCell]);
  8894. }
  8895. catch (e)
  8896. {
  8897. throw e;
  8898. }
  8899. finally
  8900. {
  8901. // Updates the display
  8902. targetGraph.getModel().endUpdate();
  8903. }
  8904. // Updates selection after stencil was created for rendering
  8905. if (isNew)
  8906. {
  8907. targetGraph.setSelectionCell(targetCell);
  8908. targetGraph.scrollCellToVisible(targetCell);
  8909. }
  8910. }
  8911. }
  8912. };
  8913. var previewBtn = mxUtils.button(mxResources.get('preview'), function()
  8914. {
  8915. updateShape(graph, clone, false);
  8916. });
  8917. previewBtn.className = 'geBtn';
  8918. td.appendChild(previewBtn);
  8919. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  8920. {
  8921. updateShape(editorUi.editor.graph, cell, true);
  8922. });
  8923. applyBtn.className = 'geBtn gePrimaryBtn';
  8924. td.appendChild(applyBtn);
  8925. if (!editorUi.editor.cancelFirst)
  8926. {
  8927. td.appendChild(cancelBtn);
  8928. }
  8929. row.appendChild(td);
  8930. tbody.appendChild(row);
  8931. table.appendChild(tbody);
  8932. this.container = table;
  8933. };
  8934. var CustomDialog = function(editorUi, content, okFn, cancelFn, okButtonText, helpLink,
  8935. buttonsContent, hideCancel, cancelButtonText, hideAfterOKFn, customButtons,
  8936. marginTop)
  8937. {
  8938. var div = document.createElement('div');
  8939. div.appendChild(content);
  8940. var btns = document.createElement('div');
  8941. btns.style.marginTop = (marginTop != null) ? marginTop : '30px';
  8942. btns.style.textAlign = 'center';
  8943. if (buttonsContent != null)
  8944. {
  8945. btns.appendChild(buttonsContent);
  8946. }
  8947. if (!editorUi.isOffline() && helpLink != null)
  8948. {
  8949. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  8950. {
  8951. editorUi.openLink(helpLink);
  8952. });
  8953. helpBtn.className = 'geBtn';
  8954. btns.appendChild(helpBtn);
  8955. }
  8956. var cancelBtn = mxUtils.button(cancelButtonText || mxResources.get('cancel'), function()
  8957. {
  8958. editorUi.hideDialog();
  8959. if (cancelFn != null)
  8960. {
  8961. cancelFn();
  8962. }
  8963. });
  8964. cancelBtn.className = 'geBtn';
  8965. if (hideCancel)
  8966. {
  8967. cancelBtn.style.display = 'none';
  8968. }
  8969. if (editorUi.editor.cancelFirst)
  8970. {
  8971. btns.appendChild(cancelBtn);
  8972. }
  8973. var okBtn = mxUtils.button(okButtonText || mxResources.get('ok'), mxUtils.bind(this, function()
  8974. {
  8975. if (!hideAfterOKFn)
  8976. {
  8977. editorUi.hideDialog(null, null, this.container);
  8978. }
  8979. if (okFn != null)
  8980. {
  8981. var okRet = okFn();
  8982. if (typeof okRet === 'string')
  8983. {
  8984. editorUi.showError(mxResources.get('error'), okRet);
  8985. return;
  8986. }
  8987. }
  8988. if (hideAfterOKFn)
  8989. {
  8990. editorUi.hideDialog(null, null, this.container);
  8991. }
  8992. }));
  8993. btns.appendChild(okBtn);
  8994. okBtn.className = 'geBtn gePrimaryBtn';
  8995. if (!editorUi.editor.cancelFirst)
  8996. {
  8997. btns.appendChild(cancelBtn);
  8998. }
  8999. if (customButtons != null)
  9000. {
  9001. for (var i = 0; i < customButtons.length; i++)
  9002. {
  9003. (function(label, fn, title)
  9004. {
  9005. var customBtn = mxUtils.button(label, function(e)
  9006. {
  9007. fn(e);
  9008. });
  9009. if (title != null)
  9010. {
  9011. customBtn.setAttribute('title', title);
  9012. }
  9013. customBtn.className = 'geBtn';
  9014. btns.appendChild(customBtn);
  9015. })(customButtons[i][0], customButtons[i][1], customButtons[i][2]);
  9016. }
  9017. }
  9018. div.appendChild(btns);
  9019. this.cancelBtn = cancelBtn;
  9020. this.okButton = okBtn;
  9021. this.container = div;
  9022. };
  9023. //TODO Many of the code is the same as NewDialog. Needs merging
  9024. var TemplatesDialog = function(editorUi, callback, cancelCallback,
  9025. templateFile, newDiagramCatsFile, username, recentDocsCallback, searchDocsCallback,
  9026. loadExtDoc, linkToDiagramCallback, customTempCallback, withOpen, withLink, withoutType, noDlgHide)
  9027. {
  9028. var dialogSkeleton =
  9029. '<div class="geTempDlgHeader">' +
  9030. '<img src="/images/draw.io-logo.svg" class="geTempDlgHeaderLogo">' +
  9031. '<input type="search" class="geTempDlgSearchBox" ' + (searchDocsCallback? '' : 'style="display: none"')
  9032. + ' placeholder="'+ mxResources.get('search') +'">' +
  9033. '</div>' +
  9034. '<div class="geTemplatesList" style="display: none">' +
  9035. '<div class="geTempDlgBack">&lt; '+ mxResources.get('back') + '</div>' +
  9036. '<div class="geTempDlgHLine"></div>' +
  9037. '<div class="geTemplatesLbl">'+ mxResources.get('templates') + '</div>' +
  9038. '</div>' +
  9039. '<div class="geTempDlgContent" style="width: 100%">' +
  9040. '<div class="geTempDlgNewDiagramCat">' +
  9041. '<div class="geTempDlgNewDiagramCatLbl">'+ mxResources.get('newDiagram') +'</div>' +
  9042. '<div class="geTempDlgNewDiagramCatList">' +
  9043. '</div>' +
  9044. '<div class="geTempDlgNewDiagramCatFooter">' +
  9045. '<div class="geTempDlgShowAllBtn">'+ mxResources.get('showMore') +'</div>' +
  9046. '</div>' +
  9047. '</div>' +
  9048. '<div class="geTempDlgDiagramsList">' +
  9049. '<div class="geTempDlgDiagramsListHeader">' +
  9050. '<div class="geTempDlgDiagramsListTitle"></div>' +
  9051. '<div class="geTempDlgDiagramsListBtns">' +
  9052. '<div class="geTempDlgRadioBtn geTempDlgRadioBtnLarge" data-id="myDiagramsBtn">' +
  9053. '<img src="/images/my-diagrams.svg" class="geTempDlgMyDiagramsBtnImg"> <span>'+ mxResources.get('myDiagrams') + '</span>' +
  9054. '</div><div class="geTempDlgRadioBtn geTempDlgRadioBtnLarge geTempDlgRadioBtnActive" data-id="allDiagramsBtn">' +
  9055. '<img src="/images/all-diagrams-sel.svg" class="geTempDlgAllDiagramsBtnImg"> <span>'+ mxResources.get('allDiagrams') + '</span>' +
  9056. '</div><div class="geTempDlgSpacer"> </div><div class="geTempDlgRadioBtn geTempDlgRadioBtnSmall geTempDlgRadioBtnActive" data-id="tilesBtn">' +
  9057. '<img src="/images/tiles-sel.svg" class="geTempDlgTilesBtnImg">' +
  9058. '</div><div class="geTempDlgRadioBtn geTempDlgRadioBtnSmall" data-id="listBtn">' +
  9059. '<img src="/images/list.svg" class="geTempDlgListBtnImg">' +
  9060. '</div>' +
  9061. '</div>' +
  9062. '</div>' +
  9063. '<div class="geTempDlgDiagramsTiles">' +
  9064. '</div>'+
  9065. '</div>' +
  9066. '</div>' +
  9067. '<br style="clear:both;"/>' +
  9068. '<div class="geTempDlgFooter">' +
  9069. '<div class="geTempDlgErrMsg"></div>' +
  9070. (withLink?
  9071. '<span class="geTempDlgLinkToDiagram geTempDlgLinkToDiagramHint">' + mxResources.get('linkToDiagramHint') + '</span>' +
  9072. '<button class="geTempDlgLinkToDiagram geTempDlgLinkToDiagramBtn">'+ mxResources.get('linkToDiagram') + '</button>' :
  9073. ''
  9074. ) +
  9075. (withOpen? '<div class="geTempDlgOpenBtn">'+ mxResources.get('open') + '</div>' : '') +
  9076. '<div class="geTempDlgCreateBtn">'+ mxResources.get('create') + '</div>' +
  9077. '<div class="geTempDlgCancelBtn">'+ mxResources.get('cancel') + '</div>' +
  9078. '</div>';
  9079. var dlg = this;
  9080. var dlgDiv = document.createElement('div');
  9081. dlgDiv.innerHTML = dialogSkeleton;
  9082. dlgDiv.className = "geTemplateDlg";
  9083. this.container = dlgDiv;
  9084. templateFile = (templateFile != null) ? templateFile : (TEMPLATE_PATH + '/index.xml');
  9085. newDiagramCatsFile = (newDiagramCatsFile != null) ? newDiagramCatsFile : NEW_DIAGRAM_CATS_PATH + '/index.xml';
  9086. var callInitiated = false;
  9087. var cancelPendingCall = false;
  9088. var currentEntry = null, lastEntry = null;
  9089. var currentItem = null;
  9090. var currentItemInfo = null;
  9091. var showingAll = false;
  9092. var isGetAll = true;
  9093. var showAsList = false;
  9094. var curDiagList = [], curSearchImportCats = null;
  9095. var lastSearchStr, lastGetAll;
  9096. var categorySelected = true;
  9097. var inTempScreen = false;
  9098. var showAllBtn = dlgDiv.querySelector(".geTempDlgShowAllBtn");
  9099. var diagramsTiles = dlgDiv.querySelector('.geTempDlgDiagramsTiles');
  9100. var diagramsListTitle = dlgDiv.querySelector('.geTempDlgDiagramsListTitle');
  9101. var diagramsListBtns = dlgDiv.querySelector('.geTempDlgDiagramsListBtns');
  9102. var tempDlgContent = dlgDiv.querySelector('.geTempDlgContent');
  9103. var diagramsList = dlgDiv.querySelector('.geTempDlgDiagramsList');
  9104. var newDiagramCat = dlgDiv.querySelector('.geTempDlgNewDiagramCat');
  9105. var newDiagramCatList = dlgDiv.querySelector(".geTempDlgNewDiagramCatList");
  9106. var createBtn = dlgDiv.querySelector('.geTempDlgCreateBtn');
  9107. var openBtn = dlgDiv.querySelector('.geTempDlgOpenBtn');
  9108. var searchInout = dlgDiv.querySelector('.geTempDlgSearchBox');
  9109. var errMsg = dlgDiv.querySelector('.geTempDlgErrMsg');
  9110. var spinner = new Spinner({
  9111. lines: 12, // The number of lines to draw
  9112. length: 10, // The length of each line
  9113. width: 5, // The line thickness
  9114. radius: 10, // The radius of the inner circle
  9115. rotate: 0, // The rotation offset
  9116. color: '#000', // #rgb or #rrggbb
  9117. speed: 1.5, // Rounds per second
  9118. trail: 60, // Afterglow percentage
  9119. shadow: false, // Whether to render a shadow
  9120. hwaccel: false, // Whether to use hardware acceleration
  9121. top: '50px',
  9122. zIndex: 2e9 // The z-index (defaults to 2000000000)
  9123. });
  9124. function showError(msg)
  9125. {
  9126. errMsg.innerText = msg;
  9127. errMsg.style.display = 'block';
  9128. setTimeout(function()
  9129. {
  9130. errMsg.style.display = 'none';
  9131. }, 4000);
  9132. };
  9133. function deselectTempCat()
  9134. {
  9135. if (currentEntry != null)
  9136. {
  9137. currentEntry.style.fontWeight = 'normal';
  9138. currentEntry.style.textDecoration = 'none';
  9139. lastEntry = currentEntry;
  9140. currentEntry = null;
  9141. }
  9142. };
  9143. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgBack'), 'click', function()
  9144. {
  9145. deselectTempCat();
  9146. inTempScreen = false;
  9147. var list = dlgDiv.querySelector(".geTemplatesList");
  9148. list.style.display = 'none';
  9149. tempDlgContent.style.width = '100%';
  9150. newDiagramCat.style.display = '';
  9151. diagramsList.style.minHeight = 'calc(100% - 280px)';
  9152. searchInout.style.display = searchDocsCallback? '' : 'none';
  9153. searchInout.value = '';
  9154. lastSearchStr = null;
  9155. getRecentDocs(isGetAll);
  9156. });
  9157. function radioClick(btn, btnImgId, btnImgFile, otherBtnId, otherBtnImgId, otherBtnImgFile, isLarge)
  9158. {
  9159. if (btn.className.indexOf('geTempDlgRadioBtnActive') > -1)
  9160. {
  9161. return false;
  9162. }
  9163. else
  9164. {
  9165. btn.className += ' geTempDlgRadioBtnActive';
  9166. dlgDiv.querySelector('.geTempDlgRadioBtn[data-id='+ otherBtnId +']').className = "geTempDlgRadioBtn " +
  9167. (isLarge? "geTempDlgRadioBtnLarge" : "geTempDlgRadioBtnSmall");
  9168. dlgDiv.querySelector('.'+ btnImgId).src = "/images/"+ btnImgFile +"-sel.svg";
  9169. dlgDiv.querySelector('.'+ otherBtnImgId).src = "/images/"+ otherBtnImgFile +".svg";
  9170. return true;
  9171. }
  9172. };
  9173. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=allDiagramsBtn]'), 'click', function()
  9174. {
  9175. if (radioClick(this, 'geTempDlgAllDiagramsBtnImg', 'all-diagrams', 'myDiagramsBtn', 'geTempDlgMyDiagramsBtnImg', 'my-diagrams', true))
  9176. {
  9177. isGetAll = true;
  9178. lastSearchStr == null? getRecentDocs(isGetAll) : doSearch(lastSearchStr);
  9179. }
  9180. });
  9181. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=myDiagramsBtn]'), 'click', function()
  9182. {
  9183. if (radioClick(this, 'geTempDlgMyDiagramsBtnImg', 'my-diagrams', 'allDiagramsBtn', 'geTempDlgAllDiagramsBtnImg', 'all-diagrams', true))
  9184. {
  9185. isGetAll = false;
  9186. lastSearchStr == null? getRecentDocs(isGetAll) : doSearch(lastSearchStr);
  9187. }
  9188. });
  9189. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=listBtn]'), 'click', function()
  9190. {
  9191. if (radioClick(this, 'geTempDlgListBtnImg', 'list', 'tilesBtn', 'geTempDlgTilesBtnImg', 'tiles', false))
  9192. {
  9193. showAsList = true;
  9194. fillDiagramsList(curDiagList, false, showAsList, curSearchImportCats);
  9195. }
  9196. });
  9197. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgRadioBtn[data-id=tilesBtn]'), 'click', function()
  9198. {
  9199. if (radioClick(this, 'geTempDlgTilesBtnImg', 'tiles', 'listBtn', 'geTempDlgListBtnImg', 'list', false))
  9200. {
  9201. showAsList = false;
  9202. fillDiagramsList(curDiagList, false, showAsList, curSearchImportCats);
  9203. }
  9204. });
  9205. var loading = false;
  9206. function createPreview(diagram, elt, img, evt)
  9207. {
  9208. var xmlData = null;
  9209. function loadXmlData(url, callback)
  9210. {
  9211. if (xmlData == null)
  9212. {
  9213. var realUrl = url;
  9214. if (/^https?:\/\//.test(realUrl) && !editorUi.editor.isCorsEnabledForUrl(realUrl))
  9215. {
  9216. realUrl = PROXY_URL + '?url=' + encodeURIComponent(realUrl);
  9217. }
  9218. else
  9219. {
  9220. realUrl = TEMPLATE_PATH + '/' + realUrl;
  9221. }
  9222. mxUtils.get(realUrl, mxUtils.bind(this, function(req)
  9223. {
  9224. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  9225. {
  9226. xmlData = req.getText();
  9227. callback(xmlData);
  9228. }
  9229. else
  9230. {
  9231. callback(xmlData);
  9232. }
  9233. }));
  9234. }
  9235. else
  9236. {
  9237. callback(xmlData);
  9238. }
  9239. }
  9240. // Shows a tooltip with the rendered template
  9241. function showTooltip(xml, x, y)
  9242. {
  9243. // Checks if dialog still visible
  9244. if (xml != null && mxUtils.isAncestorNode(document.body, elt))
  9245. {
  9246. var doc = mxUtils.parseXml(xml);
  9247. var tempNode = Editor.extractGraphModel(doc.documentElement, true);
  9248. if (tempNode == null) return; //Not a diagram file
  9249. if (tempNode.nodeName == 'mxfile')
  9250. {
  9251. var tempNode = Editor.parseDiagramNode(tempNode.getElementsByTagName('diagram')[0]);
  9252. }
  9253. var codec = new mxCodec(tempNode.ownerDocument);
  9254. var model = new mxGraphModel();
  9255. codec.decode(tempNode, model);
  9256. var cells = model.root.getChildAt(0).children || [];
  9257. var ww = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  9258. var wh = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  9259. // TODO: Use maxscreensize
  9260. editorUi.sidebar.createTooltip(elt, cells, Math.min(ww - 80, 1000), Math.min(wh - 80, 800),
  9261. (diagram.title != null) ? mxResources.get(diagram.title, null, diagram.title) : null,
  9262. true, new mxPoint(x, y), true, null, true);
  9263. var mask = document.createElement('div');
  9264. mask.className = "geTempDlgDialogMask";
  9265. dlgDiv.appendChild(mask);
  9266. //Remove the mask when tooltop is hidden
  9267. var origHideTooltip = editorUi.sidebar.hideTooltip;
  9268. editorUi.sidebar.hideTooltip = function()
  9269. {
  9270. if (mask)
  9271. {
  9272. dlgDiv.removeChild(mask);
  9273. mask = null;
  9274. origHideTooltip.apply(this, arguments);
  9275. editorUi.sidebar.hideTooltip = origHideTooltip;
  9276. }
  9277. };
  9278. mxEvent.addListener(mask, 'click', function()
  9279. {
  9280. editorUi.sidebar.hideTooltip();
  9281. });
  9282. }
  9283. };
  9284. if (!loading && editorUi.sidebar.currentElt != elt)
  9285. {
  9286. editorUi.sidebar.hideTooltip();
  9287. editorUi.sidebar.currentElt = elt;
  9288. loading = true;
  9289. img.src = '/images/aui-wait.gif';
  9290. function renderXML(xml)
  9291. {
  9292. if (loading && editorUi.sidebar.currentElt == elt)
  9293. {
  9294. showTooltip(xml, mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  9295. }
  9296. loading = false;
  9297. img.src = '/images/icon-search.svg';
  9298. };
  9299. if (diagram.isExt)
  9300. {
  9301. loadExtDoc(diagram, renderXML, function()
  9302. {
  9303. showError(mxResources.get('cantLoadPrev'));
  9304. loading = false;
  9305. img.src = '/images/icon-search.svg';
  9306. });
  9307. }
  9308. else
  9309. {
  9310. loadXmlData(diagram.url, renderXML);
  9311. }
  9312. }
  9313. else
  9314. {
  9315. editorUi.sidebar.hideTooltip();
  9316. }
  9317. };
  9318. function swapActiveItem(newItem, activeCls, itemInfo)
  9319. {
  9320. if (currentItem != null)
  9321. {
  9322. var classes = currentItem.className.split(" ");
  9323. for (var i = 0; i < classes.length; i++)
  9324. {
  9325. if (classes[i].indexOf("Active") > -1)
  9326. {
  9327. classes.splice(i, 1);
  9328. break;
  9329. }
  9330. }
  9331. currentItem.className = classes.join(" ");
  9332. }
  9333. if (newItem != null)
  9334. {
  9335. currentItem = newItem;
  9336. currentItem.className += " " + activeCls;
  9337. currentItemInfo = itemInfo;
  9338. categorySelected = itemInfo.isCategory;
  9339. //activate create button
  9340. createBtn.className = "geTempDlgCreateBtn";
  9341. }
  9342. else
  9343. {
  9344. currentItem = null;
  9345. currentItemInfo = null;
  9346. //disable create button
  9347. createBtn.className = "geTempDlgCreateBtn geTempDlgBtnDisabled";
  9348. }
  9349. };
  9350. function handleDialogOK(linkToDiagram, openDiagram)
  9351. {
  9352. if (currentItemInfo != null)
  9353. {
  9354. var itemInfo = currentItemInfo;
  9355. //disable create button
  9356. currentItemInfo = null;
  9357. if (typeof openDiagram !== 'boolean')
  9358. {
  9359. openDiagram = itemInfo.isExternal && withOpen; //Double click default to open with external docs
  9360. }
  9361. function cancelSubmit()
  9362. {
  9363. currentItemInfo = itemInfo;
  9364. createBtn.className = 'geTempDlgCreateBtn';
  9365. if (openDiagram)
  9366. {
  9367. openBtn.className = 'geTempDlgOpenBtn';
  9368. }
  9369. };
  9370. function submitErr()
  9371. {
  9372. showError(mxResources.get('cannotLoad'));
  9373. cancelSubmit();
  9374. };
  9375. function doSubmit(xml, filename)
  9376. {
  9377. if (!noDlgHide)
  9378. {
  9379. editorUi.hideDialog(true);
  9380. }
  9381. callback(xml, filename, itemInfo, openDiagram);
  9382. };
  9383. function startSubmit(filename)
  9384. {
  9385. if (itemInfo.isExternal)
  9386. {
  9387. loadExtDoc(itemInfo, function(xml)
  9388. {
  9389. doSubmit(xml, filename);
  9390. }, submitErr);
  9391. }
  9392. else if (itemInfo.url)
  9393. {
  9394. mxUtils.get(TEMPLATE_PATH + '/' + itemInfo.url, mxUtils.bind(this, function(req)
  9395. {
  9396. if (req.getStatus() >= 200 && req.getStatus() <= 299)
  9397. {
  9398. doSubmit(req.getText(), filename);
  9399. }
  9400. else
  9401. {
  9402. submitErr();
  9403. }
  9404. }));
  9405. }
  9406. else
  9407. {
  9408. doSubmit(editorUi.emptyDiagramXml, filename);
  9409. }
  9410. };
  9411. if (linkToDiagram == true)
  9412. {
  9413. linkToDiagramCallback(itemInfo.url, itemInfo);
  9414. }
  9415. else if (openDiagram)
  9416. {
  9417. openBtn.className = "geTempDlgOpenBtn geTempDlgBtnDisabled geTempDlgBtnBusy";
  9418. startSubmit();
  9419. }
  9420. else
  9421. {
  9422. createBtn.className = "geTempDlgCreateBtn geTempDlgBtnDisabled geTempDlgBtnBusy";
  9423. var nameTitle = (((editorUi.mode == null || editorUi.mode == App.MODE_GOOGLE ||
  9424. editorUi.mode == App.MODE_BROWSER) ? mxResources.get('diagramName') : mxResources.get('filename')));
  9425. var nameDlg = new FilenameDialog(editorUi, editorUi.defaultFilename + '.drawio',
  9426. mxResources.get('ok'), startSubmit, nameTitle, function(name)
  9427. {
  9428. //TODO validate?
  9429. var valid = name != null && name.length > 0;
  9430. if (valid && noDlgHide)
  9431. {
  9432. startSubmit(name);
  9433. return false; //prevent closing
  9434. }
  9435. return valid;
  9436. }, null, null, null, cancelSubmit, withoutType? null : []);
  9437. editorUi.showDialog(nameDlg.container, 350, 80, true, true);
  9438. nameDlg.init();
  9439. }
  9440. }
  9441. };
  9442. function toggleButtons(isTemplate)
  9443. {
  9444. createBtn.innerText = mxResources.get(inTempScreen || isTemplate? 'create' : 'copy');
  9445. var opemDisplay = isTemplate? 'none' : '';
  9446. if (withOpen)
  9447. {
  9448. openBtn.style.display = opemDisplay;
  9449. }
  9450. var elems = dlgDiv.querySelectorAll(".geTempDlgLinkToDiagram");
  9451. for(var i = 0; i < elems.length; i++)
  9452. {
  9453. elems[i].style.display = opemDisplay;
  9454. }
  9455. };
  9456. function fillDiagramsList(diagrams, isTemplate, asList, searchImportCats, internalCall)
  9457. {
  9458. function setSubmitBtnLbl()
  9459. {
  9460. toggleButtons(isTemplate);
  9461. };
  9462. if (!internalCall)
  9463. {
  9464. diagramsTiles.innerText = '';
  9465. swapActiveItem();
  9466. curDiagList = diagrams;
  9467. curSearchImportCats = searchImportCats;
  9468. }
  9469. var grid = null;
  9470. if (asList)
  9471. {
  9472. grid = document.createElement('table');
  9473. grid.className = 'geTempDlgDiagramsListGrid';
  9474. //create header row
  9475. var hrow = document.createElement('tr');
  9476. var th = document.createElement('th');
  9477. th.style.width = "50%";
  9478. th.innerText = mxResources.get('diagram');
  9479. hrow.appendChild(th);
  9480. th = document.createElement('th');
  9481. th.style.width = "25%";
  9482. th.innerText = mxResources.get('changedBy');
  9483. hrow.appendChild(th);
  9484. th = document.createElement('th');
  9485. th.style.width = "25%";
  9486. th.innerText = mxResources.get('lastModifiedOn');
  9487. hrow.appendChild(th);
  9488. grid.appendChild(hrow);
  9489. diagramsTiles.appendChild(grid);
  9490. }
  9491. //TODO support paging
  9492. for (var i = 0; i < diagrams.length; i++)
  9493. {
  9494. diagrams[i].isExternal = !isTemplate;
  9495. var url = diagrams[i].url;
  9496. var title = mxUtils.htmlEntities(isTemplate?
  9497. mxResources.get(diagrams[i].title, null, diagrams[i].title):
  9498. diagrams[i].title);
  9499. var tooltip = title || diagrams[i].url;
  9500. var imgUrl = diagrams[i].imgUrl;
  9501. var changedBy = diagrams[i].changedBy || '';
  9502. var lastModifiedOn = '';
  9503. if (diagrams[i].lastModifiedOn)
  9504. {
  9505. var str = editorUi.timeSince(new Date(diagrams[i].lastModifiedOn));
  9506. if (str == null)
  9507. {
  9508. str = mxResources.get('lessThanAMinute');
  9509. }
  9510. lastModifiedOn = mxResources.get('timeAgo', [str], '{1} ago');
  9511. }
  9512. if (!imgUrl)
  9513. {
  9514. imgUrl = TEMPLATE_PATH + '/' + url.substring(0, url.length - 4) + '.png';
  9515. }
  9516. var titleLimit = asList? 50 : 15;
  9517. if (title != null && title.length > titleLimit)
  9518. {
  9519. title = title.substring(0, titleLimit) + '&hellip;';
  9520. }
  9521. if (asList)
  9522. {
  9523. var row = document.createElement('tr');
  9524. var td = document.createElement('td');
  9525. var prevImg = document.createElement('img');
  9526. prevImg.src = "/images/icon-search.svg";
  9527. prevImg.className = "geTempDlgDiagramListPreviewBtn";
  9528. prevImg.setAttribute('title', mxResources.get("preview"));
  9529. if (!internalCall)
  9530. {
  9531. td.appendChild(prevImg);
  9532. }
  9533. var titleSpan = document.createElement('span');
  9534. titleSpan.className = "geTempDlgDiagramTitle";
  9535. titleSpan.innerHTML = title;
  9536. td.appendChild(titleSpan);
  9537. row.appendChild(td);
  9538. td = document.createElement('td');
  9539. td.innerText = changedBy;
  9540. row.appendChild(td);
  9541. td = document.createElement('td');
  9542. td.innerText = lastModifiedOn;
  9543. row.appendChild(td);
  9544. grid.appendChild(row);
  9545. if (currentItem == null)
  9546. {
  9547. setSubmitBtnLbl();
  9548. swapActiveItem(row, "geTempDlgDiagramsListGridActive", diagrams[i]);
  9549. }
  9550. (function(diagram2, row2, prevImg2)
  9551. {
  9552. mxEvent.addListener(row, 'click', function()
  9553. {
  9554. if (currentItem != row2)
  9555. {
  9556. setSubmitBtnLbl();
  9557. swapActiveItem(row2, "geTempDlgDiagramsListGridActive", diagram2);
  9558. }
  9559. });
  9560. mxEvent.addListener(row, 'dblclick', handleDialogOK);
  9561. mxEvent.addListener(prevImg, 'click', function(evt)
  9562. {
  9563. createPreview(diagram2, row2, prevImg2, evt);
  9564. });
  9565. })(diagrams[i], row, prevImg);
  9566. }
  9567. else
  9568. {
  9569. var tile = document.createElement('div');
  9570. tile.className = "geTempDlgDiagramTile";
  9571. tile.setAttribute('title', tooltip);
  9572. if (currentItem == null)
  9573. {
  9574. setSubmitBtnLbl();
  9575. swapActiveItem(tile, "geTempDlgDiagramTileActive", diagrams[i]);
  9576. }
  9577. var imgDiv = document.createElement('div');
  9578. imgDiv.className = "geTempDlgDiagramTileImg geTempDlgDiagramTileImgLoading";
  9579. var img = document.createElement('img');
  9580. img.style.display = "none";
  9581. (function(img2, imgDiv2, fallbackImgUrl)
  9582. {
  9583. img.onload = function()
  9584. {
  9585. imgDiv2.className = "geTempDlgDiagramTileImg";
  9586. img2.style.display = "";
  9587. }
  9588. img.onerror = function()
  9589. {
  9590. if (this.src != fallbackImgUrl)
  9591. {
  9592. this.src = fallbackImgUrl;
  9593. }
  9594. else
  9595. {
  9596. imgDiv2.className = "geTempDlgDiagramTileImg geTempDlgDiagramTileImgError";
  9597. }
  9598. }
  9599. })(img, imgDiv, imgUrl? imgUrl.replace('.drawio.xml', '').replace('.drawio', '').replace('.xml', '') : '');
  9600. img.src = imgUrl;
  9601. imgDiv.appendChild(img);
  9602. tile.appendChild(imgDiv);
  9603. var lblDiv = document.createElement('div');
  9604. lblDiv.className = "geTempDlgDiagramTileLbl";
  9605. lblDiv.innerHTML = title != null? title : '';
  9606. tile.appendChild(lblDiv);
  9607. var prevImg = document.createElement('img');
  9608. prevImg.src = "/images/icon-search.svg";
  9609. prevImg.className = "geTempDlgDiagramPreviewBtn";
  9610. prevImg.setAttribute('title', mxResources.get("preview"));
  9611. if (!internalCall)
  9612. {
  9613. tile.appendChild(prevImg);
  9614. }
  9615. (function(diagram2, tile2, prevImg2)
  9616. {
  9617. mxEvent.addListener(tile, 'click', function()
  9618. {
  9619. if (currentItem != tile2)
  9620. {
  9621. setSubmitBtnLbl();
  9622. swapActiveItem(tile2, "geTempDlgDiagramTileActive", diagram2);
  9623. }
  9624. });
  9625. mxEvent.addListener(tile, 'dblclick', handleDialogOK);
  9626. mxEvent.addListener(prevImg, 'click', function(evt)
  9627. {
  9628. createPreview(diagram2, tile2, prevImg2, evt);
  9629. });
  9630. })(diagrams[i], tile, prevImg);
  9631. diagramsTiles.appendChild(tile);
  9632. }
  9633. }
  9634. for (var cat in searchImportCats)
  9635. {
  9636. var catList = searchImportCats[cat];
  9637. if (catList.length > 0)
  9638. {
  9639. var header = document.createElement('div');
  9640. header.className = 'geTempDlgImportCat';
  9641. header.innerText = mxResources.get(cat, null, cat);
  9642. diagramsTiles.appendChild(header);
  9643. fillDiagramsList(catList, isTemplate, asList, null, true);
  9644. }
  9645. }
  9646. };
  9647. function fillNewDiagramCats(newDiagramCats, showAll)
  9648. {
  9649. newDiagramCatList.innerText = '';
  9650. swapActiveItem();
  9651. var oneRowCount = Math.floor(newDiagramCatList.offsetWidth / 150) - 1;
  9652. var catCount = !showAll && newDiagramCats.length > oneRowCount ? oneRowCount : newDiagramCats.length;
  9653. for (var i = 0; i < catCount; i++)
  9654. {
  9655. var cat = newDiagramCats[i];
  9656. cat.isCategory = true;
  9657. var entry = document.createElement('div');
  9658. var label = mxResources.get(cat.title);
  9659. if (label == null)
  9660. {
  9661. label = cat.title.substring(0, 1).toUpperCase() + cat.title.substring(1);
  9662. }
  9663. entry.className = 'geTempDlgNewDiagramCatItem';
  9664. entry.setAttribute('title', label);
  9665. label = mxUtils.htmlEntities(label);
  9666. if (label.length > 15)
  9667. {
  9668. label = label.substring(0, 15) + '&hellip;';
  9669. }
  9670. if (currentItem == null)
  9671. {
  9672. toggleButtons(true);
  9673. swapActiveItem(entry, "geTempDlgNewDiagramCatItemActive", cat);
  9674. }
  9675. var imgDiv = document.createElement('div');
  9676. imgDiv.className = "geTempDlgNewDiagramCatItemImg";
  9677. var img = document.createElement('img');
  9678. img.src = NEW_DIAGRAM_CATS_PATH + '/' + cat.img;
  9679. imgDiv.appendChild(img);
  9680. entry.appendChild(imgDiv);
  9681. var lblDiv = document.createElement('div');
  9682. lblDiv.className = "geTempDlgNewDiagramCatItemLbl";
  9683. lblDiv.innerHTML = label;
  9684. entry.appendChild(lblDiv);
  9685. newDiagramCatList.appendChild(entry);
  9686. (function(cat2, entry2)
  9687. {
  9688. mxEvent.addListener(entry, 'click', function()
  9689. {
  9690. if (currentItem != entry2)
  9691. {
  9692. toggleButtons(true);
  9693. swapActiveItem(entry2, "geTempDlgNewDiagramCatItemActive", cat2);
  9694. }
  9695. });
  9696. mxEvent.addListener(entry, 'dblclick', handleDialogOK);
  9697. })(cat, entry);
  9698. }
  9699. //Add the "Show All Templates" card
  9700. var entry = document.createElement('div');
  9701. entry.className = 'geTempDlgNewDiagramCatItem';
  9702. var label = mxResources.get('showAllTemps');
  9703. entry.setAttribute('title', label);
  9704. var imgDiv = document.createElement('div');
  9705. imgDiv.className = "geTempDlgNewDiagramCatItemImg";
  9706. imgDiv.innerText = '...';
  9707. imgDiv.style.fontSize = '32px';
  9708. entry.appendChild(imgDiv);
  9709. var lblDiv = document.createElement('div');
  9710. lblDiv.className = "geTempDlgNewDiagramCatItemLbl";
  9711. lblDiv.innerText = label;
  9712. entry.appendChild(lblDiv);
  9713. newDiagramCatList.appendChild(entry);
  9714. mxEvent.addListener(entry, 'click', function()
  9715. {
  9716. //Show templates screen
  9717. inTempScreen = true;
  9718. var list = dlgDiv.querySelector(".geTemplatesList");
  9719. list.style.display = 'block';
  9720. tempDlgContent.style.width = '';
  9721. searchInout.style.display = '';
  9722. searchInout.value = '';
  9723. lastSearchStr = null;
  9724. function openFirstCat()
  9725. {
  9726. var firstCat = list.querySelector('.geTemplateDrawioCatLink');
  9727. if (firstCat != null)
  9728. {
  9729. firstCat.click();
  9730. }
  9731. else
  9732. {
  9733. setTimeout(openFirstCat, 200);
  9734. }
  9735. };
  9736. openFirstCat();
  9737. });
  9738. showAllBtn.style.display = newDiagramCats.length <= oneRowCount ? "none" : "";
  9739. };
  9740. mxEvent.addListener(showAllBtn, 'click', function()
  9741. {
  9742. if (showingAll)
  9743. {
  9744. newDiagramCat.style.height = "280px";
  9745. newDiagramCatList.style.height = "190px";
  9746. showAllBtn.innerText = mxResources.get('showMore');
  9747. fillNewDiagramCats(newDiagramCats);
  9748. }
  9749. else
  9750. {
  9751. newDiagramCat.style.height = "440px";
  9752. newDiagramCatList.style.height = "355px";
  9753. showAllBtn.innerText = mxResources.get('showLess');
  9754. fillNewDiagramCats(newDiagramCats, true);
  9755. }
  9756. showingAll = !showingAll;
  9757. });
  9758. function fillTemplatesList(categories, customCats, customCatCount)
  9759. {
  9760. var list = dlgDiv.querySelector(".geTemplatesList");
  9761. function getEntryTitle(cat, templateList)
  9762. {
  9763. var label = mxResources.get(cat, null, cat.substring(0, 1).
  9764. toUpperCase() + cat.substring(1));
  9765. var fullLbl = label + ' (' + templateList.length + ')';
  9766. label = mxUtils.htmlEntities(label);
  9767. var lblOnly = label;
  9768. if (label.length > 15)
  9769. {
  9770. label = label.substring(0, 15) + '&hellip;';
  9771. }
  9772. return {lbl: label + ' (' + templateList.length + ')', fullLbl: fullLbl, lblOnly: lblOnly};
  9773. };
  9774. function addEntryHandler(cat, label, entry, subCat, isCustom)
  9775. {
  9776. mxEvent.addListener(entry, 'click', function()
  9777. {
  9778. if (currentEntry != entry)
  9779. {
  9780. if (currentEntry != null)
  9781. {
  9782. currentEntry.style.fontWeight = 'normal';
  9783. currentEntry.style.textDecoration = 'none';
  9784. }
  9785. else
  9786. {
  9787. newDiagramCat.style.display = 'none';
  9788. diagramsList.style.minHeight = '100%';
  9789. }
  9790. currentEntry = entry;
  9791. currentEntry.style.fontWeight = 'bold';
  9792. currentEntry.style.textDecoration = 'underline';
  9793. tempDlgContent.scrollTop = 0;
  9794. if (callInitiated)
  9795. {
  9796. cancelPendingCall = true;
  9797. }
  9798. diagramsListTitle.innerHTML = label;
  9799. diagramsListBtns.style.display = 'none';
  9800. fillDiagramsList(isCustom ? customCats[cat] :
  9801. (subCat? subCategories[cat][subCat] :
  9802. categories[cat]), isCustom ?
  9803. false : true);
  9804. }
  9805. });
  9806. };
  9807. if (customCatCount > 0)
  9808. {
  9809. var titleCss = 'font-weight: bold;background: #f9f9f9;padding: 5px 0 5px 0;text-align: center;margin-top: 10px;';
  9810. var title = document.createElement('div');
  9811. title.style.cssText = titleCss;
  9812. mxUtils.write(title, mxResources.get('custom'));
  9813. list.appendChild(title);
  9814. for (var cat in customCats)
  9815. {
  9816. var entry = document.createElement('div');
  9817. var templateList = customCats[cat];
  9818. var lbls = getEntryTitle(cat, templateList);
  9819. entry.className = 'geTemplateCatLink';
  9820. entry.setAttribute('title', lbls.fullLbl);
  9821. entry.innerHTML = lbls.lbl;
  9822. list.appendChild(entry);
  9823. addEntryHandler(cat, lbls.lblOnly, entry, null, true);
  9824. }
  9825. title = document.createElement('div');
  9826. title.style.cssText = titleCss;
  9827. mxUtils.write(title, 'draw.io');
  9828. list.appendChild(title);
  9829. }
  9830. for (var cat in categories)
  9831. {
  9832. var subCats = subCategories[cat];
  9833. var entry = document.createElement(subCats? 'ul' : 'div');
  9834. var clickElem = entry;
  9835. var templateList = categories[cat];
  9836. var lbls = getEntryTitle(cat, templateList);
  9837. if (subCats != null)
  9838. {
  9839. var entryLi = document.createElement('li');
  9840. var entryDiv = document.createElement('div');
  9841. entryDiv.className = 'geTempTreeCaret geTemplateCatLink geTemplateDrawioCatLink';
  9842. entryDiv.style.padding = '0';
  9843. entryDiv.setAttribute('title', lbls.fullLbl);
  9844. entryDiv.innerHTML = lbls.lbl;
  9845. clickElem = entryDiv;
  9846. entryLi.appendChild(entryDiv);
  9847. //We support one level deep only
  9848. var subUl = document.createElement('ul');
  9849. subUl.className = 'geTempTreeNested';
  9850. subUl.style.visibility = 'hidden';
  9851. for (var subCat in subCats)
  9852. {
  9853. var subLi = document.createElement('li');
  9854. var subLbls = getEntryTitle(subCat, subCats[subCat]);
  9855. subLi.setAttribute('title', subLbls.fullLbl);
  9856. subLi.innerHTML = subLbls.lbl;
  9857. subLi.className = 'geTemplateCatLink';
  9858. subLi.style.padding = '0';
  9859. subLi.style.margin = '0';
  9860. addEntryHandler(cat, subLbls.lblOnly, subLi, subCat);
  9861. subUl.appendChild(subLi);
  9862. }
  9863. entryLi.appendChild(subUl);
  9864. entry.className = 'geTempTree';
  9865. entry.appendChild(entryLi);
  9866. (function(subUl2, entryDiv2)
  9867. {
  9868. mxEvent.addListener(entryDiv2, 'click', function()
  9869. {
  9870. var lis = subUl2.querySelectorAll('li');
  9871. for (var i = 0; i < lis.length; i++)
  9872. {
  9873. lis[i].style.margin = '';
  9874. }
  9875. subUl2.style.visibility = 'visible';
  9876. subUl2.classList.toggle('geTempTreeActive');
  9877. if (subUl2.classList.toggle('geTempTreeNested'))
  9878. {
  9879. //Must hide sub elements to allow click on elements above it
  9880. setTimeout(function()
  9881. {
  9882. for (var i = 0; i < lis.length; i++)
  9883. {
  9884. lis[i].style.margin = '0';
  9885. }
  9886. subUl2.style.visibility = 'hidden';
  9887. }, 250);
  9888. }
  9889. entryDiv2.classList.toggle('geTempTreeCaret-down');
  9890. });
  9891. })(subUl, entryDiv);
  9892. }
  9893. else
  9894. {
  9895. entry.className = 'geTemplateCatLink geTemplateDrawioCatLink';
  9896. entry.setAttribute('title', lbls.fullLbl);
  9897. entry.innerHTML = lbls.lbl;
  9898. }
  9899. list.appendChild(entry);
  9900. addEntryHandler(cat, lbls.lblOnly, clickElem);
  9901. }
  9902. };
  9903. var indexLoaded = false, indexLoaded2 = false;
  9904. var categories = {}, subCategories = {}, customCats = {};
  9905. var newDiagramCats = [];
  9906. var categoryCount = 1, customCatCount = 0;
  9907. function loadDrawioTemplates()
  9908. {
  9909. mxUtils.get(templateFile, function(req)
  9910. {
  9911. // Workaround for index loaded 3 times in iOS offline mode
  9912. if (!indexLoaded)
  9913. {
  9914. indexLoaded = true;
  9915. var tmpDoc = req.getXml();
  9916. var node = tmpDoc.documentElement.firstChild;
  9917. var clibs = {};
  9918. while (node != null)
  9919. {
  9920. if (typeof(node.getAttribute) !== 'undefined')
  9921. {
  9922. if (node.nodeName == 'clibs')
  9923. {
  9924. var name = node.getAttribute('name');
  9925. var adds = node.getElementsByTagName('add');
  9926. var temp = [];
  9927. for (var i = 0; i < adds.length; i++)
  9928. {
  9929. temp.push(encodeURIComponent(mxUtils.getTextContent(adds[i])));
  9930. }
  9931. if (name != null && temp.length > 0)
  9932. {
  9933. clibs[name] = temp.join(';');
  9934. }
  9935. }
  9936. else
  9937. {
  9938. var url = node.getAttribute('url');
  9939. if (url != null)
  9940. {
  9941. var category = node.getAttribute('section');
  9942. var subCategory = node.getAttribute('subsection');
  9943. if (category == null)
  9944. {
  9945. var slash = url.indexOf('/');
  9946. category = url.substring(0, slash);
  9947. if (subCategory == null)
  9948. {
  9949. var nextSlash = url.indexOf('/', slash + 1);
  9950. if (nextSlash > -1)
  9951. {
  9952. subCategory = url.substring(slash + 1, nextSlash);
  9953. }
  9954. }
  9955. }
  9956. var list = categories[category];
  9957. if (list == null)
  9958. {
  9959. categoryCount++;
  9960. list = [];
  9961. categories[category] = list;
  9962. }
  9963. var tempLibs = node.getAttribute('clibs');
  9964. if (clibs[tempLibs] != null)
  9965. {
  9966. tempLibs = clibs[tempLibs];
  9967. }
  9968. var tempObj = {url: node.getAttribute('url'), libs: node.getAttribute('libs'),
  9969. title: node.getAttribute('title') || node.getAttribute('name'),
  9970. preview: node.getAttribute('preview'), clibs: tempLibs, tags: node.getAttribute('tags')};
  9971. list.push(tempObj);
  9972. if (subCategory != null)
  9973. {
  9974. var subCats = subCategories[category];
  9975. if (subCats == null)
  9976. {
  9977. subCats = {};
  9978. subCategories[category] = subCats;
  9979. }
  9980. var subCatList = subCats[subCategory];
  9981. if (subCatList == null)
  9982. {
  9983. subCatList = [];
  9984. subCats[subCategory] = subCatList;
  9985. }
  9986. subCatList.push(tempObj);
  9987. }
  9988. }
  9989. }
  9990. }
  9991. node = node.nextSibling;
  9992. }
  9993. fillTemplatesList(categories, customCats, customCatCount);
  9994. }
  9995. });
  9996. };
  9997. if (customTempCallback != null)
  9998. {
  9999. customTempCallback(function(cats, count)
  10000. {
  10001. customCats = cats;
  10002. customCatCount = count;
  10003. loadDrawioTemplates();
  10004. }, loadDrawioTemplates); //In case of an error, just load draw.io templates only
  10005. }
  10006. else
  10007. {
  10008. loadDrawioTemplates();
  10009. }
  10010. mxUtils.get(newDiagramCatsFile, function(req)
  10011. {
  10012. // Workaround for index loaded 3 times in iOS offline mode
  10013. if (!indexLoaded2)
  10014. {
  10015. indexLoaded2 = true;
  10016. var tmpDoc = req.getXml();
  10017. var node = tmpDoc.documentElement.firstChild;
  10018. while (node != null)
  10019. {
  10020. if (typeof(node.getAttribute) !== 'undefined')
  10021. {
  10022. var title = node.getAttribute('title');
  10023. if (title != null)
  10024. {
  10025. newDiagramCats.push({img: node.getAttribute('img'), libs: node.getAttribute('libs'),
  10026. clibs: node.getAttribute('clibs'), title: node.getAttribute('title')});
  10027. }
  10028. }
  10029. node = node.nextSibling;
  10030. }
  10031. fillNewDiagramCats(newDiagramCats);
  10032. }
  10033. });
  10034. var extDiagramsCallback = function(list, errorMsg, searchImportCats)
  10035. {
  10036. diagramsListBtns.style.display = '';
  10037. spinner.stop();
  10038. callInitiated = false;
  10039. if (cancelPendingCall)
  10040. {
  10041. cancelPendingCall = false;
  10042. return;
  10043. }
  10044. if (errorMsg)
  10045. {
  10046. diagramsTiles.innerText = errorMsg;
  10047. }
  10048. else
  10049. {
  10050. searchImportCats = searchImportCats || {};
  10051. var importListsCount = 0;
  10052. for (var cat in searchImportCats)
  10053. {
  10054. importListsCount += searchImportCats[cat].length;
  10055. }
  10056. if (list.length == 0 && importListsCount == 0)
  10057. {
  10058. diagramsTiles.innerText = mxResources.get('noDiagrams');
  10059. }
  10060. else
  10061. {
  10062. fillDiagramsList(list, false, showAsList, importListsCount == 0? null : searchImportCats);
  10063. }
  10064. }
  10065. };
  10066. function getRecentDocs(getAll)
  10067. {
  10068. if (recentDocsCallback)
  10069. {
  10070. tempDlgContent.scrollTop = 0;
  10071. diagramsTiles.innerText = '';
  10072. spinner.spin(diagramsTiles);
  10073. cancelPendingCall = false;
  10074. callInitiated = true;
  10075. diagramsListTitle.innerText = mxResources.get('recentDiag');
  10076. lastSearchStr = null;
  10077. recentDocsCallback(extDiagramsCallback, function()
  10078. {
  10079. showError(mxResources.get('cannotLoad'));
  10080. extDiagramsCallback([]);
  10081. }, getAll? null : username);
  10082. }
  10083. };
  10084. getRecentDocs(isGetAll);
  10085. var delayTimer = null;
  10086. function resetTemplates()
  10087. {
  10088. if (lastEntry != null)
  10089. {
  10090. lastEntry.click();
  10091. lastEntry = null;
  10092. }
  10093. };
  10094. function filterTemplates(searchTerms)
  10095. {
  10096. if (searchTerms == '')
  10097. {
  10098. resetTemplates();
  10099. return;
  10100. }
  10101. if (TemplatesDialog.tagsList[templateFile] == null)
  10102. {
  10103. var tagsList = {};
  10104. for (var cat in categories)
  10105. {
  10106. var templateList = categories[cat];
  10107. for (var i = 0; i < templateList.length; i++)
  10108. {
  10109. var temp = templateList[i];
  10110. if (temp.tags != null)
  10111. {
  10112. var tags = temp.tags.toLowerCase().split(';');
  10113. for (var j = 0; j < tags.length; j++)
  10114. {
  10115. if (tagsList[tags[j]] == null)
  10116. {
  10117. tagsList[tags[j]] = [];
  10118. }
  10119. tagsList[tags[j]].push(temp);
  10120. }
  10121. }
  10122. }
  10123. }
  10124. TemplatesDialog.tagsList[templateFile] = tagsList;
  10125. }
  10126. var tmp = searchTerms.toLowerCase().split(' ');
  10127. tagsList = TemplatesDialog.tagsList[templateFile];
  10128. if (customCatCount > 0 && tagsList.__tagsList__ == null)
  10129. {
  10130. for (var cat in customCats)
  10131. {
  10132. var templateList = customCats[cat];
  10133. for (var i = 0; i < templateList.length; i++)
  10134. {
  10135. var temp = templateList[i];
  10136. var tags = temp.title.split(' ');
  10137. tags.push(cat);
  10138. for (var j = 0; j < tags.length; j++)
  10139. {
  10140. var tag = tags[j].toLowerCase();
  10141. if (tagsList[tag] == null)
  10142. {
  10143. tagsList[tag] = [];
  10144. }
  10145. tagsList[tag].push(temp);
  10146. }
  10147. }
  10148. }
  10149. tagsList.__tagsList__ = true;
  10150. }
  10151. var results = [], resMap = {}, index = 0;
  10152. for (var i = 0; i < tmp.length; i++)
  10153. {
  10154. if (tmp[i].length > 0)
  10155. {
  10156. var list = tagsList[tmp[i]];
  10157. var tmpResMap = {};
  10158. results = [];
  10159. if (list != null)
  10160. {
  10161. for (var j = 0; j < list.length; j++)
  10162. {
  10163. var temp = list[j];
  10164. //ANDing terms
  10165. if ((index == 0) == (resMap[temp.url] == null))
  10166. {
  10167. tmpResMap[temp.url] = true;
  10168. results.push(temp);
  10169. }
  10170. }
  10171. }
  10172. resMap = tmpResMap;
  10173. index++;
  10174. }
  10175. }
  10176. if (results.length == 0)
  10177. {
  10178. diagramsListTitle.innerText = mxResources.get('noResultsFor', [searchTerms]);
  10179. }
  10180. else
  10181. {
  10182. fillDiagramsList(results, true);
  10183. }
  10184. };
  10185. function doSearch(searchStr)
  10186. {
  10187. if (lastSearchStr == searchStr && isGetAll == lastGetAll) return;
  10188. deselectTempCat();
  10189. tempDlgContent.scrollTop = 0;
  10190. diagramsTiles.innerText = '';
  10191. diagramsListTitle.innerText = mxResources.get('searchResults') +
  10192. ' "' + searchStr + '"';
  10193. delayTimer = null;
  10194. if (inTempScreen)
  10195. {
  10196. //Do search in templates
  10197. filterTemplates(searchStr);
  10198. }
  10199. else if (searchDocsCallback)
  10200. {
  10201. if (searchStr)
  10202. {
  10203. spinner.spin(diagramsTiles);
  10204. cancelPendingCall = false;
  10205. callInitiated = true;
  10206. //TODO use request id to allow only last request to show results
  10207. searchDocsCallback(searchStr, extDiagramsCallback, function()
  10208. {
  10209. showError(mxResources.get('searchFailed'));
  10210. extDiagramsCallback([]);
  10211. }, isGetAll? null : username);
  10212. }
  10213. else
  10214. {
  10215. getRecentDocs(isGetAll); //Load recent doc again
  10216. }
  10217. }
  10218. lastSearchStr = searchStr;
  10219. lastGetAll = isGetAll;
  10220. };
  10221. function searchEvent(evt)
  10222. {
  10223. if (delayTimer != null)
  10224. {
  10225. clearTimeout(delayTimer);
  10226. }
  10227. if (evt.keyCode == 13)
  10228. {
  10229. doSearch(searchInout.value);
  10230. }
  10231. else
  10232. {
  10233. delayTimer = setTimeout(function()
  10234. {
  10235. doSearch(searchInout.value);
  10236. }, 1000);
  10237. }
  10238. };
  10239. //Use keyup to detect delete and backspace
  10240. mxEvent.addListener(searchInout, 'keyup', searchEvent);
  10241. //To detect copy/paste and clear
  10242. mxEvent.addListener(searchInout, 'search', searchEvent);
  10243. mxEvent.addListener(searchInout, 'input', searchEvent);
  10244. mxEvent.addListener(createBtn, 'click', function(evt)
  10245. {
  10246. handleDialogOK(false, false);
  10247. });
  10248. if (withOpen)
  10249. {
  10250. mxEvent.addListener(openBtn, 'click', function(evt)
  10251. {
  10252. handleDialogOK(false, true);
  10253. });
  10254. }
  10255. if (withLink)
  10256. {
  10257. mxEvent.addListener(dlgDiv.querySelector(".geTempDlgLinkToDiagramBtn"), 'click', function(evt)
  10258. {
  10259. handleDialogOK(true);
  10260. });
  10261. }
  10262. mxEvent.addListener(dlgDiv.querySelector('.geTempDlgCancelBtn'), 'click', function()
  10263. {
  10264. if (cancelCallback != null)
  10265. {
  10266. cancelCallback();
  10267. }
  10268. if (!noDlgHide)
  10269. {
  10270. editorUi.hideDialog(true);
  10271. }
  10272. });
  10273. };
  10274. TemplatesDialog.tagsList = {};
  10275. /**
  10276. * Constructs a new popup opener button dialog.
  10277. */
  10278. var BtnDialog = function(editorUi, peer, btnLbl, fn)
  10279. {
  10280. var div = document.createElement('div');
  10281. div.style.textAlign = 'center';
  10282. var hd = document.createElement('p');
  10283. hd.style.fontSize = '16pt';
  10284. hd.style.padding = '0px';
  10285. hd.style.margin = '0px';
  10286. hd.style.color = 'gray';
  10287. mxUtils.write(hd, mxResources.get('done'));
  10288. var service = 'Unknown';
  10289. var img = document.createElement('img');
  10290. img.setAttribute('border', '0');
  10291. img.setAttribute('align', 'absmiddle');
  10292. img.style.marginRight = '10px';
  10293. if (peer == editorUi.drive)
  10294. {
  10295. service = mxResources.get('googleDrive');
  10296. img.src = IMAGE_PATH + '/google-drive-logo-white.svg';
  10297. }
  10298. else if (peer == editorUi.dropbox)
  10299. {
  10300. service = mxResources.get('dropbox');
  10301. img.src = IMAGE_PATH + '/dropbox-logo-white.svg';
  10302. }
  10303. else if (peer == editorUi.oneDrive)
  10304. {
  10305. service = mxResources.get('oneDrive');
  10306. img.src = IMAGE_PATH + '/onedrive-logo-white.svg';
  10307. }
  10308. else if (peer == editorUi.gitHub)
  10309. {
  10310. service = mxResources.get('github');
  10311. img.src = IMAGE_PATH + '/github-logo-white.svg';
  10312. }
  10313. else if (peer == editorUi.gitLab)
  10314. {
  10315. service = mxResources.get('gitlab');
  10316. img.src = IMAGE_PATH + '/gitlab-logo.svg';
  10317. }
  10318. else if (peer == editorUi.trello)
  10319. {
  10320. service = mxResources.get('trello');
  10321. img.src = IMAGE_PATH + '/trello-logo-white.svg';
  10322. }
  10323. var p = document.createElement('p');
  10324. mxUtils.write(p, mxResources.get('authorizedIn', [service], 'You are now authorized in {1}'));
  10325. var button = mxUtils.button(btnLbl, fn);
  10326. button.insertBefore(img, button.firstChild);
  10327. button.style.marginTop = '6px';
  10328. button.className = 'geBigButton';
  10329. button.style.fontSize = '18px';
  10330. button.style.padding = '14px';
  10331. div.appendChild(hd);
  10332. div.appendChild(p);
  10333. div.appendChild(button);
  10334. this.container = div;
  10335. };
  10336. /**
  10337. * Constructs a new font dialog.
  10338. */
  10339. var FontDialog = function(editorUi, curFontname, curUrl, curType, fn)
  10340. {
  10341. var row, td, label;
  10342. var table = document.createElement('table');
  10343. var tbody = document.createElement('tbody');
  10344. table.style.marginTop = '8px';
  10345. //System fonts section
  10346. row = document.createElement('tr');
  10347. td = document.createElement('td');
  10348. td.colSpan = 2;
  10349. td.style.whiteSpace = 'nowrap';
  10350. td.style.fontSize = '10pt';
  10351. td.style.fontWeight = 'bold';
  10352. var sysFontRadio = document.createElement('input');
  10353. sysFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  10354. sysFontRadio.setAttribute('value', 'sysfonts');
  10355. sysFontRadio.setAttribute('type', 'radio');
  10356. sysFontRadio.setAttribute('name', 'current-fontdialog');
  10357. sysFontRadio.setAttribute('id', 'fontdialog-sysfonts');
  10358. td.appendChild(sysFontRadio);
  10359. label = document.createElement('label');
  10360. label.setAttribute('for', 'fontdialog-sysfonts');
  10361. mxUtils.write(label, (mxResources.get('sysFonts', null, 'System Fonts')));
  10362. td.appendChild(label);
  10363. row.appendChild(td);
  10364. tbody.appendChild(row);
  10365. row = document.createElement('tr');
  10366. td = document.createElement('td');
  10367. td.style.whiteSpace = 'nowrap';
  10368. td.style.fontSize = '10pt';
  10369. td.style.width = '120px';
  10370. td.style.paddingLeft = '15px';
  10371. mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':');
  10372. row.appendChild(td);
  10373. var sysFontInput = document.createElement('input');
  10374. if (curType == 's')
  10375. {
  10376. sysFontInput.setAttribute('value', curFontname);
  10377. }
  10378. sysFontInput.style.marginLeft = '4px';
  10379. sysFontInput.style.width = '250px';
  10380. sysFontInput.className = 'dlg_fontName_s';
  10381. td = document.createElement('td');
  10382. td.appendChild(sysFontInput);
  10383. row.appendChild(td);
  10384. tbody.appendChild(row);
  10385. //Google fonts section
  10386. row = document.createElement('tr');
  10387. td = document.createElement('td');
  10388. td.colSpan = 2;
  10389. td.style.whiteSpace = 'nowrap';
  10390. td.style.fontSize = '10pt';
  10391. td.style.fontWeight = 'bold';
  10392. var googleFontRadio = document.createElement('input');
  10393. googleFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  10394. googleFontRadio.setAttribute('value', 'googlefonts');
  10395. googleFontRadio.setAttribute('type', 'radio');
  10396. googleFontRadio.setAttribute('name', 'current-fontdialog');
  10397. googleFontRadio.setAttribute('id', 'fontdialog-googlefonts');
  10398. td.appendChild(googleFontRadio);
  10399. label = document.createElement('label');
  10400. label.setAttribute('for', 'fontdialog-googlefonts');
  10401. mxUtils.write(label, (mxResources.get('googleFonts', null, 'Google Fonts')));
  10402. td.appendChild(label);
  10403. // Link to Google Fonts
  10404. if (!mxClient.IS_CHROMEAPP && (!editorUi.isOffline() || EditorUi.isElectronApp))
  10405. {
  10406. var link = editorUi.menus.createHelpLink('https://fonts.google.com/');
  10407. link.getElementsByTagName('img')[0].setAttribute('valign', 'middle');
  10408. td.appendChild(link);
  10409. }
  10410. row.appendChild(td);
  10411. tbody.appendChild(row);
  10412. row = document.createElement('tr');
  10413. td = document.createElement('td');
  10414. td.style.whiteSpace = 'nowrap';
  10415. td.style.fontSize = '10pt';
  10416. td.style.width = '120px';
  10417. td.style.paddingLeft = '15px';
  10418. mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':');
  10419. row.appendChild(td);
  10420. var googleFontInput = document.createElement('input');
  10421. if (curType == 'g')
  10422. {
  10423. googleFontInput.setAttribute('value', curFontname);
  10424. }
  10425. googleFontInput.style.marginLeft = '4px';
  10426. googleFontInput.style.width = '250px';
  10427. googleFontInput.className = 'dlg_fontName_g';
  10428. td = document.createElement('td');
  10429. td.appendChild(googleFontInput);
  10430. row.appendChild(td);
  10431. tbody.appendChild(row);
  10432. //Generic remote fonts section
  10433. row = document.createElement('tr');
  10434. td = document.createElement('td');
  10435. td.colSpan = 2;
  10436. td.style.whiteSpace = 'nowrap';
  10437. td.style.fontSize = '10pt';
  10438. td.style.fontWeight = 'bold';
  10439. var webFontRadio = document.createElement('input');
  10440. webFontRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;';
  10441. webFontRadio.setAttribute('value', 'webfonts');
  10442. webFontRadio.setAttribute('type', 'radio');
  10443. webFontRadio.setAttribute('name', 'current-fontdialog');
  10444. webFontRadio.setAttribute('id', 'fontdialog-webfonts');
  10445. td.appendChild(webFontRadio);
  10446. label = document.createElement('label');
  10447. label.setAttribute('for', 'fontdialog-webfonts');
  10448. mxUtils.write(label, (mxResources.get('webfonts', null, 'Web Fonts')));
  10449. td.appendChild(label);
  10450. row.appendChild(td);
  10451. if (Editor.enableWebFonts)
  10452. {
  10453. tbody.appendChild(row);
  10454. }
  10455. row = document.createElement('tr');
  10456. td = document.createElement('td');
  10457. td.style.whiteSpace = 'nowrap';
  10458. td.style.fontSize = '10pt';
  10459. td.style.width = '120px';
  10460. td.style.paddingLeft = '15px';
  10461. mxUtils.write(td, (mxResources.get('fontname', null, 'Font Name')) + ':');
  10462. row.appendChild(td);
  10463. var webFontInput = document.createElement('input');
  10464. if (curType == 'w')
  10465. {
  10466. if (Editor.enableWebFonts)
  10467. {
  10468. webFontInput.setAttribute('value', curFontname);
  10469. }
  10470. else
  10471. {
  10472. sysFontInput.setAttribute('value', curFontname);
  10473. }
  10474. }
  10475. webFontInput.style.marginLeft = '4px';
  10476. webFontInput.style.width = '250px';
  10477. webFontInput.className = 'dlg_fontName_w';
  10478. td = document.createElement('td');
  10479. td.appendChild(webFontInput);
  10480. row.appendChild(td);
  10481. if (Editor.enableWebFonts)
  10482. {
  10483. tbody.appendChild(row);
  10484. }
  10485. row = document.createElement('tr');
  10486. td = document.createElement('td');
  10487. td.style.whiteSpace = 'nowrap';
  10488. td.style.fontSize = '10pt';
  10489. td.style.width = '120px';
  10490. td.style.paddingLeft = '15px';
  10491. mxUtils.write(td, (mxResources.get('fontUrl', null, 'Font URL')) + ':');
  10492. row.appendChild(td);
  10493. var webFontUrlInput = document.createElement('input');
  10494. webFontUrlInput.setAttribute('value', curUrl || '');
  10495. webFontUrlInput.style.marginLeft = '4px';
  10496. webFontUrlInput.style.width = '250px';
  10497. webFontUrlInput.className = 'dlg_fontUrl';
  10498. td = document.createElement('td');
  10499. td.appendChild(webFontUrlInput);
  10500. row.appendChild(td);
  10501. if (Editor.enableWebFonts)
  10502. {
  10503. tbody.appendChild(row);
  10504. }
  10505. this.init = function()
  10506. {
  10507. var input = sysFontInput;
  10508. if (curType == 'g')
  10509. {
  10510. input = googleFontInput;
  10511. }
  10512. else if (curType == 'w' && Editor.enableWebFonts)
  10513. {
  10514. input = webFontInput;
  10515. }
  10516. input.focus();
  10517. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  10518. {
  10519. input.select();
  10520. }
  10521. else
  10522. {
  10523. document.execCommand('selectAll', false, null);
  10524. }
  10525. };
  10526. row = document.createElement('tr');
  10527. td = document.createElement('td');
  10528. td.colSpan = 2;
  10529. td.style.paddingTop = '20px';
  10530. td.style.whiteSpace = 'nowrap';
  10531. td.setAttribute('align', 'right');
  10532. if (!editorUi.isOffline())
  10533. {
  10534. var helpBtn = mxUtils.button(mxResources.get('help'), function()
  10535. {
  10536. editorUi.openLink('https://www.diagrams.net/blog/external-fonts');
  10537. });
  10538. helpBtn.className = 'geBtn';
  10539. td.appendChild(helpBtn);
  10540. }
  10541. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  10542. {
  10543. editorUi.hideDialog();
  10544. fn();
  10545. });
  10546. cancelBtn.className = 'geBtn';
  10547. if (editorUi.editor.cancelFirst)
  10548. {
  10549. td.appendChild(cancelBtn);
  10550. }
  10551. function validateFn(fontName, fontUrl, type)
  10552. {
  10553. var urlPattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
  10554. if (fontName == null || fontName.length == 0)
  10555. {
  10556. table.querySelector('.dlg_fontName_' + type).style.border = '1px solid red';
  10557. return false;
  10558. }
  10559. if (type == 'w' && !urlPattern.test(fontUrl))
  10560. {
  10561. table.querySelector('.dlg_fontUrl').style.border = '1px solid red';
  10562. return false;
  10563. }
  10564. return true;
  10565. };
  10566. var okBtn = mxUtils.button(mxResources.get('apply'), function()
  10567. {
  10568. var fontName, fontUrl, type;
  10569. if (sysFontRadio.checked)
  10570. {
  10571. fontName = sysFontInput.value;
  10572. type = 's';
  10573. }
  10574. else if (googleFontRadio.checked)
  10575. {
  10576. fontName = googleFontInput.value;
  10577. fontUrl = Editor.GOOGLE_FONTS + encodeURIComponent(fontName).replace(/%20/g, '+');
  10578. type = 'g';
  10579. }
  10580. else if (webFontRadio.checked)
  10581. {
  10582. fontName = webFontInput.value;
  10583. fontUrl = webFontUrlInput.value;
  10584. type = 'w';
  10585. }
  10586. if (validateFn(fontName, fontUrl, type))
  10587. {
  10588. fn(fontName, fontUrl, type);
  10589. editorUi.hideDialog();
  10590. }
  10591. });
  10592. okBtn.className = 'geBtn gePrimaryBtn';
  10593. function enterSubmit(e)
  10594. {
  10595. this.style.border = '';
  10596. if (e.keyCode == 13)
  10597. {
  10598. okBtn.click();
  10599. }
  10600. };
  10601. mxEvent.addListener(sysFontInput, 'keypress', enterSubmit);
  10602. mxEvent.addListener(googleFontInput, 'keypress', enterSubmit);
  10603. mxEvent.addListener(webFontInput, 'keypress', enterSubmit);
  10604. mxEvent.addListener(webFontUrlInput, 'keypress', enterSubmit);
  10605. mxEvent.addListener(sysFontInput, 'focus', function()
  10606. {
  10607. sysFontRadio.setAttribute('checked', 'checked');
  10608. sysFontRadio.checked = true;
  10609. });
  10610. mxEvent.addListener(googleFontInput, 'focus', function()
  10611. {
  10612. googleFontRadio.setAttribute('checked', 'checked');
  10613. googleFontRadio.checked = true;
  10614. });
  10615. mxEvent.addListener(webFontInput, 'focus', function()
  10616. {
  10617. webFontRadio.setAttribute('checked', 'checked');
  10618. webFontRadio.checked = true;
  10619. });
  10620. mxEvent.addListener(webFontUrlInput, 'focus', function()
  10621. {
  10622. webFontRadio.setAttribute('checked', 'checked');
  10623. webFontRadio.checked = true;
  10624. });
  10625. td.appendChild(okBtn);
  10626. if (!editorUi.editor.cancelFirst)
  10627. {
  10628. td.appendChild(cancelBtn);
  10629. }
  10630. row.appendChild(td);
  10631. tbody.appendChild(row);
  10632. table.appendChild(tbody);
  10633. this.container = table;
  10634. };
  10635. /* Aspect Dialog
  10636. * @module drawio/aspect-dialog
  10637. */
  10638. function AspectDialog(editorUi, pageId, layerIds, okFn, cancelFn)
  10639. {
  10640. this.aspect = {pageId : pageId || (editorUi.pages? editorUi.pages[0].getId() : null), layerIds : layerIds || []};
  10641. var div = document.createElement('div');
  10642. var title = document.createElement('h5');
  10643. title.style.margin = '0 0 10px';
  10644. mxUtils.write(title, mxResources.get('pages'));
  10645. div.appendChild(title);
  10646. var pagesContainer = document.createElement('div');
  10647. pagesContainer.className = 'geAspectDlgList';
  10648. div.appendChild(pagesContainer);
  10649. title = document.createElement('h5');
  10650. title.style.margin = '0 0 10px';
  10651. mxUtils.write(title, mxResources.get('layers'));
  10652. div.appendChild(title);
  10653. var layersContainer = document.createElement('div');
  10654. layersContainer.className = 'geAspectDlgList';
  10655. div.appendChild(layersContainer);
  10656. this.pagesContainer = pagesContainer;
  10657. this.layersContainer = layersContainer;
  10658. this.ui = editorUi;
  10659. var btns = document.createElement('div');
  10660. btns.style.marginTop = '16px';
  10661. btns.style.textAlign = 'center';
  10662. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  10663. {
  10664. editorUi.hideDialog();
  10665. if (cancelFn != null)
  10666. {
  10667. cancelFn();
  10668. }
  10669. });
  10670. cancelBtn.className = 'geBtn';
  10671. if (editorUi.editor.cancelFirst)
  10672. {
  10673. btns.appendChild(cancelBtn);
  10674. }
  10675. var okBtn = mxUtils.button(mxResources.get('ok'), mxUtils.bind(this, function()
  10676. {
  10677. editorUi.hideDialog();
  10678. okFn({pageId: this.selectedPage, layerIds: Object.keys(this.selectedLayers)});
  10679. }));
  10680. btns.appendChild(okBtn);
  10681. okBtn.className = 'geBtn gePrimaryBtn';
  10682. if (!editorUi.editor.cancelFirst)
  10683. {
  10684. btns.appendChild(cancelBtn);
  10685. }
  10686. okBtn.setAttribute('disabled', 'disabled');
  10687. this.okBtn = okBtn;
  10688. div.appendChild(btns);
  10689. this.container = div;
  10690. };
  10691. //Drawing the graph with dialog not visible doesn't get dimensions right. It has to be visible!
  10692. AspectDialog.prototype.init = function()
  10693. {
  10694. var xml = this.ui.getFileData(true); //Force pages to update their nodes
  10695. if (this.ui.pages)
  10696. {
  10697. for (var i = 0; i < this.ui.pages.length; i++)
  10698. {
  10699. var page = this.ui.updatePageRoot(this.ui.pages[i]);
  10700. this.createPageItem(page.getId(), page.getName(), page.node);
  10701. }
  10702. }
  10703. else
  10704. {
  10705. this.createPageItem('1', 'Page-1', mxUtils.parseXml(xml).documentElement);
  10706. }
  10707. };
  10708. AspectDialog.prototype.createViewer = function(container, pageNode, layerId, defaultBackground)
  10709. {
  10710. mxEvent.disableContextMenu(container);
  10711. container.style.userSelect = 'none';
  10712. var graph = new Graph(container);
  10713. graph.setTooltips(false);
  10714. graph.setEnabled(false);
  10715. graph.setPanning(false);
  10716. graph.minFitScale = null;
  10717. graph.maxFitScale = null;
  10718. graph.centerZoom = true;
  10719. var node = pageNode.nodeName == 'mxGraphModel'? pageNode : Editor.parseDiagramNode(pageNode); //Handles compressed and non-compressed page node
  10720. if (node != null)
  10721. {
  10722. var bg = node.getAttribute('background');
  10723. if (bg == null || bg == '' || bg == mxConstants.NONE)
  10724. {
  10725. bg = (defaultBackground != null) ? defaultBackground : '#ffffff';
  10726. }
  10727. container.style.backgroundColor = bg;
  10728. var codec = new mxCodec(node.ownerDocument);
  10729. var model = graph.getModel();
  10730. codec.decode(node, model);
  10731. var childCount = model.getChildCount(model.root);
  10732. var showAll = layerId == null;
  10733. // handle layers visibility
  10734. for (var i = 0; i < childCount; i++)
  10735. {
  10736. var child = model.getChildAt(model.root, i);
  10737. model.setVisible(child, showAll || layerId == child.id);
  10738. }
  10739. graph.maxFitScale = 1;
  10740. graph.fit(0);
  10741. graph.center();
  10742. }
  10743. return graph;
  10744. };
  10745. AspectDialog.prototype.createPageItem = function(pageId, pageName, pageNode)
  10746. {
  10747. var $listItem = document.createElement('div');
  10748. $listItem.className = 'geAspectDlgListItem';
  10749. $listItem.setAttribute('data-page-id', pageId)
  10750. $listItem.innerHTML = '<div style="max-width: 100%; max-height: 100%;"></div><div class="geAspectDlgListItemText">' + mxUtils.htmlEntities(pageName) + '</div>';
  10751. this.pagesContainer.appendChild($listItem);
  10752. var graph = this.createViewer($listItem.childNodes[0], pageNode);
  10753. var onClick = mxUtils.bind(this, function()
  10754. {
  10755. if (this.selectedItem != null)
  10756. {
  10757. this.selectedItem.className = 'geAspectDlgListItem';
  10758. }
  10759. this.selectedItem = $listItem;
  10760. this.selectedPage = pageId;
  10761. $listItem.className += ' geAspectDlgListItemSelected';
  10762. this.layersContainer.innerText = '';
  10763. this.selectedLayers = {};
  10764. this.okBtn.setAttribute('disabled', 'disabled');
  10765. var graphModel = graph.model;
  10766. var layers = graphModel.getChildCells(graphModel.getRoot());
  10767. for (var i = 0; i < layers.length; i++)
  10768. {
  10769. this.createLayerItem(layers[i], pageId, graph, pageNode);
  10770. }
  10771. });
  10772. mxEvent.addListener($listItem, 'click', onClick);
  10773. if(this.aspect.pageId == pageId)
  10774. {
  10775. onClick();
  10776. }
  10777. };
  10778. AspectDialog.prototype.createLayerItem = function(layer, pageId, graph, pageNode)
  10779. {
  10780. var layerName = graph.convertValueToString(layer) || (mxResources.get('background') || 'Background');
  10781. var $listItem = document.createElement('div');
  10782. $listItem.setAttribute('data-layer-id', layer.id);
  10783. $listItem.className = 'geAspectDlgListItem';
  10784. $listItem.innerHTML = '<div style="max-width: 100%; max-height: 100%;"></div><div class="geAspectDlgListItemText">' + mxUtils.htmlEntities(layerName) + '</div>';
  10785. this.layersContainer.appendChild($listItem);
  10786. this.createViewer($listItem.childNodes[0], pageNode, layer.id);
  10787. var onClick = mxUtils.bind(this, function()
  10788. {
  10789. if ($listItem.className.indexOf('geAspectDlgListItemSelected') >= 0) //Selected
  10790. {
  10791. $listItem.className = 'geAspectDlgListItem';
  10792. delete this.selectedLayers[layer.id];
  10793. if (mxUtils.isEmptyObject(this.selectedLayers))
  10794. {
  10795. this.okBtn.setAttribute('disabled', 'disabled');
  10796. }
  10797. }
  10798. else
  10799. {
  10800. $listItem.className += ' geAspectDlgListItemSelected';
  10801. this.selectedLayers[layer.id] = true;
  10802. this.okBtn.removeAttribute('disabled');
  10803. }
  10804. });
  10805. mxEvent.addListener($listItem, 'click', onClick);
  10806. if(this.aspect.layerIds.indexOf(layer.id) != -1)
  10807. {
  10808. onClick();
  10809. }
  10810. };
  10811. /**
  10812. * Constructs a new page setup dialog.
  10813. */
  10814. var FilePropertiesDialog = function(editorUi)
  10815. {
  10816. var row, td;
  10817. var table = document.createElement('table');
  10818. var tbody = document.createElement('tbody');
  10819. table.style.width = '100%';
  10820. table.style.marginTop = '8px';
  10821. var file = editorUi.getCurrentFile();
  10822. var filename = (file != null && file.getTitle() != null) ?
  10823. file.getTitle() : editorUi.defaultFilename;
  10824. var isPng = /(\.png)$/i.test(filename);
  10825. var apply = function() { };
  10826. if (isPng)
  10827. {
  10828. var scale = 1;
  10829. var border = 0;
  10830. var node = editorUi.fileNode;
  10831. if (node != null)
  10832. {
  10833. if (node.hasAttribute('scale'))
  10834. {
  10835. scale = parseFloat(node.getAttribute('scale'));
  10836. }
  10837. if (node.hasAttribute('border'))
  10838. {
  10839. border = parseInt(node.getAttribute('border'));
  10840. }
  10841. }
  10842. row = document.createElement('tr');
  10843. td = document.createElement('td');
  10844. td.style.whiteSpace = 'nowrap';
  10845. td.style.fontSize = '10pt';
  10846. td.style.width = '120px';
  10847. mxUtils.write(td, mxResources.get('zoom') + ':');
  10848. row.appendChild(td);
  10849. var zoomInput = document.createElement('input');
  10850. zoomInput.setAttribute('value', (scale * 100) + '%');
  10851. zoomInput.style.marginLeft = '4px';
  10852. zoomInput.style.width ='180px';
  10853. td = document.createElement('td');
  10854. td.style.whiteSpace = 'nowrap';
  10855. td.appendChild(zoomInput);
  10856. row.appendChild(td);
  10857. tbody.appendChild(row);
  10858. row = document.createElement('tr');
  10859. td = document.createElement('td');
  10860. td.style.whiteSpace = 'nowrap';
  10861. td.style.fontSize = '10pt';
  10862. td.style.width = '120px';
  10863. mxUtils.write(td, mxResources.get('borderWidth') + ':');
  10864. row.appendChild(td);
  10865. var borderInput = document.createElement('input');
  10866. borderInput.setAttribute('value', border);
  10867. borderInput.style.marginLeft = '4px';
  10868. borderInput.style.width ='180px';
  10869. td = document.createElement('td');
  10870. td.style.whiteSpace = 'nowrap';
  10871. td.appendChild(borderInput);
  10872. row.appendChild(td);
  10873. tbody.appendChild(row);
  10874. this.init = function()
  10875. {
  10876. zoomInput.focus();
  10877. if (mxClient.IS_GC || mxClient.IS_FF || document.documentMode >= 5)
  10878. {
  10879. zoomInput.select();
  10880. }
  10881. else
  10882. {
  10883. document.execCommand('selectAll', false, null);
  10884. }
  10885. };
  10886. apply = function()
  10887. {
  10888. if (editorUi.fileNode != null)
  10889. {
  10890. editorUi.fileNode.setAttribute('scale', Math.max(0, parseInt(zoomInput.value) / 100));
  10891. editorUi.fileNode.setAttribute('border', Math.max(0, parseInt(borderInput.value)));
  10892. if (file != null)
  10893. {
  10894. file.fileChanged();
  10895. }
  10896. }
  10897. editorUi.hideDialog();
  10898. };
  10899. }
  10900. else if (!/(\.html)$/i.test(filename) &&
  10901. !/(\.svg)$/i.test(filename))
  10902. {
  10903. var initialCompressed = (file != null) ? file.isCompressed() : Editor.compressXml;
  10904. row = document.createElement('tr');
  10905. td = document.createElement('td');
  10906. td.style.whiteSpace = 'nowrap';
  10907. td.style.fontSize = '10pt';
  10908. td.style.width = '120px';
  10909. mxUtils.write(td, mxResources.get('compressed') + ':');
  10910. row.appendChild(td);
  10911. var compressedInput = document.createElement('input');
  10912. compressedInput.setAttribute('type', 'checkbox');
  10913. if (initialCompressed)
  10914. {
  10915. compressedInput.setAttribute('checked', 'checked');
  10916. compressedInput.defaultChecked = true;
  10917. }
  10918. td = document.createElement('td');
  10919. td.style.whiteSpace = 'nowrap';
  10920. td.appendChild(compressedInput);
  10921. row.appendChild(td);
  10922. tbody.appendChild(row);
  10923. this.init = function()
  10924. {
  10925. compressedInput.focus();
  10926. };
  10927. apply = function()
  10928. {
  10929. if (editorUi.fileNode != null && initialCompressed != compressedInput.checked)
  10930. {
  10931. editorUi.fileNode.setAttribute('compressed',
  10932. (compressedInput.checked) ? 'true' : 'false');
  10933. if (file != null)
  10934. {
  10935. file.fileChanged();
  10936. }
  10937. }
  10938. editorUi.hideDialog();
  10939. };
  10940. }
  10941. if (file != null && file.isRealtimeOptional())
  10942. {
  10943. row = document.createElement('tr');
  10944. td = document.createElement('td');
  10945. td.style.whiteSpace = 'nowrap';
  10946. td.style.fontSize = '10pt';
  10947. td.style.width = '120px';
  10948. mxUtils.write(td, mxResources.get('realtimeCollaboration') + ':');
  10949. row.appendChild(td);
  10950. var collabInput = document.createElement('input');
  10951. collabInput.setAttribute('type', 'checkbox');
  10952. var initialCollab = file.isRealtimeEnabled();
  10953. var collab = editorUi.drive.getCustomProperty(file.desc, 'collaboration');
  10954. var initialCollab = collab != 'disabled';
  10955. if (initialCollab)
  10956. {
  10957. collabInput.setAttribute('checked', 'checked');
  10958. collabInput.defaultChecked = true;
  10959. }
  10960. prevApply = apply;
  10961. apply = function()
  10962. {
  10963. prevApply();
  10964. editorUi.hideDialog();
  10965. if (collabInput.checked != initialCollab)
  10966. {
  10967. if (editorUi.spinner.spin(document.body, mxResources.get('updatingDocument')))
  10968. {
  10969. file.setRealtimeEnabled(collabInput.checked, mxUtils.bind(this, function(resp)
  10970. {
  10971. editorUi.spinner.stop();
  10972. }), mxUtils.bind(this, function(resp)
  10973. {
  10974. editorUi.spinner.stop();
  10975. editorUi.showError(mxResources.get('error'), (resp != null && resp.error != null) ?
  10976. resp.error.message : mxResources.get('unknownError'), mxResources.get('ok'));
  10977. }));
  10978. }
  10979. }
  10980. };
  10981. this.init = (this.init != null) ? this.init : function()
  10982. {
  10983. collabInput.focus();
  10984. };
  10985. td = document.createElement('td');
  10986. td.style.whiteSpace = 'nowrap';
  10987. td.appendChild(collabInput);
  10988. td.appendChild(editorUi.menus.createHelpLink('https://github.com/jgraph/drawio/discussions/2672'));
  10989. row.appendChild(td);
  10990. tbody.appendChild(row);
  10991. }
  10992. this.init = (this.init != null) ? this.init : function() { };
  10993. var genericBtn = mxUtils.button(mxResources.get('apply'), apply);
  10994. genericBtn.className = 'geBtn gePrimaryBtn';
  10995. row = document.createElement('tr');
  10996. td = document.createElement('td');
  10997. td.colSpan = 2;
  10998. td.style.paddingTop = '20px';
  10999. td.style.whiteSpace = 'nowrap';
  11000. td.setAttribute('align', 'center');
  11001. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  11002. {
  11003. editorUi.hideDialog();
  11004. });
  11005. cancelBtn.className = 'geBtn';
  11006. if (editorUi.editor.cancelFirst)
  11007. {
  11008. td.appendChild(cancelBtn);
  11009. }
  11010. td.appendChild(genericBtn);
  11011. if (!editorUi.editor.cancelFirst)
  11012. {
  11013. td.appendChild(cancelBtn);
  11014. }
  11015. row.appendChild(td);
  11016. tbody.appendChild(row);
  11017. table.appendChild(tbody);
  11018. this.container = table;
  11019. };
  11020. var ConnectionPointsDialog = function(editorUi, cell)
  11021. {
  11022. var GRAPH_SIZE = 350, CP_SIZE = 6, CP_HLF_SIZE = 3;
  11023. var div = document.createElement('div');
  11024. div.style.userSelect = 'none';
  11025. var keyHandler = null;
  11026. this.init = function()
  11027. {
  11028. var graphDiv = document.createElement('div');
  11029. graphDiv.style.width = GRAPH_SIZE + 'px';
  11030. graphDiv.style.height = GRAPH_SIZE + 'px';
  11031. graphDiv.style.overflow = 'hidden';
  11032. graphDiv.style.border = '1px solid lightGray';
  11033. graphDiv.style.boxSizing = 'border-box';
  11034. mxEvent.disableContextMenu(graphDiv);
  11035. div.appendChild(graphDiv);
  11036. var editingGraph = new Graph(graphDiv);
  11037. editingGraph.autoExtend = false;
  11038. editingGraph.autoScroll = false;
  11039. editingGraph.setGridEnabled(false);
  11040. editingGraph.setEnabled(true);
  11041. editingGraph.setPanning(true);
  11042. editingGraph.setConnectable(false);
  11043. editingGraph.setTooltips(false);
  11044. editingGraph.minFitScale = null;
  11045. editingGraph.maxFitScale = null;
  11046. editingGraph.centerZoom = true;
  11047. editingGraph.maxFitScale = 2;
  11048. function createCPoint(x, y)
  11049. {
  11050. var cPointStyle = 'shape=mxgraph.basic.x;fillColor=#29b6f2;strokeColor=#29b6f2;points=[];rotatable=0;resizable=0;connectable=0;editable=0;';
  11051. var cPoint = new mxCell('', new mxGeometry(x, y, CP_SIZE, CP_SIZE), cPointStyle);
  11052. cPoint.vertex = true;
  11053. cPoint.cp = true;
  11054. return editingGraph.addCell(cPoint);
  11055. };
  11056. //Add cell and current connection points on it
  11057. var geo = cell.geometry;
  11058. var mainCell = new mxCell(cell.value, new mxGeometry(0, 0, geo.width, geo.height),
  11059. cell.style + ';rotatable=0;resizable=0;connectable=0;editable=0;movable=0;');
  11060. mainCell.vertex = true;
  11061. editingGraph.addCell(mainCell);
  11062. //Adding a point via double click
  11063. editingGraph.dblClick = function(evt, cell)
  11064. {
  11065. if (cell != null && cell != mainCell)
  11066. {
  11067. editingGraph.setSelectionCell(cell);
  11068. }
  11069. else
  11070. {
  11071. var pt = mxUtils.convertPoint(editingGraph.container, mxEvent.getClientX(evt), mxEvent.getClientY(evt));
  11072. mxEvent.consume(evt);
  11073. var scale = editingGraph.view.scale;
  11074. var tr = editingGraph.view.translate;
  11075. editingGraph.setSelectionCell(createCPoint((pt.x - CP_HLF_SIZE * scale) / scale - tr.x,
  11076. (pt.y - CP_HLF_SIZE * scale) / scale - tr.y));
  11077. }
  11078. }
  11079. keyHandler = new mxKeyHandler(editingGraph);
  11080. function removeCPoints(evt)
  11081. {
  11082. var cells = editingGraph.getSelectionCells();
  11083. editingGraph.deleteCells(cells);
  11084. };
  11085. keyHandler.bindKey(46, removeCPoints);
  11086. keyHandler.bindKey(8, removeCPoints);
  11087. //Force rubberband inside the cell
  11088. editingGraph.getRubberband().isForceRubberbandEvent = function(event)
  11089. {
  11090. //Left click and not a click on a connection point
  11091. return event.evt.button == 0
  11092. && (event.getCell() == null || event.getCell() == mainCell);
  11093. };
  11094. //Force panning inside the cell
  11095. editingGraph.panningHandler.isForcePanningEvent = function(event)
  11096. {
  11097. return event.evt.button == 2;
  11098. };
  11099. var origIsCellSelectable = editingGraph.isCellSelectable;
  11100. editingGraph.isCellSelectable = function(cell)
  11101. {
  11102. if (cell == mainCell)
  11103. {
  11104. return false;
  11105. }
  11106. else
  11107. {
  11108. return origIsCellSelectable.apply(this, arguments);
  11109. }
  11110. };
  11111. // Disables hyperlinks
  11112. editingGraph.getLinkForCell = function()
  11113. {
  11114. return null;
  11115. };
  11116. var state = editingGraph.view.getState(mainCell);
  11117. var constraints = editingGraph.getAllConnectionConstraints(state);
  11118. for (var i = 0; constraints != null && i < constraints.length; i++)
  11119. {
  11120. var cp = editingGraph.getConnectionPoint(state, constraints[i]);
  11121. createCPoint(cp.x - CP_HLF_SIZE, cp.y - CP_HLF_SIZE);
  11122. }
  11123. editingGraph.fit(8);
  11124. editingGraph.center();
  11125. var zoomInBtn = mxUtils.button('', function()
  11126. {
  11127. editingGraph.zoomIn();
  11128. });
  11129. zoomInBtn.className = 'geSprite geSprite-zoomin';
  11130. zoomInBtn.setAttribute('title', mxResources.get('zoomIn'));
  11131. zoomInBtn.style.position = 'relative';
  11132. zoomInBtn.style.outline = 'none';
  11133. zoomInBtn.style.border = 'none';
  11134. zoomInBtn.style.margin = '2px';
  11135. zoomInBtn.style.cursor = 'pointer';
  11136. zoomInBtn.style.top = (mxClient.IS_FF) ? '-6px' : '0px';
  11137. mxUtils.setOpacity(zoomInBtn, 60);
  11138. var zoomOutBtn = mxUtils.button('', function()
  11139. {
  11140. editingGraph.zoomOut();
  11141. });
  11142. zoomOutBtn.className = 'geSprite geSprite-zoomout';
  11143. zoomOutBtn.setAttribute('title', mxResources.get('zoomOut'));
  11144. zoomOutBtn.style.position = 'relative';
  11145. zoomOutBtn.style.outline = 'none';
  11146. zoomOutBtn.style.border = 'none';
  11147. zoomOutBtn.style.margin = '2px';
  11148. zoomOutBtn.style.cursor = 'pointer';
  11149. zoomOutBtn.style.top = (mxClient.IS_FF) ? '-6px' : '0px';
  11150. mxUtils.setOpacity(zoomOutBtn, 60);
  11151. var zoomFitBtn = mxUtils.button('', function()
  11152. {
  11153. editingGraph.fit(8);
  11154. editingGraph.center();
  11155. });
  11156. zoomFitBtn.className = 'geSprite geSprite-fit';
  11157. zoomFitBtn.setAttribute('title', mxResources.get('fit'));
  11158. zoomFitBtn.style.position = 'relative';
  11159. zoomFitBtn.style.outline = 'none';
  11160. zoomFitBtn.style.border = 'none';
  11161. zoomFitBtn.style.margin = '2px';
  11162. zoomFitBtn.style.cursor = 'pointer';
  11163. zoomFitBtn.style.top = (mxClient.IS_FF) ? '-6px' : '0px';
  11164. mxUtils.setOpacity(zoomFitBtn, 60);
  11165. var zoomActualBtn = mxUtils.button('', function()
  11166. {
  11167. editingGraph.zoomActual();
  11168. editingGraph.center();
  11169. });
  11170. zoomActualBtn.className = 'geSprite geSprite-actualsize';
  11171. zoomActualBtn.setAttribute('title', mxResources.get('actualSize'));
  11172. zoomActualBtn.style.position = 'relative';
  11173. zoomActualBtn.style.outline = 'none';
  11174. zoomActualBtn.style.border = 'none';
  11175. zoomActualBtn.style.margin = '2px';
  11176. zoomActualBtn.style.cursor = 'pointer';
  11177. zoomActualBtn.style.top = (mxClient.IS_FF) ? '-6px' : '0px';
  11178. mxUtils.setOpacity(zoomActualBtn, 60);
  11179. var deleteBtn = mxUtils.button('', removeCPoints);
  11180. deleteBtn.className = 'geSprite geSprite-delete';
  11181. deleteBtn.setAttribute('title', mxResources.get('delete'));
  11182. deleteBtn.style.position = 'relative';
  11183. deleteBtn.style.outline = 'none';
  11184. deleteBtn.style.border = 'none';
  11185. deleteBtn.style.margin = '2px';
  11186. deleteBtn.style.float = 'right';
  11187. deleteBtn.style.cursor = 'pointer';
  11188. mxUtils.setOpacity(deleteBtn, 10); //Disabled
  11189. var zoomBtns = document.createElement('div');
  11190. zoomBtns.appendChild(zoomInBtn);
  11191. zoomBtns.appendChild(zoomOutBtn);
  11192. zoomBtns.appendChild(zoomActualBtn);
  11193. zoomBtns.appendChild(zoomFitBtn);
  11194. zoomBtns.appendChild(deleteBtn);
  11195. div.appendChild(zoomBtns);
  11196. var pCount = document.createElement('input');
  11197. pCount.setAttribute('type', 'number');
  11198. pCount.setAttribute('min', '1');
  11199. pCount.setAttribute('value', '1');
  11200. pCount.style.width = '45px';
  11201. pCount.style.position = 'relative';
  11202. pCount.style.top = (mxClient.IS_FF) ? '0px' : '-4px';
  11203. pCount.style.margin = '0 4px 0 4px';
  11204. zoomBtns.appendChild(pCount);
  11205. var sideSelect = document.createElement('select');
  11206. sideSelect.style.position = 'relative';
  11207. sideSelect.style.top = (mxClient.IS_FF) ? '0px' : '-4px';
  11208. var sides = ['left', 'right', 'top', 'bottom'];
  11209. for (var i = 0; i < sides.length; i++)
  11210. {
  11211. var side = sides[i];
  11212. var option = document.createElement('option');
  11213. mxUtils.write(option, mxResources.get(side));
  11214. option.value = side;
  11215. sideSelect.appendChild(option);
  11216. }
  11217. zoomBtns.appendChild(sideSelect);
  11218. var addBtn = mxUtils.button(mxResources.get('add'), function()
  11219. {
  11220. var count = parseInt(pCount.value);
  11221. count = count < 1? 1 : (count > 100? 100 : count);
  11222. pCount.value = count;
  11223. var side = sideSelect.value;
  11224. var geo = mainCell.geometry;
  11225. var cells = [];
  11226. for (var i = 0; i < count; i++)
  11227. {
  11228. var x, y;
  11229. switch(side)
  11230. {
  11231. case 'left':
  11232. x = geo.x;
  11233. y = geo.y + (i + 1) * geo.height / (count + 1);
  11234. break;
  11235. case 'right':
  11236. x = geo.x + geo.width;
  11237. y = geo.y + (i + 1) * geo.height / (count + 1);
  11238. break;
  11239. case 'top':
  11240. x = geo.x + (i + 1) * geo.width / (count + 1);
  11241. y = geo.y;
  11242. break;
  11243. case 'bottom':
  11244. x = geo.x + (i + 1) * geo.width / (count + 1);
  11245. y = geo.y + geo.height;
  11246. break;
  11247. }
  11248. cells.push(createCPoint(x - CP_HLF_SIZE, y - CP_HLF_SIZE));
  11249. }
  11250. editingGraph.setSelectionCells(cells);
  11251. });
  11252. addBtn.style.position = 'relative';
  11253. addBtn.style.marginLeft = '8px';
  11254. addBtn.style.top = (mxClient.IS_FF) ? '0px' : '-4px';
  11255. zoomBtns.appendChild(addBtn);
  11256. //Point properties
  11257. var pointPropsDiv = document.createElement('div');
  11258. pointPropsDiv.style.margin = '4px 0px 8px 0px';
  11259. pointPropsDiv.style.whiteSpace = 'nowrap';
  11260. pointPropsDiv.style.height = '24px';
  11261. var xSpan = document.createElement('span');
  11262. mxUtils.write(xSpan, mxResources.get('dx'));
  11263. pointPropsDiv.appendChild(xSpan);
  11264. var xInput = document.createElement('input');
  11265. xInput.setAttribute('type', 'number');
  11266. xInput.setAttribute('min', '0');
  11267. xInput.setAttribute('max', '100');
  11268. xInput.style.width = '45px';
  11269. xInput.style.margin = '0 4px 0 4px';
  11270. pointPropsDiv.appendChild(xInput);
  11271. mxUtils.write(pointPropsDiv, '%');
  11272. var dxInput = document.createElement('input');
  11273. dxInput.setAttribute('type', 'number');
  11274. dxInput.style.width = '45px';
  11275. dxInput.style.margin = '0 4px 0 4px';
  11276. pointPropsDiv.appendChild(dxInput);
  11277. mxUtils.write(pointPropsDiv, 'pt');
  11278. var ySpan = document.createElement('span');
  11279. mxUtils.write(ySpan, mxResources.get('dy'));
  11280. ySpan.style.marginLeft = '12px';
  11281. pointPropsDiv.appendChild(ySpan);
  11282. var yInput = document.createElement('input');
  11283. yInput.setAttribute('type', 'number');
  11284. yInput.setAttribute('min', '0');
  11285. yInput.setAttribute('max', '100');
  11286. yInput.style.width = '45px';
  11287. yInput.style.margin = '0 4px 0 4px';
  11288. pointPropsDiv.appendChild(yInput);
  11289. mxUtils.write(pointPropsDiv, '%');
  11290. var dyInput = document.createElement('input');
  11291. dyInput.setAttribute('type', 'number');
  11292. dyInput.style.width = '45px';
  11293. dyInput.style.margin = '0 4px 0 4px';
  11294. pointPropsDiv.appendChild(dyInput);
  11295. mxUtils.write(pointPropsDiv, 'pt');
  11296. div.appendChild(pointPropsDiv);
  11297. function applyPointProp()
  11298. {
  11299. var x = parseInt(xInput.value) || 0;
  11300. x = x < 0? 0 : (x > 100? 100 : x);
  11301. xInput.value = x;
  11302. var y = parseInt(yInput.value) || 0;
  11303. y = y < 0? 0 : (y > 100? 100 : y);
  11304. yInput.value = y;
  11305. var dx = parseInt(dxInput.value) || 0;
  11306. var dy = parseInt(dyInput.value) || 0;
  11307. var cp = editingGraph.getConnectionPoint(state,
  11308. new mxConnectionConstraint(new mxPoint(x/100, y/100), false, null, dx, dy));
  11309. var cell = editingGraph.getSelectionCell();
  11310. if (cell != null)
  11311. {
  11312. var geo = cell.geometry.clone();
  11313. var scale = editingGraph.view.scale;
  11314. var tr = editingGraph.view.translate;
  11315. geo.x = (cp.x - CP_HLF_SIZE * scale) / scale - tr.x;
  11316. geo.y = (cp.y - CP_HLF_SIZE * scale) / scale - tr.y;
  11317. editingGraph.model.setGeometry(cell, geo);
  11318. }
  11319. };
  11320. function getConstraintFromCPoint(cp)
  11321. {
  11322. var dx = 0, dy = 0, mGeo = mainCell.geometry;
  11323. var x = mxUtils.format((cp.geometry.x + CP_HLF_SIZE - mGeo.x) / mGeo.width);
  11324. var y = mxUtils.format((cp.geometry.y + CP_HLF_SIZE - mGeo.y) / mGeo.height);
  11325. if (x < 0)
  11326. {
  11327. dx = x * mGeo.width;
  11328. x = 0;
  11329. }
  11330. else if (x > 1)
  11331. {
  11332. dx = (x - 1) * mGeo.width;
  11333. x = 1;
  11334. }
  11335. if (y < 0)
  11336. {
  11337. dy = y * mGeo.height;
  11338. y = 0;
  11339. }
  11340. else if (y > 1)
  11341. {
  11342. dy = (y - 1) * mGeo.height;
  11343. y = 1;
  11344. }
  11345. return {x: x, y: y, dx: parseInt(dx), dy: parseInt(dy)};
  11346. };
  11347. function fillCPointProp()
  11348. {
  11349. if (editingGraph.getSelectionCount() == 1)
  11350. {
  11351. var cell = editingGraph.getSelectionCell();
  11352. var constraint = getConstraintFromCPoint(cell);
  11353. xInput.value = constraint.x * 100;
  11354. yInput.value = constraint.y * 100;
  11355. dxInput.value = constraint.dx;
  11356. dyInput.value = constraint.dy;
  11357. pointPropsDiv.style.visibility = '';
  11358. }
  11359. else
  11360. {
  11361. pointPropsDiv.style.visibility = 'hidden';
  11362. }
  11363. };
  11364. fillCPointProp();
  11365. editingGraph.getSelectionModel().addListener(mxEvent.CHANGE, function()
  11366. {
  11367. if (editingGraph.getSelectionCount() > 0)
  11368. {
  11369. mxUtils.setOpacity(deleteBtn, 60); //Enabled
  11370. }
  11371. else
  11372. {
  11373. mxUtils.setOpacity(deleteBtn, 10); //Disabled
  11374. }
  11375. fillCPointProp();
  11376. });
  11377. editingGraph.addListener(mxEvent.CELLS_MOVED, fillCPointProp);
  11378. mxEvent.addListener(xInput, 'change', applyPointProp);
  11379. mxEvent.addListener(yInput, 'change', applyPointProp);
  11380. mxEvent.addListener(dxInput, 'change', applyPointProp);
  11381. mxEvent.addListener(dyInput, 'change', applyPointProp);
  11382. var cancelBtn = mxUtils.button(mxResources.get('cancel'), function()
  11383. {
  11384. destroy();
  11385. editorUi.hideDialog();
  11386. });
  11387. cancelBtn.className = 'geBtn';
  11388. var applyBtn = mxUtils.button(mxResources.get('apply'), function()
  11389. {
  11390. var cells = editingGraph.model.cells, points = [], constraints = [];
  11391. for (var id in cells)
  11392. {
  11393. var cp = cells[id];
  11394. if (!cp.cp) continue;
  11395. constraints.push(getConstraintFromCPoint(cp));
  11396. }
  11397. //Find and remove identical points
  11398. constraints.sort(function(a, b)
  11399. {
  11400. return (a.x != b.x) ? a.x - b.x : ((a.y != b.y) ? a.y - b.y :
  11401. ((a.dx != b.dx) ? a.dx - b.dx : a.dy - b.dy)); //Sort based on x then y, dx and dy
  11402. });
  11403. for (var i = 0; i < constraints.length; i++)
  11404. {
  11405. if (i > 0 && constraints[i].x == constraints[i - 1].x && constraints[i].y == constraints[i - 1].y
  11406. && constraints[i].dx == constraints[i - 1].dx && constraints[i].dy == constraints[i - 1].dy)
  11407. {
  11408. continue; //Skip this identical point
  11409. }
  11410. points.push('[' + constraints[i].x + ',' + constraints[i].y + ',0,' +
  11411. constraints[i].dx + ',' + constraints[i].dy + ']');
  11412. }
  11413. editorUi.editor.graph.setCellStyles('points', '[' + points.join(',') + ']', [cell]);
  11414. destroy();
  11415. editorUi.hideDialog();
  11416. });
  11417. applyBtn.className = 'geBtn gePrimaryBtn';
  11418. var resetBtn = mxUtils.button(mxResources.get('reset'), function()
  11419. {
  11420. editorUi.editor.graph.setCellStyles('points', null, [cell]);
  11421. destroy();
  11422. editorUi.hideDialog();
  11423. });
  11424. resetBtn.className = 'geBtn';
  11425. var buttons = document.createElement('div');
  11426. buttons.style.marginTop = '10px';
  11427. buttons.style.textAlign = 'right';
  11428. if (editorUi.editor.cancelFirst)
  11429. {
  11430. buttons.appendChild(cancelBtn);
  11431. buttons.appendChild(resetBtn);
  11432. buttons.appendChild(applyBtn);
  11433. }
  11434. else
  11435. {
  11436. buttons.appendChild(resetBtn);
  11437. buttons.appendChild(applyBtn);
  11438. buttons.appendChild(cancelBtn);
  11439. }
  11440. div.appendChild(buttons);
  11441. };
  11442. function destroy()
  11443. {
  11444. if (keyHandler != null)
  11445. {
  11446. keyHandler.destroy();
  11447. }
  11448. };
  11449. this.destroy = destroy;
  11450. this.container = div;
  11451. };