Format.js 216 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378
  1. /**
  2. * Copyright (c) 2006-2012, JGraph Ltd
  3. */
  4. Format = function(editorUi, container)
  5. {
  6. this.editorUi = editorUi;
  7. this.container = container;
  8. };
  9. /**
  10. * Background color for inactive tabs.
  11. */
  12. Format.inactiveTabBackgroundColor = '#e4e4e4';
  13. /**
  14. * Icons for markers (24x16).
  15. */
  16. Format.classicFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  17. Format.classicThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 3 8 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  18. Format.openFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 0 L 0 8 L 8 16 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  19. Format.openThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 8 12 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  20. Format.openAsyncFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  21. Format.blockFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  22. Format.blockThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  23. Format.asyncFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  24. Format.ovalFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  25. Format.diamondFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  26. Format.diamondThinFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 0 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  27. Format.classicMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 10 2 L 5 8 L 10 14 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  28. Format.classicThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 5 8 L 8 12 Z M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  29. Format.blockMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  30. Format.blockThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 4 L 8 12 Z M 8 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  31. Format.asyncMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 8 L 6 4 L 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  32. Format.ovalMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 5 5 0 0 1 5 3 A 5 5 0 0 1 11 8 A 5 5 0 0 1 5 13 A 5 5 0 0 1 0 8 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  33. Format.diamondMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 6 2 L 12 8 L 6 14 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  34. Format.diamondThinMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 3 L 16 8 L 8 13 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  35. Format.boxMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 L 10 3 L 10 13 L 0 13 Z M 10 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  36. Format.halfCircleMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 3 A 5 5 0 0 1 5 8 A 5 5 0 0 1 0 13 M 5 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  37. Format.dashMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  38. Format.crossMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 14 M 12 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  39. Format.circlePlusMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 6 2 L 6 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  40. Format.circleMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 A 6 6 0 0 1 6 2 A 6 6 0 0 1 12 8 A 6 6 0 0 1 6 14 A 6 6 0 0 1 0 8 Z M 12 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  41. Format.ERmandOneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 6 2 L 6 14 M 9 2 L 9 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  42. Format.ERmanyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  43. Format.ERoneToManyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 12 8 L 0 14 M 15 2 L 15 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  44. Format.ERzeroToOneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 4 3 L 4 13" stroke="#404040" fill="transparent"/>', 32, 20);
  45. Format.ERzeroToManyMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 8 8 A 5 5 0 0 1 13 3 A 5 5 0 0 1 18 8 A 5 5 0 0 1 13 13 A 5 5 0 0 1 8 8 Z M 0 8 L 8 8 M 18 8 L 24 8 M 0 3 L 8 8 L 0 13" stroke="#404040" fill="transparent"/>', 32, 20);
  46. Format.EROneMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 5 2 L 5 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  47. Format.baseDashMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 2 L 0 14 M 0 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  48. Format.doubleBlockMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="transparent"/>', 32, 20);
  49. Format.doubleBlockFilledMarkerImage = Graph.createSvgImage(20, 22, '<path transform="translate(4,2)" stroke-width="2" d="M 0 8 L 8 2 L 8 14 Z M 8 8 L 16 2 L 16 14 Z M 16 8 L 24 8" stroke="#404040" fill="#404040"/>', 32, 20);
  50. /**
  51. * Adds a style change item to the given menu.
  52. */
  53. Format.processMenuIcon = function(elt, transform)
  54. {
  55. var imgs = elt.getElementsByTagName('img');
  56. if (imgs.length > 0)
  57. {
  58. imgs[0].className = 'geIcon geAdaptiveAsset';
  59. imgs[0].style.padding = '0px';
  60. imgs[0].style.margin = '0 0 0 2px';
  61. if (transform != null)
  62. {
  63. mxUtils.setPrefixedStyle(imgs[0].style, 'transform', transform);
  64. }
  65. }
  66. return elt;
  67. };
  68. /**
  69. * Returns information about the current selection.
  70. */
  71. Format.prototype.labelIndex = 0;
  72. /**
  73. * Returns information about the current selection.
  74. */
  75. Format.prototype.diagramIndex = 0;
  76. /**
  77. * Returns information about the current selection.
  78. */
  79. Format.prototype.currentIndex = 0;
  80. /**
  81. * Returns information about the current selection.
  82. */
  83. Format.prototype.showCloseButton = true;
  84. /**
  85. * Returns information about the current selection.
  86. */
  87. Format.prototype.rounded = false;
  88. /**
  89. * Returns information about the current selection.
  90. */
  91. Format.prototype.curved = false;
  92. /**
  93. * Adds the label menu items to the given menu and parent.
  94. */
  95. Format.prototype.init = function()
  96. {
  97. var ui = this.editorUi;
  98. var editor = ui.editor;
  99. var graph = editor.graph;
  100. this.update = mxUtils.bind(this, function(sender, evt)
  101. {
  102. this.refresh();
  103. });
  104. graph.getSelectionModel().addListener(mxEvent.CHANGE, this.update);
  105. graph.getModel().addListener(mxEvent.CHANGE, this.update);
  106. graph.addListener(mxEvent.EDITING_STARTED, this.update);
  107. graph.addListener(mxEvent.EDITING_STOPPED, this.update);
  108. graph.getView().addListener('unitChanged', this.update);
  109. editor.addListener('autosaveChanged', this.update);
  110. graph.addListener(mxEvent.ROOT, this.update);
  111. ui.addListener('styleChanged', this.update);
  112. ui.addListener('darkModeChanged', this.update);
  113. ui.addListener('lockedChanged', this.update);
  114. this.refresh();
  115. };
  116. /**
  117. * Adds the label menu items to the given menu and parent.
  118. */
  119. Format.prototype.clear = function()
  120. {
  121. this.container.innerText = '';
  122. // Destroy existing panels
  123. if (this.panels != null)
  124. {
  125. for (var i = 0; i < this.panels.length; i++)
  126. {
  127. this.panels[i].destroy();
  128. }
  129. }
  130. this.panels = [];
  131. };
  132. /**
  133. * Adds the label menu items to the given menu and parent.
  134. */
  135. Format.prototype.refresh = function()
  136. {
  137. if (this.pendingRefresh != null)
  138. {
  139. window.clearTimeout(this.pendingRefresh);
  140. this.pendingRefresh = null;
  141. }
  142. this.pendingRefresh = window.setTimeout(mxUtils.bind(this, function()
  143. {
  144. this.immediateRefresh();
  145. }));
  146. };
  147. /**
  148. * Adds the label menu items to the given menu and parent.
  149. */
  150. Format.prototype.immediateRefresh = function()
  151. {
  152. // Performance tweak: No refresh needed if not visible
  153. if (this.container.style.width == '0px')
  154. {
  155. return;
  156. }
  157. this.clear();
  158. var ui = this.editorUi;
  159. var graph = ui.editor.graph;
  160. var div = document.createElement('div');
  161. div.style.whiteSpace = 'nowrap';
  162. div.style.color = Editor.isDarkMode() ? '#8D8D8D' : '#616161';
  163. div.style.textAlign = 'left';
  164. div.style.cursor = 'default';
  165. var label = document.createElement('div');
  166. label.className = 'geFormatSection';
  167. label.style.textAlign = 'center';
  168. label.style.fontWeight = 'bold';
  169. label.style.paddingTop = '8px';
  170. label.style.fontSize = '13px';
  171. label.style.borderWidth = '0px 0px 1px 1px';
  172. label.style.borderStyle = 'solid';
  173. label.style.display = 'inline-block';
  174. label.style.height = '25px';
  175. label.style.overflow = 'hidden';
  176. label.style.width = '100%';
  177. this.container.appendChild(div);
  178. // Prevents text selection
  179. mxEvent.addListener(label, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
  180. mxUtils.bind(this, function(evt)
  181. {
  182. evt.preventDefault();
  183. }));
  184. var ss = ui.getSelectionState();
  185. var containsLabel = ss.containsLabel;
  186. var currentLabel = null;
  187. var currentPanel = null;
  188. var addClickHandler = mxUtils.bind(this, function(elt, panel, index, lastEntry)
  189. {
  190. var clickHandler = mxUtils.bind(this, function(evt)
  191. {
  192. if (currentLabel != elt)
  193. {
  194. if (containsLabel)
  195. {
  196. this.labelIndex = index;
  197. }
  198. else if (graph.isSelectionEmpty())
  199. {
  200. this.diagramIndex = index;
  201. }
  202. else
  203. {
  204. this.currentIndex = index;
  205. }
  206. if (currentLabel != null)
  207. {
  208. currentLabel.style.backgroundColor = Format.inactiveTabBackgroundColor;
  209. currentLabel.style.borderBottomWidth = '1px';
  210. }
  211. currentLabel = elt;
  212. currentLabel.style.backgroundColor = '';
  213. currentLabel.style.borderBottomWidth = '0px';
  214. if (currentPanel != panel)
  215. {
  216. if (currentPanel != null)
  217. {
  218. currentPanel.style.display = 'none';
  219. }
  220. currentPanel = panel;
  221. currentPanel.style.display = '';
  222. }
  223. }
  224. });
  225. mxEvent.addListener(elt, 'click', clickHandler);
  226. // Prevents text selection
  227. mxEvent.addListener(elt, (mxClient.IS_POINTER) ? 'pointerdown' : 'mousedown',
  228. mxUtils.bind(this, function(evt)
  229. {
  230. evt.preventDefault();
  231. }));
  232. if ((lastEntry && currentLabel == null) ||
  233. (index == ((containsLabel) ? this.labelIndex : ((graph.isSelectionEmpty()) ?
  234. this.diagramIndex : this.currentIndex))))
  235. {
  236. // Invokes handler directly as a workaround for no click on DIV in KHTML.
  237. clickHandler();
  238. }
  239. });
  240. var idx = 0;
  241. if (graph.isSelectionEmpty())
  242. {
  243. mxUtils.write(label, mxResources.get('diagram'));
  244. label.style.borderLeftWidth = '0px';
  245. div.appendChild(label);
  246. var diagramPanel = div.cloneNode(false);
  247. this.panels.push(new DiagramFormatPanel(this, ui, diagramPanel));
  248. this.container.appendChild(diagramPanel);
  249. if (Editor.styles != null)
  250. {
  251. diagramPanel.style.display = 'none';
  252. label.style.width = (this.showCloseButton) ? '106px' : '50%';
  253. label.style.cursor = 'pointer';
  254. label.style.backgroundColor = Format.inactiveTabBackgroundColor;
  255. var label2 = label.cloneNode(false);
  256. label2.style.borderLeftWidth = '1px';
  257. label2.style.borderRightWidth = '1px';
  258. label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
  259. addClickHandler(label, diagramPanel, idx++);
  260. var stylePanel = div.cloneNode(false);
  261. stylePanel.style.display = 'none';
  262. mxUtils.write(label2, mxResources.get('style'));
  263. div.appendChild(label2);
  264. this.panels.push(new DiagramStylePanel(this, ui, stylePanel));
  265. this.container.appendChild(stylePanel);
  266. addClickHandler(label2, stylePanel, idx++);
  267. }
  268. // Adds button to hide the format panel since
  269. // people don't seem to find the toolbar button
  270. // and the menu item in the format menu
  271. if (this.showCloseButton)
  272. {
  273. var label2 = label.cloneNode(false);
  274. label2.style.borderLeftWidth = '1px';
  275. label2.style.borderRightWidth = '1px';
  276. label2.style.borderBottomWidth = '1px';
  277. label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
  278. label2.style.position = 'absolute';
  279. label2.style.right = '0px';
  280. label2.style.top = '0px';
  281. label2.style.width = '25px';
  282. var img = document.createElement('img');
  283. img.setAttribute('border', '0');
  284. img.setAttribute('src', Dialog.prototype.closeImage);
  285. img.setAttribute('title', mxResources.get('hide'));
  286. img.style.position = 'absolute';
  287. img.style.display = 'block';
  288. img.style.right = '0px';
  289. img.style.top = '8px';
  290. img.style.cursor = 'pointer';
  291. img.style.marginTop = '1px';
  292. img.style.marginRight = '6px';
  293. img.style.border = '1px solid transparent';
  294. img.style.padding = '1px';
  295. img.style.opacity = 0.5;
  296. label2.appendChild(img)
  297. mxEvent.addListener(img, 'click', function()
  298. {
  299. ui.actions.get('format').funct();
  300. });
  301. div.appendChild(label2);
  302. }
  303. }
  304. else if (graph.isEditing())
  305. {
  306. mxUtils.write(label, mxResources.get('text'));
  307. div.appendChild(label);
  308. label.style.borderLeftStyle = 'none';
  309. this.panels.push(new TextFormatPanel(this, ui, div));
  310. }
  311. else
  312. {
  313. label.style.backgroundColor = Format.inactiveTabBackgroundColor;
  314. label.style.borderLeftWidth = '1px';
  315. label.style.cursor = 'pointer';
  316. label.style.width = ss.cells.length == 0 ? '100%' :
  317. (containsLabel ? '50%' : '33.3%');
  318. var label2 = label.cloneNode(false);
  319. var label3 = label2.cloneNode(false);
  320. // Workaround for ignored background in IE
  321. label2.style.backgroundColor = Format.inactiveTabBackgroundColor;
  322. label3.style.backgroundColor = Format.inactiveTabBackgroundColor;
  323. // Style
  324. if (containsLabel)
  325. {
  326. label2.style.borderLeftWidth = '0px';
  327. }
  328. else if (ss.cells.length > 0)
  329. {
  330. label.style.borderLeftWidth = '0px';
  331. mxUtils.write(label, mxResources.get('style'));
  332. div.appendChild(label);
  333. var stylePanel = div.cloneNode(false);
  334. stylePanel.style.display = 'none';
  335. this.panels.push(new StyleFormatPanel(this, ui, stylePanel));
  336. this.container.appendChild(stylePanel);
  337. addClickHandler(label, stylePanel, idx++);
  338. }
  339. // Text
  340. mxUtils.write(label2, mxResources.get('text'));
  341. div.appendChild(label2);
  342. var textPanel = div.cloneNode(false);
  343. textPanel.style.display = 'none';
  344. this.panels.push(new TextFormatPanel(this, ui, textPanel));
  345. this.container.appendChild(textPanel);
  346. // Arrange
  347. mxUtils.write(label3, mxResources.get('arrange'));
  348. div.appendChild(label3);
  349. var arrangePanel = div.cloneNode(false);
  350. arrangePanel.style.display = 'none';
  351. this.panels.push(new ArrangePanel(this, ui, arrangePanel));
  352. this.container.appendChild(arrangePanel);
  353. if (ss.cells.length > 0)
  354. {
  355. addClickHandler(label2, textPanel, idx + 1);
  356. }
  357. else
  358. {
  359. label2.style.display = 'none';
  360. }
  361. addClickHandler(label3, arrangePanel, idx++, true);
  362. }
  363. };
  364. /**
  365. * Base class for format panels.
  366. */
  367. BaseFormatPanel = function(format, editorUi, container)
  368. {
  369. this.format = format;
  370. this.editorUi = editorUi;
  371. this.container = container;
  372. this.listeners = [];
  373. };
  374. /**
  375. *
  376. */
  377. BaseFormatPanel.prototype.buttonBackgroundColor = 'transparent';
  378. /**
  379. * Install input handler.
  380. */
  381. BaseFormatPanel.prototype.installInputHandler = function(input, key, defaultValue, min, max, unit, textEditFallback, isFloat, useUnits)
  382. {
  383. unit = (unit != null) ? unit : '';
  384. isFloat = (isFloat != null) ? isFloat : false;
  385. var ui = this.editorUi;
  386. var graph = ui.editor.graph;
  387. min = (min != null) ? min : 1;
  388. max = (max != null) ? max : 999;
  389. var selState = null;
  390. var updating = false;
  391. var lastValue = null;
  392. var update = mxUtils.bind(this, function(evt)
  393. {
  394. var value = (isFloat) ? parseFloat(input.value) : parseInt(input.value);
  395. if (useUnits)
  396. {
  397. value = this.fromUnit(value);
  398. }
  399. if (value != lastValue)
  400. {
  401. lastValue = value;
  402. // Special case: angle mod 360
  403. if (!isNaN(value) && key == mxConstants.STYLE_ROTATION)
  404. {
  405. // Workaround for decimal rounding errors in floats is to
  406. // use integer and round all numbers to two decimal point
  407. value = mxUtils.mod(Math.round(value * 100), 36000) / 100;
  408. }
  409. value = Math.min(max, Math.max(min, (isNaN(value)) ? defaultValue : value));
  410. if (graph.cellEditor.isContentEditing() && textEditFallback)
  411. {
  412. if (!updating)
  413. {
  414. updating = true;
  415. if (selState != null)
  416. {
  417. graph.cellEditor.restoreSelection(selState);
  418. selState = null;
  419. }
  420. textEditFallback(value);
  421. input.value = (useUnits? this.inUnit(value) : value) + unit;
  422. // Restore focus and selection in input
  423. updating = false;
  424. }
  425. }
  426. else if (value != mxUtils.getValue(ui.getSelectionState().style, key, defaultValue))
  427. {
  428. if (graph.isEditing())
  429. {
  430. graph.stopEditing(true);
  431. }
  432. graph.getModel().beginUpdate();
  433. try
  434. {
  435. var cells = ui.getSelectionState().cells;
  436. graph.setCellStyles(key, value, cells);
  437. // Handles special case for fontSize where HTML labels are parsed and updated
  438. if (key == mxConstants.STYLE_FONTSIZE)
  439. {
  440. graph.updateLabelElements(cells, function(elt)
  441. {
  442. elt.style.fontSize = value + 'px';
  443. elt.removeAttribute('size');
  444. });
  445. }
  446. for (var i = 0; i < cells.length; i++)
  447. {
  448. if (graph.model.getChildCount(cells[i]) == 0)
  449. {
  450. graph.autoSizeCell(cells[i], false);
  451. }
  452. }
  453. ui.fireEvent(new mxEventObject('styleChanged', 'keys', [key],
  454. 'values', [value], 'cells', cells));
  455. }
  456. finally
  457. {
  458. graph.getModel().endUpdate();
  459. }
  460. }
  461. input.value = (useUnits? this.inUnit(value) : value) + unit;
  462. }
  463. mxEvent.consume(evt);
  464. });
  465. if (textEditFallback && graph.cellEditor.isContentEditing())
  466. {
  467. // KNOWN: Arrow up/down clear selection text in quirks/IE 8
  468. // Text size via arrow button limits to 16 in IE11. Why?
  469. mxEvent.addListener(input, 'mousedown', function()
  470. {
  471. if (document.activeElement == graph.cellEditor.textarea)
  472. {
  473. selState = graph.cellEditor.saveSelection();
  474. }
  475. });
  476. mxEvent.addListener(input, 'touchstart', function()
  477. {
  478. if (document.activeElement == graph.cellEditor.textarea)
  479. {
  480. selState = graph.cellEditor.saveSelection();
  481. }
  482. });
  483. }
  484. mxEvent.addListener(input, 'change', update);
  485. mxEvent.addListener(input, 'blur', update);
  486. return update;
  487. };
  488. /**
  489. * Adds the given option.
  490. */
  491. BaseFormatPanel.prototype.createPanel = function()
  492. {
  493. var div = document.createElement('div');
  494. div.className = 'geFormatSection';
  495. div.style.padding = '12px 0px 8px 14px';
  496. return div;
  497. };
  498. /**
  499. * Adds the given option.
  500. */
  501. BaseFormatPanel.prototype.createTitle = function(title)
  502. {
  503. var div = document.createElement('div');
  504. div.style.padding = '0px 0px 6px 0px';
  505. div.style.whiteSpace = 'nowrap';
  506. div.style.overflow = 'hidden';
  507. div.style.width = '200px';
  508. div.style.fontWeight = 'bold';
  509. mxUtils.write(div, title);
  510. return div;
  511. };
  512. /**
  513. *
  514. */
  515. BaseFormatPanel.prototype.addAction = function(div, name)
  516. {
  517. var action = this.editorUi.actions.get(name);
  518. var btn = null;
  519. if (action != null && action.isEnabled())
  520. {
  521. btn = mxUtils.button(action.label, mxUtils.bind(this, function(evt)
  522. {
  523. try
  524. {
  525. action.funct(evt, evt);
  526. }
  527. catch (e)
  528. {
  529. this.editorUi.handleError(e);
  530. }
  531. }));
  532. var short = (action.shortcut != null) ? ' (' + action.shortcut + ')' : '';
  533. btn.setAttribute('title', action.label + short);
  534. btn.style.marginBottom = '2px';
  535. btn.style.width = '210px';
  536. div.appendChild(btn);
  537. }
  538. return btn;
  539. };
  540. /**
  541. *
  542. */
  543. BaseFormatPanel.prototype.addActions = function(div, names)
  544. {
  545. var lastBr = null;
  546. var last = null;
  547. var count = 0;
  548. for (var i = 0; i < names.length; i++)
  549. {
  550. var btn = this.addAction(div, names[i]);
  551. if (btn != null)
  552. {
  553. count++;
  554. if (mxUtils.mod(count, 2) == 0)
  555. {
  556. last.style.marginRight = '2px';
  557. last.style.width = '104px';
  558. btn.style.width = '104px';
  559. lastBr.parentNode.removeChild(lastBr);
  560. }
  561. lastBr = mxUtils.br(div);
  562. last = btn;
  563. }
  564. }
  565. return count;
  566. };
  567. /**
  568. *
  569. */
  570. BaseFormatPanel.prototype.createStepper = function(input, update, step, height, disableFocus, defaultValue, isFloat)
  571. {
  572. step = (step != null) ? step : 1;
  573. height = (height != null) ? height : 9;
  574. var bigStep = 10 * step;
  575. var stepper = document.createElement('div');
  576. stepper.className = 'geBtnStepper';
  577. stepper.style.position = 'absolute';
  578. var up = document.createElement('div');
  579. up.style.position = 'relative';
  580. up.style.height = height + 'px';
  581. up.style.width = '10px';
  582. up.className = 'geBtnUp';
  583. stepper.appendChild(up);
  584. var down = up.cloneNode(false);
  585. down.style.border = 'none';
  586. down.style.height = height + 'px';
  587. down.className = 'geBtnDown';
  588. stepper.appendChild(down);
  589. mxEvent.addGestureListeners(down, function(evt)
  590. {
  591. // Stops text selection on shift+click
  592. mxEvent.consume(evt);
  593. }, null, function(evt)
  594. {
  595. if (input.value == '')
  596. {
  597. input.value = defaultValue || '2';
  598. }
  599. var val = isFloat? parseFloat(input.value) : parseInt(input.value);
  600. if (!isNaN(val))
  601. {
  602. input.value = val - (mxEvent.isShiftDown(evt) ? bigStep : step);
  603. if (update != null)
  604. {
  605. update(evt);
  606. }
  607. }
  608. mxEvent.consume(evt);
  609. });
  610. mxEvent.addGestureListeners(up, function(evt)
  611. {
  612. // Stops text selection on shift+click
  613. mxEvent.consume(evt);
  614. }, null, function(evt)
  615. {
  616. if (input.value == '')
  617. {
  618. input.value = defaultValue || '0';
  619. }
  620. var val = isFloat? parseFloat(input.value) : parseInt(input.value);
  621. if (!isNaN(val))
  622. {
  623. input.value = val + (mxEvent.isShiftDown(evt) ? bigStep : step);
  624. if (update != null)
  625. {
  626. update(evt);
  627. }
  628. }
  629. mxEvent.consume(evt);
  630. });
  631. // Disables transfer of focus to DIV but also :active CSS
  632. // so it's only used for fontSize where the focus should
  633. // stay on the selected text, but not for any other input.
  634. if (disableFocus)
  635. {
  636. var currentSelection = null;
  637. mxEvent.addGestureListeners(stepper,
  638. function(evt)
  639. {
  640. mxEvent.consume(evt);
  641. },
  642. null,
  643. function(evt)
  644. {
  645. // Workaround for lost current selection in page because of focus in IE
  646. if (currentSelection != null)
  647. {
  648. try
  649. {
  650. currentSelection.select();
  651. }
  652. catch (e)
  653. {
  654. // ignore
  655. }
  656. currentSelection = null;
  657. mxEvent.consume(evt);
  658. }
  659. }
  660. );
  661. }
  662. else
  663. {
  664. // Stops propagation on checkbox labels
  665. mxEvent.addListener(stepper, 'click', function(evt)
  666. {
  667. mxEvent.consume(evt);
  668. });
  669. }
  670. return stepper;
  671. };
  672. /**
  673. * Adds the given option.
  674. */
  675. BaseFormatPanel.prototype.createOption = function(label, isCheckedFn, setCheckedFn, listener, fn)
  676. {
  677. var div = document.createElement('div');
  678. div.style.display = 'flex';
  679. div.style.alignItems = 'center';
  680. div.style.padding = '3px 0px 3px 0px';
  681. div.style.height = '18px';
  682. var cb = document.createElement('input');
  683. cb.setAttribute('type', 'checkbox');
  684. cb.style.margin = '1px 6px 0px 0px';
  685. cb.style.verticalAlign = 'top';
  686. div.appendChild(cb);
  687. var elt = document.createElement('div');
  688. elt.setAttribute('title', label);
  689. elt.style.display = 'inline-block';
  690. elt.style.whiteSpace = 'nowrap';
  691. elt.style.textOverflow = 'ellipsis';
  692. elt.style.overflow = 'hidden';
  693. elt.style.maxWidth = '160px';
  694. elt.style.maxWidth = '160px';
  695. elt.style.userSelect = 'none';
  696. mxUtils.write(elt, label);
  697. div.appendChild(elt);
  698. var applying = false;
  699. var value = isCheckedFn();
  700. var apply = function(newValue, evt)
  701. {
  702. if (!applying)
  703. {
  704. applying = true;
  705. if (newValue)
  706. {
  707. cb.setAttribute('checked', 'checked');
  708. cb.defaultChecked = true;
  709. cb.checked = true;
  710. }
  711. else
  712. {
  713. cb.removeAttribute('checked');
  714. cb.defaultChecked = false;
  715. cb.checked = false;
  716. }
  717. if (value != newValue)
  718. {
  719. value = newValue;
  720. // Checks if the color value needs to be updated in the model
  721. if (isCheckedFn() != value)
  722. {
  723. setCheckedFn(value, evt);
  724. }
  725. }
  726. applying = false;
  727. }
  728. };
  729. mxEvent.addListener(div, 'click', function(evt)
  730. {
  731. if (cb.getAttribute('disabled') != 'disabled')
  732. {
  733. // Toggles checkbox state for click on label
  734. var source = mxEvent.getSource(evt);
  735. if (source == div || source == elt)
  736. {
  737. cb.checked = !cb.checked;
  738. }
  739. apply(cb.checked, evt);
  740. }
  741. });
  742. apply(value);
  743. if (listener != null)
  744. {
  745. listener.install(apply);
  746. this.listeners.push(listener);
  747. }
  748. if (fn != null)
  749. {
  750. fn(div);
  751. }
  752. return div;
  753. };
  754. /**
  755. * The string 'null' means use null in values.
  756. */
  757. BaseFormatPanel.prototype.createCellOption = function(label, key, defaultValue, enabledValue, disabledValue, fn, action, stopEditing, cells)
  758. {
  759. var ui = this.editorUi;
  760. var editor = ui.editor;
  761. var graph = editor.graph;
  762. enabledValue = (enabledValue != null) ? ((enabledValue == 'null') ? null : enabledValue) : 1;
  763. disabledValue = (disabledValue != null) ? ((disabledValue == 'null') ? null : disabledValue) : 0;
  764. var style = (cells != null) ? graph.getCommonStyle(cells) : ui.getSelectionState().style;
  765. return this.createOption(label, function()
  766. {
  767. return mxUtils.getValue(style, key, defaultValue) != disabledValue;
  768. }, function(checked)
  769. {
  770. if (stopEditing)
  771. {
  772. graph.stopEditing();
  773. }
  774. if (action != null)
  775. {
  776. action.funct();
  777. }
  778. else
  779. {
  780. graph.getModel().beginUpdate();
  781. try
  782. {
  783. var temp = (cells != null) ? cells : ui.getSelectionState().cells;
  784. var value = (checked) ? enabledValue : disabledValue;
  785. graph.setCellStyles(key, value, temp);
  786. if (fn != null)
  787. {
  788. fn(temp, value);
  789. }
  790. ui.fireEvent(new mxEventObject('styleChanged', 'keys',
  791. [key], 'values', [value], 'cells', temp));
  792. }
  793. finally
  794. {
  795. graph.getModel().endUpdate();
  796. }
  797. }
  798. },
  799. {
  800. install: function(apply)
  801. {
  802. this.listener = function()
  803. {
  804. apply(mxUtils.getValue(style, key, defaultValue) != disabledValue);
  805. };
  806. graph.getModel().addListener(mxEvent.CHANGE, this.listener);
  807. },
  808. destroy: function()
  809. {
  810. graph.getModel().removeListener(this.listener);
  811. }
  812. });
  813. };
  814. /**
  815. * Adds the given color option.
  816. */
  817. BaseFormatPanel.prototype.createColorOption = function(label, getColorFn, setColorFn,
  818. defaultColor, listener, callbackFn, hideCheckbox, defaultColorValue)
  819. {
  820. var graph = this.editorUi.editor.graph;
  821. var div = document.createElement('div');
  822. div.style.padding = '3px 0px 3px 0px';
  823. div.style.whiteSpace = 'nowrap';
  824. div.style.overflow = 'hidden';
  825. div.style.width = '200px';
  826. div.style.height = '18px';
  827. var cb = document.createElement('input');
  828. cb.setAttribute('type', 'checkbox');
  829. cb.style.margin = '1px 6px 0px 0px';
  830. cb.style.verticalAlign = 'top';
  831. if (!hideCheckbox)
  832. {
  833. div.appendChild(cb);
  834. }
  835. var span = document.createElement('span');
  836. span.style.verticalAlign = 'top';
  837. mxUtils.write(span, label);
  838. div.appendChild(span);
  839. var value = getColorFn();
  840. var applying = false;
  841. var dropper = null;
  842. var btn = null;
  843. var clrInput = document.createElement('input');
  844. clrInput.setAttribute('type', 'color');
  845. clrInput.style.position = 'relative';
  846. clrInput.style.visibility = 'hidden';
  847. clrInput.style.top = '10px';
  848. clrInput.style.width = '0px';
  849. clrInput.style.height = '0px';
  850. clrInput.style.border = 'none';
  851. // Adds native color dialog
  852. if (!mxClient.IS_IE && !mxClient.IS_IE11 && !mxClient.IS_TOUCH)
  853. {
  854. dropper = document.createElement('img');
  855. dropper.src = Editor.colorDropperImage;
  856. dropper.className = 'geColorDropper geAdaptiveAsset';
  857. dropper.style.position = 'relative';
  858. dropper.style.right = '-20px';
  859. dropper.style.top = '-1px';
  860. dropper.style.width = 'auto';
  861. dropper.style.height = '14px';
  862. mxEvent.addListener(dropper, 'click', function(evt)
  863. {
  864. var color = value;
  865. if (color == 'default')
  866. {
  867. color = defaultColorValue;
  868. }
  869. clrInput.value = color;
  870. clrInput.click();
  871. mxEvent.consume(evt);
  872. });
  873. }
  874. var apply = function(color, disableUpdate, forceUpdate)
  875. {
  876. if (!applying)
  877. {
  878. var defaultValue = (defaultColor == 'null') ? null : defaultColor;
  879. applying = true;
  880. color = (/(^#?[a-zA-Z0-9]*$)/.test(color)) ? color : defaultValue;
  881. var tempColor = (color != null && color != mxConstants.NONE) ? color : defaultValue;
  882. var div = document.createElement('div');
  883. div.style.width = '21px';
  884. div.style.height = '12px';
  885. div.style.margin = '2px 18px 2px 3px';
  886. div.style.border = '1px solid black';
  887. div.style.backgroundColor = (tempColor == 'default') ? defaultColorValue : tempColor;
  888. btn.innerText = '';
  889. btn.appendChild(div);
  890. if (dropper != null)
  891. {
  892. div.style.width = '21px';
  893. div.style.margin = '2px 18px 2px 3px';
  894. div.appendChild(dropper);
  895. }
  896. else
  897. {
  898. div.style.width = '36px';
  899. div.style.margin = '3px';
  900. }
  901. if (color != null && color != mxConstants.NONE && color.length > 1 && typeof color === 'string')
  902. {
  903. var clr = (color.charAt(0) == '#') ? color.substring(1).toUpperCase() : color;
  904. var name = ColorDialog.prototype.colorNames[clr];
  905. if (name != null)
  906. {
  907. btn.setAttribute('title', name);
  908. }
  909. }
  910. if (color != null && color != mxConstants.NONE &&
  911. !graph.isSpecialColor(color))
  912. {
  913. cb.setAttribute('checked', 'checked');
  914. cb.defaultChecked = true;
  915. cb.checked = true;
  916. }
  917. else
  918. {
  919. cb.removeAttribute('checked');
  920. cb.defaultChecked = false;
  921. cb.checked = false;
  922. }
  923. btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none';
  924. if (callbackFn != null)
  925. {
  926. callbackFn(color == 'null' ? null : color);
  927. }
  928. value = color;
  929. if (!disableUpdate)
  930. {
  931. // Checks if the color value needs to be updated in the model
  932. if (forceUpdate || hideCheckbox || getColorFn() != value)
  933. {
  934. setColorFn(value == 'null' ? null : value, value);
  935. }
  936. }
  937. applying = false;
  938. }
  939. };
  940. div.appendChild(clrInput);
  941. mxEvent.addListener(clrInput, 'change', function()
  942. {
  943. apply(clrInput.value, null, true);
  944. });
  945. btn = mxUtils.button('', mxUtils.bind(this, function(evt)
  946. {
  947. var color = value;
  948. if (color == 'default' && defaultColor != 'default')
  949. {
  950. color = defaultColorValue;
  951. }
  952. this.editorUi.pickColor(color, function(newColor)
  953. {
  954. apply(newColor, null, true);
  955. }, (defaultColor == 'default') ? 'default' : null,
  956. defaultColorValue);
  957. mxEvent.consume(evt);
  958. }));
  959. btn.style.position = 'absolute';
  960. btn.style.marginTop = '-3px';
  961. btn.style.left = '178px';
  962. btn.style.height = '22px';
  963. btn.className = 'geColorBtn';
  964. btn.style.display = (cb.checked || hideCheckbox) ? '' : 'none';
  965. div.appendChild(btn);
  966. var clr = (value != null && typeof value === 'string' && value.charAt(0) == '#') ? value.substring(1).toUpperCase() : value;
  967. var name = ColorDialog.prototype.colorNames[clr];
  968. if (name != null)
  969. {
  970. btn.setAttribute('title', name);
  971. }
  972. mxEvent.addListener(div, 'click', function(evt)
  973. {
  974. var source = mxEvent.getSource(evt);
  975. if (source == cb || source.nodeName != 'INPUT')
  976. {
  977. // Toggles checkbox state for click on label
  978. if (source != cb)
  979. {
  980. cb.checked = !cb.checked;
  981. }
  982. // Overrides default value with current value to make it easier
  983. // to restore previous value if the checkbox is clicked twice
  984. if (!cb.checked && value != null && value != mxConstants.NONE &&
  985. defaultColor != mxConstants.NONE)
  986. {
  987. defaultColor = value;
  988. }
  989. apply((cb.checked) ? defaultColor : mxConstants.NONE);
  990. }
  991. });
  992. apply(value, true);
  993. if (listener != null)
  994. {
  995. listener.install(apply);
  996. this.listeners.push(listener);
  997. }
  998. return div;
  999. };
  1000. /**
  1001. *
  1002. */
  1003. BaseFormatPanel.prototype.createCellColorOption = function(label, colorKey, defaultColor, callbackFn, setStyleFn, defaultColorValue)
  1004. {
  1005. var ui = this.editorUi;
  1006. var editor = ui.editor;
  1007. var graph = editor.graph;
  1008. return this.createColorOption(label, function()
  1009. {
  1010. // Seems to be null sometimes, not sure why...
  1011. var state = graph.view.getState(ui.getSelectionState().cells[0]);
  1012. if (state != null)
  1013. {
  1014. return mxUtils.getValue(state.style, colorKey, null);
  1015. }
  1016. return null;
  1017. }, function(color)
  1018. {
  1019. graph.getModel().beginUpdate();
  1020. try
  1021. {
  1022. var cells = ui.getSelectionState().cells;
  1023. graph.setCellStyles(colorKey, color, cells);
  1024. if (setStyleFn != null)
  1025. {
  1026. setStyleFn(color);
  1027. }
  1028. ui.fireEvent(new mxEventObject('styleChanged', 'keys', [colorKey],
  1029. 'values', [color], 'cells', cells));
  1030. }
  1031. finally
  1032. {
  1033. graph.getModel().endUpdate();
  1034. }
  1035. }, defaultColor || mxConstants.NONE,
  1036. {
  1037. install: function(apply)
  1038. {
  1039. this.listener = function()
  1040. {
  1041. // Seems to be null sometimes, not sure why...
  1042. var state = graph.view.getState(ui.getSelectionState().cells[0]);
  1043. if (state != null)
  1044. {
  1045. apply(mxUtils.getValue(state.style, colorKey, null), true);
  1046. }
  1047. };
  1048. graph.getModel().addListener(mxEvent.CHANGE, this.listener);
  1049. },
  1050. destroy: function()
  1051. {
  1052. graph.getModel().removeListener(this.listener);
  1053. }
  1054. }, callbackFn, null, defaultColorValue);
  1055. };
  1056. /**
  1057. *
  1058. */
  1059. BaseFormatPanel.prototype.addArrow = function(elt)
  1060. {
  1061. elt.className = 'geColorBtn';
  1062. elt.style.display = 'inline-flex';
  1063. elt.style.alignItems = 'top';
  1064. elt.style.boxSizing = 'border-box';
  1065. elt.style.width = '64px';
  1066. elt.style.height = '22px';
  1067. elt.style.borderWidth = '1px';
  1068. elt.style.borderStyle = 'solid';
  1069. elt.style.margin = '2px 2px 2px 3px';
  1070. var arrow = document.createElement('div');
  1071. arrow.className = 'geAdaptiveAsset';
  1072. arrow.style.display = 'inline-block';
  1073. arrow.style.backgroundImage = 'url(' + Editor.thinExpandImage + ')';
  1074. arrow.style.backgroundRepeat = 'no-repeat';
  1075. arrow.style.backgroundPosition = '-2px 1px';
  1076. arrow.style.backgroundSize = '18px 18px';
  1077. arrow.style.opacity = '0.5';
  1078. arrow.style.height = '100%';
  1079. arrow.style.width = '14px';
  1080. elt.appendChild(arrow);
  1081. var symbol = elt.getElementsByTagName('div')[0];
  1082. if (symbol != null)
  1083. {
  1084. symbol.style.display = 'inline-block';
  1085. symbol.style.backgroundPositionX = 'center';
  1086. symbol.style.textAlign = 'center';
  1087. symbol.style.height = '100%';
  1088. symbol.style.flexGrow = '1';
  1089. symbol.style.opacity = '0.6';
  1090. }
  1091. return symbol;
  1092. };
  1093. /**
  1094. *
  1095. */
  1096. BaseFormatPanel.prototype.addUnitInput = function(container, unit, right, width, update, step, marginTop, disableFocus, isFloat)
  1097. {
  1098. marginTop = (marginTop != null) ? marginTop : 0;
  1099. var input = document.createElement('input');
  1100. input.style.position = 'absolute';
  1101. input.style.textAlign = 'right';
  1102. input.style.marginTop = '-2px';
  1103. input.style.left = (228 - right - width) + 'px';
  1104. input.style.width = width + 'px';
  1105. input.style.height = '21px';
  1106. input.style.borderWidth = '1px';
  1107. input.style.borderStyle = 'solid';
  1108. input.style.boxSizing = 'border-box';
  1109. container.appendChild(input);
  1110. var stepper = this.createStepper(input, update, step, null, disableFocus, null, isFloat);
  1111. stepper.style.marginTop = (marginTop - 2) + 'px';
  1112. stepper.style.left = (228 - right) + 'px';
  1113. container.appendChild(stepper);
  1114. return input;
  1115. };
  1116. /**
  1117. *
  1118. */
  1119. BaseFormatPanel.prototype.addGenericInput = function(container, unit, left, width, readFn, writeFn)
  1120. {
  1121. var graph = this.editorUi.editor.graph;
  1122. var update = function()
  1123. {
  1124. writeFn(input.value);
  1125. };
  1126. var input = this.addUnitInput(container, unit, left, width, update);
  1127. var listener = mxUtils.bind(this, function(sender, evt, force)
  1128. {
  1129. if (force || input != document.activeElement)
  1130. {
  1131. input.value = readFn() + unit;
  1132. }
  1133. });
  1134. mxEvent.addListener(input, 'keydown', function(e)
  1135. {
  1136. if (e.keyCode == 13)
  1137. {
  1138. graph.container.focus();
  1139. mxEvent.consume(e);
  1140. }
  1141. else if (e.keyCode == 27)
  1142. {
  1143. listener(null, null, true);
  1144. graph.container.focus();
  1145. mxEvent.consume(e);
  1146. }
  1147. });
  1148. graph.getModel().addListener(mxEvent.CHANGE, listener);
  1149. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  1150. listener();
  1151. mxEvent.addListener(input, 'blur', update);
  1152. mxEvent.addListener(input, 'change', update);
  1153. return input;
  1154. };
  1155. /**
  1156. *
  1157. */
  1158. BaseFormatPanel.prototype.createRelativeOption = function(label, key, width, handler, init)
  1159. {
  1160. width = (width != null) ? width : 52;
  1161. var ui = this.editorUi;
  1162. var graph = ui.editor.graph;
  1163. var div = this.createPanel();
  1164. div.style.paddingTop = '10px';
  1165. div.style.paddingBottom = '12px';
  1166. mxUtils.write(div, label);
  1167. div.style.fontWeight = 'bold';
  1168. var update = mxUtils.bind(this, function(evt)
  1169. {
  1170. if (handler != null)
  1171. {
  1172. handler(input);
  1173. }
  1174. else
  1175. {
  1176. var value = parseInt(input.value);
  1177. value = Math.min(100, Math.max(0, (isNaN(value)) ? 100 : value));
  1178. var state = graph.view.getState(ui.getSelectionState().cells[0]);
  1179. if (state != null && value != mxUtils.getValue(state.style, key, 100))
  1180. {
  1181. // Removes entry in style (assumes 100 is default for relative values)
  1182. if (value == 100)
  1183. {
  1184. value = null;
  1185. }
  1186. var cells = ui.getSelectionState().cells;
  1187. graph.setCellStyles(key, value, cells);
  1188. this.editorUi.fireEvent(new mxEventObject('styleChanged', 'keys', [key],
  1189. 'values', [value], 'cells', cells));
  1190. }
  1191. input.value = ((value != null) ? value : '100') + ' %';
  1192. }
  1193. mxEvent.consume(evt);
  1194. });
  1195. var input = this.addUnitInput(div, '%', 16, width, update, 10,
  1196. (mxClient.IS_MAC && mxClient.IS_GC) ? -14 :
  1197. ((mxClient.IS_WIN) ? -16 : -15), handler != null);
  1198. if (key != null)
  1199. {
  1200. var listener = mxUtils.bind(this, function(sender, evt, force)
  1201. {
  1202. if (force || input != document.activeElement)
  1203. {
  1204. var ss = ui.getSelectionState();
  1205. var tmp = parseInt(mxUtils.getValue(ss.style, key, 100));
  1206. input.value = (isNaN(tmp)) ? '' : tmp + ' %';
  1207. }
  1208. });
  1209. mxEvent.addListener(input, 'keydown', function(e)
  1210. {
  1211. if (e.keyCode == 13)
  1212. {
  1213. graph.container.focus();
  1214. mxEvent.consume(e);
  1215. }
  1216. else if (e.keyCode == 27)
  1217. {
  1218. listener(null, null, true);
  1219. graph.container.focus();
  1220. mxEvent.consume(e);
  1221. }
  1222. });
  1223. graph.getModel().addListener(mxEvent.CHANGE, listener);
  1224. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  1225. listener();
  1226. }
  1227. mxEvent.addListener(input, 'blur', update);
  1228. mxEvent.addListener(input, 'change', update);
  1229. if (init != null)
  1230. {
  1231. init(input);
  1232. }
  1233. return div;
  1234. };
  1235. /**
  1236. *
  1237. */
  1238. BaseFormatPanel.prototype.addLabel = function(div, title, right, width)
  1239. {
  1240. width = (width != null) ? width : 61;
  1241. var label = document.createElement('div');
  1242. mxUtils.write(label, title);
  1243. label.style.position = 'absolute';
  1244. label.style.left = (240 - right - width) + 'px';
  1245. label.style.width = width + 'px';
  1246. label.style.marginTop = '6px';
  1247. label.style.display = 'flex';
  1248. label.style.justifyContent = 'center';
  1249. div.appendChild(label);
  1250. return label;
  1251. };
  1252. /**
  1253. *
  1254. */
  1255. BaseFormatPanel.prototype.addKeyHandler = function(input, listener)
  1256. {
  1257. mxEvent.addListener(input, 'keydown', mxUtils.bind(this, function(e)
  1258. {
  1259. if (e.keyCode == 13)
  1260. {
  1261. this.editorUi.editor.graph.container.focus();
  1262. mxEvent.consume(e);
  1263. }
  1264. else if (e.keyCode == 27)
  1265. {
  1266. if (listener != null)
  1267. {
  1268. listener(null, null, true);
  1269. }
  1270. this.editorUi.editor.graph.container.focus();
  1271. mxEvent.consume(e);
  1272. }
  1273. }));
  1274. };
  1275. /**
  1276. *
  1277. */
  1278. BaseFormatPanel.prototype.styleButtons = function(elts)
  1279. {
  1280. for (var i = 0; i < elts.length; i++)
  1281. {
  1282. mxUtils.setPrefixedStyle(elts[i].style, 'borderRadius', '3px');
  1283. mxUtils.setOpacity(elts[i], 100);
  1284. elts[i].style.border = '1px solid #a0a0a0';
  1285. elts[i].style.padding = '4px';
  1286. elts[i].style.paddingTop = '3px';
  1287. elts[i].style.paddingRight = '1px';
  1288. elts[i].style.margin = '1px';
  1289. elts[i].style.marginRight = '2px';
  1290. elts[i].style.width = '24px';
  1291. elts[i].style.height = '20px';
  1292. elts[i].className += ' geColorBtn';
  1293. }
  1294. };
  1295. /**
  1296. * Adds the label menu items to the given menu and parent.
  1297. */
  1298. BaseFormatPanel.prototype.destroy = function()
  1299. {
  1300. if (this.listeners != null)
  1301. {
  1302. for (var i = 0; i < this.listeners.length; i++)
  1303. {
  1304. this.listeners[i].destroy();
  1305. }
  1306. this.listeners = null;
  1307. }
  1308. };
  1309. /**
  1310. * Adds the label menu items to the given menu and parent.
  1311. */
  1312. ArrangePanel = function(format, editorUi, container)
  1313. {
  1314. BaseFormatPanel.call(this, format, editorUi, container);
  1315. this.init();
  1316. };
  1317. mxUtils.extend(ArrangePanel, BaseFormatPanel);
  1318. /**
  1319. * Adds the label menu items to the given menu and parent.
  1320. */
  1321. ArrangePanel.prototype.init = function()
  1322. {
  1323. var ss = this.editorUi.getSelectionState();
  1324. if (ss.cells.length > 0)
  1325. {
  1326. this.container.appendChild(this.addLayerOps(this.createPanel()));
  1327. // Special case that adds two panels
  1328. this.addGeometry(this.container);
  1329. this.addEdgeGeometry(this.container);
  1330. if (!ss.containsLabel || ss.edges.length == 0)
  1331. {
  1332. this.container.appendChild(this.addAngle(this.createPanel()));
  1333. }
  1334. if (!ss.containsLabel)
  1335. {
  1336. this.container.appendChild(this.addFlip(this.createPanel()));
  1337. }
  1338. this.container.appendChild(this.addAlign(this.createPanel()));
  1339. if (ss.vertices.length > 1 && !ss.cell && !ss.row)
  1340. {
  1341. this.container.appendChild(this.addDistribute(this.createPanel()));
  1342. }
  1343. this.container.appendChild(this.addTable(this.createPanel()));
  1344. }
  1345. // Allows to lock/unload button to be added
  1346. this.container.appendChild(this.addGroupOps(this.createPanel()));
  1347. if (ss.containsLabel)
  1348. {
  1349. // Adds functions from hidden style format panel
  1350. // No title required for more than one selected cell
  1351. // as no actions are added in this case
  1352. if (ss.cells.length == 1)
  1353. {
  1354. var span = document.createElement('div');
  1355. span.style.width = '100%';
  1356. span.style.marginTop = '0px';
  1357. span.style.fontWeight = 'bold';
  1358. span.style.padding = '10px 0 0 14px';
  1359. mxUtils.write(span, mxResources.get('style'));
  1360. this.container.appendChild(span);
  1361. }
  1362. new StyleFormatPanel(this.format, this.editorUi, this.container);
  1363. }
  1364. };
  1365. /**
  1366. *
  1367. */
  1368. ArrangePanel.prototype.addTable = function(div)
  1369. {
  1370. var ui = this.editorUi;
  1371. var editor = ui.editor;
  1372. var graph = editor.graph;
  1373. var ss = ui.getSelectionState();
  1374. div.style.paddingTop = '6px';
  1375. div.style.paddingBottom = '10px';
  1376. var span = document.createElement('div');
  1377. span.style.marginTop = '0px';
  1378. span.style.marginBottom = '6px';
  1379. span.style.fontWeight = 'bold';
  1380. mxUtils.write(span, mxResources.get('table'));
  1381. div.appendChild(span);
  1382. var panel = document.createElement('div');
  1383. panel.style.position = 'relative';
  1384. panel.style.paddingLeft = '0px';
  1385. panel.style.borderWidth = '0px';
  1386. panel.style.width = '220px';
  1387. panel.className = 'geToolbarContainer';
  1388. var cell = ss.vertices[0];
  1389. if (graph.getSelectionCount() > 1)
  1390. {
  1391. if (graph.isTableCell(cell))
  1392. {
  1393. cell = graph.model.getParent(cell);
  1394. }
  1395. if (graph.isTableRow(cell))
  1396. {
  1397. cell = graph.model.getParent(cell);
  1398. }
  1399. }
  1400. var isTable = ss.table || ss.row || ss.cell;
  1401. var isStack = graph.isStack(cell) ||
  1402. graph.isStackChild(cell);
  1403. var showCols = isTable;
  1404. var showRows = isTable;
  1405. if (isStack)
  1406. {
  1407. var style = (graph.isStack(cell)) ? ss.style :
  1408. graph.getCellStyle(graph.model.getParent(cell));
  1409. showRows = style['horizontalStack'] == '0';
  1410. showCols = !showRows;
  1411. }
  1412. var btns = [];
  1413. if (showCols)
  1414. {
  1415. btns = btns.concat([
  1416. ui.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'),
  1417. mxUtils.bind(this, function()
  1418. {
  1419. try
  1420. {
  1421. if (isStack)
  1422. {
  1423. graph.insertLane(cell, true);
  1424. }
  1425. else
  1426. {
  1427. graph.insertTableColumn(cell, true);
  1428. }
  1429. }
  1430. catch (e)
  1431. {
  1432. ui.handleError(e);
  1433. }
  1434. }), panel),
  1435. ui.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'),
  1436. mxUtils.bind(this, function()
  1437. {
  1438. try
  1439. {
  1440. if (isStack)
  1441. {
  1442. graph.insertLane(cell, false);
  1443. }
  1444. else
  1445. {
  1446. graph.insertTableColumn(cell, false);
  1447. }
  1448. }
  1449. catch (e)
  1450. {
  1451. ui.handleError(e);
  1452. }
  1453. }), panel),
  1454. ui.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'),
  1455. mxUtils.bind(this, function()
  1456. {
  1457. try
  1458. {
  1459. if (isStack)
  1460. {
  1461. graph.deleteLane(cell);
  1462. }
  1463. else
  1464. {
  1465. graph.deleteTableColumn(cell);
  1466. }
  1467. }
  1468. catch (e)
  1469. {
  1470. ui.handleError(e);
  1471. }
  1472. }), panel)]);
  1473. }
  1474. if (showRows)
  1475. {
  1476. btns = btns.concat([ui.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'),
  1477. mxUtils.bind(this, function()
  1478. {
  1479. try
  1480. {
  1481. if (isStack)
  1482. {
  1483. graph.insertLane(cell, true);
  1484. }
  1485. else
  1486. {
  1487. graph.insertTableRow(cell, true);
  1488. }
  1489. }
  1490. catch (e)
  1491. {
  1492. ui.handleError(e);
  1493. }
  1494. }), panel),
  1495. ui.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'),
  1496. mxUtils.bind(this, function()
  1497. {
  1498. try
  1499. {
  1500. if (isStack)
  1501. {
  1502. graph.insertLane(cell, false);
  1503. }
  1504. else
  1505. {
  1506. graph.insertTableRow(cell, false);
  1507. }
  1508. }
  1509. catch (e)
  1510. {
  1511. ui.handleError(e);
  1512. }
  1513. }), panel),
  1514. ui.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'),
  1515. mxUtils.bind(this, function()
  1516. {
  1517. try
  1518. {
  1519. if (isStack)
  1520. {
  1521. graph.deleteLane(cell);
  1522. }
  1523. else
  1524. {
  1525. graph.deleteTableRow(cell);
  1526. }
  1527. }
  1528. catch (e)
  1529. {
  1530. ui.handleError(e);
  1531. }
  1532. }), panel)]);
  1533. }
  1534. if (btns.length > 0)
  1535. {
  1536. this.styleButtons(btns);
  1537. div.appendChild(panel);
  1538. if (btns.length > 3)
  1539. {
  1540. btns[2].style.marginRight = '10px';
  1541. }
  1542. var count = 0;
  1543. if (ss.mergeCell != null)
  1544. {
  1545. count += this.addActions(div, ['mergeCells']);
  1546. }
  1547. else if (ss.style['colspan'] > 1 || ss.style['rowspan'] > 1)
  1548. {
  1549. count += this.addActions(div, ['unmergeCells']);
  1550. }
  1551. if (count > 0)
  1552. {
  1553. panel.style.paddingBottom = '2px';
  1554. }
  1555. }
  1556. else
  1557. {
  1558. div.style.display = 'none';
  1559. }
  1560. return div;
  1561. };
  1562. /**
  1563. *
  1564. */
  1565. ArrangePanel.prototype.addLayerOps = function(div)
  1566. {
  1567. this.addActions(div, ['toFront', 'toBack']);
  1568. this.addActions(div, ['bringForward', 'sendBackward']);
  1569. return div;
  1570. };
  1571. /**
  1572. *
  1573. */
  1574. ArrangePanel.prototype.addGroupOps = function(div)
  1575. {
  1576. var ui = this.editorUi;
  1577. var graph = ui.editor.graph;
  1578. var ss = ui.getSelectionState();
  1579. div.style.paddingTop = '8px';
  1580. div.style.paddingBottom = '6px';
  1581. var count = this.addActions(div, ['group', 'ungroup']) +
  1582. this.addActions(div, ['removeFromGroup']);
  1583. if (!ss.cell && !ss.row)
  1584. {
  1585. count += this.addActions(div, ['copySize', 'pasteSize', 'swap']);
  1586. }
  1587. var resetSelect = document.createElement('select');
  1588. resetSelect.style.width = '210px';
  1589. resetSelect.style.textAlign = 'center';
  1590. resetSelect.style.marginBottom = '2px';
  1591. var ops = [{label: mxResources.get('reset'), action: 'reset'},
  1592. {label: mxResources.get('waypoints'), action: 'clearWaypoints'},
  1593. {label: mxResources.get('connectionPoints'), action: 'clearAnchors'}];
  1594. for (var i = 0; i < ops.length; i++)
  1595. {
  1596. var action = this.editorUi.actions.get(ops[i].action);
  1597. if (action == null || action.enabled)
  1598. {
  1599. var option = document.createElement('option');
  1600. option.setAttribute('value', ops[i].action);
  1601. option.setAttribute('title', ops[i].label +
  1602. ((action != null && action.shortcut != null) ?
  1603. ' (' + action.shortcut + ')' : ''));
  1604. mxUtils.write(option, ops[i].label);
  1605. resetSelect.appendChild(option);
  1606. }
  1607. }
  1608. if (resetSelect.children.length > 1)
  1609. {
  1610. resetSelect.value = 'reset';
  1611. div.appendChild(resetSelect);
  1612. mxUtils.br(div);
  1613. count++;
  1614. mxEvent.addListener(resetSelect, 'change', mxUtils.bind(this, function(evt)
  1615. {
  1616. var action = this.editorUi.actions.get(resetSelect.value);
  1617. resetSelect.value = 'reset';
  1618. if (action != null)
  1619. {
  1620. action.funct();
  1621. }
  1622. }));
  1623. }
  1624. count += this.addActions(div, ['lockUnlock']);
  1625. if (ss.vertices.length == 1 && ss.edges.length == 0)
  1626. {
  1627. if (graph.getOpposites(graph.getEdges(ss.vertices[0]),
  1628. ss.vertices[0]).length > 0)
  1629. {
  1630. count += this.addActions(div, ['explore']);
  1631. }
  1632. }
  1633. if (count == 0)
  1634. {
  1635. div.style.display = 'none';
  1636. }
  1637. return div;
  1638. };
  1639. /**
  1640. *
  1641. */
  1642. ArrangePanel.prototype.addAlign = function(div)
  1643. {
  1644. var ss = this.editorUi.getSelectionState();
  1645. var graph = this.editorUi.editor.graph;
  1646. div.style.paddingTop = '6px';
  1647. div.style.paddingBottom = '8px';
  1648. div.appendChild(this.createTitle(mxResources.get('align')));
  1649. var stylePanel = document.createElement('div');
  1650. stylePanel.style.position = 'relative';
  1651. stylePanel.style.whiteSpace = 'nowrap';
  1652. stylePanel.style.paddingLeft = '0px';
  1653. stylePanel.style.paddingBottom = '2px';
  1654. stylePanel.style.borderWidth = '0px';
  1655. stylePanel.style.width = '220px';
  1656. stylePanel.className = 'geToolbarContainer';
  1657. if (ss.vertices.length > 1)
  1658. {
  1659. var left = this.editorUi.toolbar.addButton('geSprite-alignleft', mxResources.get('left'),
  1660. function() { graph.alignCells(mxConstants.ALIGN_LEFT); }, stylePanel);
  1661. var center = this.editorUi.toolbar.addButton('geSprite-aligncenter', mxResources.get('center'),
  1662. function() { graph.alignCells(mxConstants.ALIGN_CENTER); }, stylePanel);
  1663. var right = this.editorUi.toolbar.addButton('geSprite-alignright', mxResources.get('right'),
  1664. function() { graph.alignCells(mxConstants.ALIGN_RIGHT); }, stylePanel);
  1665. var top = this.editorUi.toolbar.addButton('geSprite-aligntop', mxResources.get('top'),
  1666. function() { graph.alignCells(mxConstants.ALIGN_TOP); }, stylePanel);
  1667. var middle = this.editorUi.toolbar.addButton('geSprite-alignmiddle', mxResources.get('middle'),
  1668. function() { graph.alignCells(mxConstants.ALIGN_MIDDLE); }, stylePanel);
  1669. var bottom = this.editorUi.toolbar.addButton('geSprite-alignbottom', mxResources.get('bottom'),
  1670. function() { graph.alignCells(mxConstants.ALIGN_BOTTOM); }, stylePanel);
  1671. this.styleButtons([left, center, right, top, middle, bottom]);
  1672. right.style.marginRight = '10px';
  1673. }
  1674. div.appendChild(stylePanel);
  1675. this.addActions(div, ['snapToGrid']);
  1676. return div;
  1677. };
  1678. /**
  1679. *
  1680. */
  1681. ArrangePanel.prototype.addFlip = function(div)
  1682. {
  1683. var ui = this.editorUi;
  1684. var editor = ui.editor;
  1685. var graph = editor.graph;
  1686. div.style.paddingTop = '6px';
  1687. div.style.paddingBottom = '10px';
  1688. var ss = this.editorUi.getSelectionState();
  1689. var span = document.createElement('div');
  1690. span.style.marginTop = '2px';
  1691. span.style.marginBottom = '8px';
  1692. span.style.fontWeight = 'bold';
  1693. mxUtils.write(span, mxResources.get('flip'));
  1694. div.appendChild(span);
  1695. var btn = mxUtils.button(mxResources.get('horizontal'), function(evt)
  1696. {
  1697. graph.flipCells(ss.cells, true);
  1698. })
  1699. btn.setAttribute('title', mxResources.get('horizontal'));
  1700. btn.style.width = '104px';
  1701. btn.style.marginRight = '2px';
  1702. div.appendChild(btn);
  1703. var btn = mxUtils.button(mxResources.get('vertical'), function(evt)
  1704. {
  1705. graph.flipCells(ss.cells, false);
  1706. })
  1707. btn.setAttribute('title', mxResources.get('vertical'));
  1708. btn.style.width = '104px';
  1709. div.appendChild(btn);
  1710. return div;
  1711. };
  1712. /**
  1713. *
  1714. */
  1715. ArrangePanel.prototype.addDistribute = function(div)
  1716. {
  1717. var ui = this.editorUi;
  1718. var editor = ui.editor;
  1719. var graph = editor.graph;
  1720. div.style.paddingTop = '6px';
  1721. div.style.paddingBottom = '8px';
  1722. div.appendChild(this.createTitle(mxResources.get('distribute')));
  1723. var btn = mxUtils.button(mxResources.get('horizontal'), function(evt)
  1724. {
  1725. graph.distributeCells(true, null, cb.checked);
  1726. })
  1727. btn.setAttribute('title', mxResources.get('horizontal'));
  1728. btn.style.width = '104px';
  1729. btn.style.marginRight = '2px';
  1730. div.appendChild(btn);
  1731. var btn = mxUtils.button(mxResources.get('vertical'), function(evt)
  1732. {
  1733. graph.distributeCells(false, null, cb.checked);
  1734. })
  1735. btn.setAttribute('title', mxResources.get('vertical'));
  1736. btn.style.width = '104px';
  1737. div.appendChild(btn);
  1738. mxUtils.br(div);
  1739. var panel = document.createElement('div');
  1740. panel.style.margin = '6px 0 0 0';
  1741. panel.style.display = 'flex';
  1742. panel.style.justifyContent = 'center';
  1743. panel.style.alignItems = 'center';
  1744. var cb = document.createElement('input');
  1745. cb.setAttribute('type', 'checkbox');
  1746. cb.setAttribute('id', 'spacingCheckbox');
  1747. cb.style.margin = '0 6px 0 0';
  1748. panel.appendChild(cb);
  1749. var label = document.createElement('label');
  1750. label.style.verticalAlign = 'top';
  1751. label.setAttribute('for', 'spacingCheckbox');
  1752. label.style.userSelect = 'none';
  1753. mxUtils.write(label, mxResources.get('spacing'));
  1754. panel.appendChild(label);
  1755. div.appendChild(panel);
  1756. return div;
  1757. };
  1758. /**
  1759. *
  1760. */
  1761. ArrangePanel.prototype.addAngle = function(div)
  1762. {
  1763. var ui = this.editorUi;
  1764. var editor = ui.editor;
  1765. var graph = editor.graph;
  1766. var ss = ui.getSelectionState();
  1767. div.style.paddingBottom = '12px';
  1768. var span = document.createElement('div');
  1769. span.style.position = 'absolute';
  1770. span.style.width = '70px';
  1771. span.style.marginTop = '0px';
  1772. span.style.fontWeight = 'bold';
  1773. var input = null;
  1774. var update = null;
  1775. var btn = null;
  1776. if (ss.rotatable && !ss.table && !ss.row && !ss.cell)
  1777. {
  1778. mxUtils.write(span, mxResources.get('angle'));
  1779. div.appendChild(span);
  1780. input = this.addUnitInput(div, '°', 16, 52, function()
  1781. {
  1782. update.apply(this, arguments);
  1783. });
  1784. mxUtils.br(div);
  1785. div.style.paddingTop = '10px';
  1786. }
  1787. else
  1788. {
  1789. div.style.paddingTop = '8px';
  1790. }
  1791. if (!ss.containsLabel)
  1792. {
  1793. var label = mxResources.get('reverse');
  1794. if (ss.vertices.length > 0 && ss.edges.length > 0)
  1795. {
  1796. label = mxResources.get('turn') + ' / ' + label;
  1797. }
  1798. else if (ss.vertices.length > 0)
  1799. {
  1800. label = mxResources.get('turn');
  1801. }
  1802. btn = mxUtils.button(label, function(evt)
  1803. {
  1804. ui.actions.get('turn').funct(evt);
  1805. })
  1806. btn.setAttribute('title', label + ' (' + this.editorUi.actions.get('turn').shortcut + ')');
  1807. btn.style.width = '210px';
  1808. div.appendChild(btn);
  1809. if (input != null)
  1810. {
  1811. btn.style.marginTop = '8px';
  1812. }
  1813. }
  1814. if (input != null)
  1815. {
  1816. var listener = mxUtils.bind(this, function(sender, evt, force)
  1817. {
  1818. if (force || document.activeElement != input)
  1819. {
  1820. ss = ui.getSelectionState();
  1821. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_ROTATION, 0));
  1822. input.value = (isNaN(tmp)) ? '' : tmp + '°';
  1823. }
  1824. });
  1825. update = this.installInputHandler(input, mxConstants.STYLE_ROTATION, 0, 0, 360, '°', null, true);
  1826. this.addKeyHandler(input, listener);
  1827. graph.getModel().addListener(mxEvent.CHANGE, listener);
  1828. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  1829. listener();
  1830. }
  1831. return div;
  1832. };
  1833. /**
  1834. *
  1835. */
  1836. BaseFormatPanel.prototype.getUnit = function(prefix)
  1837. {
  1838. var unit = this.editorUi.editor.graph.view.unit;
  1839. var retUnit = '';
  1840. switch(unit)
  1841. {
  1842. case mxConstants.POINTS:
  1843. retUnit = 'pt';
  1844. break;
  1845. case mxConstants.INCHES:
  1846. retUnit = '"';
  1847. break;
  1848. case mxConstants.MILLIMETERS:
  1849. retUnit = 'mm';
  1850. break;
  1851. case mxConstants.METERS:
  1852. retUnit = 'm';
  1853. }
  1854. return (prefix? prefix : '') + retUnit;
  1855. };
  1856. /**
  1857. *
  1858. */
  1859. BaseFormatPanel.prototype.inUnit = function(pixels)
  1860. {
  1861. return this.editorUi.editor.graph.view.formatUnitText(pixels);
  1862. };
  1863. /**
  1864. *
  1865. */
  1866. BaseFormatPanel.prototype.fromUnit = function(value)
  1867. {
  1868. var unit = this.editorUi.editor.graph.view.unit;
  1869. switch(unit)
  1870. {
  1871. case mxConstants.POINTS:
  1872. return value;
  1873. case mxConstants.INCHES:
  1874. return value * mxConstants.PIXELS_PER_INCH;
  1875. case mxConstants.MILLIMETERS:
  1876. return value * mxConstants.PIXELS_PER_MM;
  1877. case mxConstants.METERS:
  1878. return value * mxConstants.PIXELS_PER_MM * 1000;
  1879. }
  1880. };
  1881. BaseFormatPanel.prototype.isFloatUnit = function()
  1882. {
  1883. return this.editorUi.editor.graph.view.unit != mxConstants.POINTS;
  1884. };
  1885. /**
  1886. *
  1887. */
  1888. BaseFormatPanel.prototype.getUnitStep = function()
  1889. {
  1890. var unit = this.editorUi.editor.graph.view.unit;
  1891. switch(unit)
  1892. {
  1893. case mxConstants.POINTS:
  1894. return 1;
  1895. case mxConstants.INCHES:
  1896. return 0.1;
  1897. case mxConstants.MILLIMETERS:
  1898. return 0.5;
  1899. case mxConstants.METERS:
  1900. return 0.001;
  1901. }
  1902. };
  1903. /**
  1904. *
  1905. */
  1906. ArrangePanel.prototype.addGeometry = function(container)
  1907. {
  1908. var panel = this;
  1909. var ui = this.editorUi;
  1910. var graph = ui.editor.graph;
  1911. var model = graph.getModel();
  1912. var rect = ui.getSelectionState();
  1913. var div = this.createPanel();
  1914. div.style.paddingBottom = '8px';
  1915. var span = document.createElement('div');
  1916. span.style.position = 'absolute';
  1917. span.style.width = '50px';
  1918. span.style.marginTop = '0px';
  1919. span.style.fontWeight = 'bold';
  1920. mxUtils.write(span, mxResources.get('size'));
  1921. div.appendChild(span);
  1922. var widthUpdate, heightUpdate, leftUpdate, topUpdate;
  1923. var width = this.addUnitInput(div, this.getUnit(), 87, 52, function()
  1924. {
  1925. widthUpdate.apply(this, arguments);
  1926. }, this.getUnitStep(), null, null, this.isFloatUnit());
  1927. var height = this.addUnitInput(div, this.getUnit(), 16, 52, function()
  1928. {
  1929. heightUpdate.apply(this, arguments);
  1930. }, this.getUnitStep(), null, null, this.isFloatUnit());
  1931. var autosizeBtn = document.createElement('div');
  1932. autosizeBtn.className = 'geSprite geSprite-fit';
  1933. autosizeBtn.setAttribute('title', mxResources.get('autosize') + ' (' + this.editorUi.actions.get('autosize').shortcut + ')');
  1934. autosizeBtn.style.position = 'relative';
  1935. autosizeBtn.style.cursor = 'pointer';
  1936. autosizeBtn.style.marginTop = '-3px';
  1937. autosizeBtn.style.border = '0px';
  1938. autosizeBtn.style.left = '42px';
  1939. mxUtils.setOpacity(autosizeBtn, 50);
  1940. mxEvent.addListener(autosizeBtn, 'mouseenter', function()
  1941. {
  1942. mxUtils.setOpacity(autosizeBtn, 100);
  1943. });
  1944. mxEvent.addListener(autosizeBtn, 'mouseleave', function()
  1945. {
  1946. mxUtils.setOpacity(autosizeBtn, 50);
  1947. });
  1948. mxEvent.addListener(autosizeBtn, 'click', function()
  1949. {
  1950. ui.actions.get('autosize').funct();
  1951. });
  1952. div.appendChild(autosizeBtn);
  1953. if (rect.row)
  1954. {
  1955. width.style.visibility = 'hidden';
  1956. width.nextSibling.style.visibility = 'hidden';
  1957. }
  1958. else
  1959. {
  1960. this.addLabel(div, mxResources.get('width'), 87, 64);
  1961. }
  1962. this.addLabel(div, mxResources.get('height'), 16, 64);
  1963. mxUtils.br(div);
  1964. var wrapper = document.createElement('div');
  1965. wrapper.style.paddingTop = '8px';
  1966. wrapper.style.paddingRight = '20px';
  1967. wrapper.style.whiteSpace = 'nowrap';
  1968. wrapper.style.textAlign = 'right';
  1969. var opt = this.createCellOption(mxResources.get('constrainProportions'),
  1970. mxConstants.STYLE_ASPECT, null, 'fixed', 'null');
  1971. opt.style.width = '210px';
  1972. wrapper.appendChild(opt);
  1973. if (!rect.cell && !rect.row)
  1974. {
  1975. div.appendChild(wrapper);
  1976. }
  1977. else
  1978. {
  1979. autosizeBtn.style.visibility = 'hidden';
  1980. }
  1981. var constrainCheckbox = opt.getElementsByTagName('input')[0];
  1982. this.addKeyHandler(width, listener);
  1983. this.addKeyHandler(height, listener);
  1984. widthUpdate = this.addGeometryHandler(width, function(geo, value, cell)
  1985. {
  1986. value = Math.max(1, panel.fromUnit(value));
  1987. if (graph.isTableCell(cell))
  1988. {
  1989. graph.setTableColumnWidth(cell, value - geo.width, true);
  1990. // Blocks processing in caller
  1991. return true;
  1992. }
  1993. else if (geo.width > 0)
  1994. {
  1995. if (constrainCheckbox.checked)
  1996. {
  1997. geo.height = Math.round((geo.height * value * 100) / geo.width) / 100;
  1998. }
  1999. geo.width = value;
  2000. }
  2001. });
  2002. heightUpdate = this.addGeometryHandler(height, function(geo, value, cell)
  2003. {
  2004. value = Math.max(1, panel.fromUnit(value));
  2005. if (graph.isTableCell(cell))
  2006. {
  2007. cell = model.getParent(cell);
  2008. }
  2009. if (graph.isTableRow(cell))
  2010. {
  2011. graph.setTableRowHeight(cell, value - geo.height);
  2012. // Blocks processing in caller
  2013. return true;
  2014. }
  2015. else if (geo.height > 0)
  2016. {
  2017. if (constrainCheckbox.checked)
  2018. {
  2019. geo.width = Math.round((geo.width * value * 100) / geo.height) / 100;
  2020. }
  2021. geo.height = value;
  2022. }
  2023. });
  2024. if (rect.resizable || rect.row || rect.cell)
  2025. {
  2026. container.appendChild(div);
  2027. }
  2028. var div2 = this.createPanel();
  2029. div2.style.paddingBottom = '30px';
  2030. var span = document.createElement('div');
  2031. span.style.position = 'absolute';
  2032. span.style.width = '70px';
  2033. span.style.marginTop = '0px';
  2034. span.style.fontWeight = 'bold';
  2035. mxUtils.write(span, mxResources.get('position'));
  2036. div2.appendChild(span);
  2037. var left = this.addUnitInput(div2, this.getUnit(), 87, 52, function()
  2038. {
  2039. leftUpdate.apply(this, arguments);
  2040. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2041. var top = this.addUnitInput(div2, this.getUnit(), 16, 52, function()
  2042. {
  2043. topUpdate.apply(this, arguments);
  2044. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2045. mxUtils.br(div2);
  2046. var coordinateLabels = true;
  2047. var dx = null;
  2048. var dy = null;
  2049. if (rect.movable)
  2050. {
  2051. if (rect.edges.length == 0 && rect.vertices.length == 1)
  2052. {
  2053. var geo = graph.getCellGeometry(rect.vertices[0]);
  2054. if (geo != null && geo.relative)
  2055. {
  2056. mxUtils.br(div2);
  2057. var span = document.createElement('div');
  2058. span.style.position = 'absolute';
  2059. span.style.width = '70px';
  2060. span.style.marginTop = '0px';
  2061. mxUtils.write(span, mxResources.get('relative'));
  2062. div2.appendChild(span);
  2063. dx = this.addGenericInput(div2, ' %', 87, 52, function()
  2064. {
  2065. return (Math.round(geo.x * 1000) / 10);
  2066. }, function(value)
  2067. {
  2068. value = parseFloat(value);
  2069. if (!isNaN(value))
  2070. {
  2071. model.beginUpdate();
  2072. try
  2073. {
  2074. geo = geo.clone();
  2075. geo.x = parseFloat(value) / 100;
  2076. model.setGeometry(rect.vertices[0], geo);
  2077. }
  2078. finally
  2079. {
  2080. model.endUpdate();
  2081. }
  2082. }
  2083. });
  2084. if (model.isEdge(model.getParent(rect.vertices[0])))
  2085. {
  2086. coordinateLabels = false;
  2087. var dyUpdate = null;
  2088. dy = this.addUnitInput(div2, this.getUnit(), 16, 52, function()
  2089. {
  2090. dyUpdate.apply(this, arguments);
  2091. });
  2092. dyUpdate = this.addGeometryHandler(dy, function(geo, value)
  2093. {
  2094. geo.y = panel.fromUnit(value);
  2095. });
  2096. }
  2097. else
  2098. {
  2099. dy = this.addGenericInput(div2, ' %', 16, 52, function()
  2100. {
  2101. return (Math.round(geo.y * 1000) / 10);
  2102. }, function(value)
  2103. {
  2104. value = parseFloat(value);
  2105. if (!isNaN(value))
  2106. {
  2107. model.beginUpdate();
  2108. try
  2109. {
  2110. geo = geo.clone();
  2111. geo.y = parseFloat(value) / 100;
  2112. model.setGeometry(rect.vertices[0], geo);
  2113. }
  2114. finally
  2115. {
  2116. model.endUpdate();
  2117. }
  2118. }
  2119. });
  2120. }
  2121. mxUtils.br(div2);
  2122. }
  2123. }
  2124. container.appendChild(div2);
  2125. }
  2126. this.addLabel(div2, mxResources.get(coordinateLabels ? 'left' : 'line'), 87, 64).style.marginTop = '8px';
  2127. this.addLabel(div2, mxResources.get(coordinateLabels ? 'top' : 'orthogonal'), 16, 64).style.marginTop = '8px';
  2128. var listener = mxUtils.bind(this, function(sender, evt, force)
  2129. {
  2130. rect = ui.getSelectionState();
  2131. if (!rect.containsLabel && rect.vertices.length == graph.getSelectionCount() &&
  2132. rect.width != null && rect.height != null)
  2133. {
  2134. div.style.display = '';
  2135. if (force || document.activeElement != width)
  2136. {
  2137. width.value = this.inUnit(rect.width) + ' ' + this.getUnit();
  2138. }
  2139. if (force || document.activeElement != height)
  2140. {
  2141. height.value = this.inUnit(rect.height) + ' ' + this.getUnit();
  2142. }
  2143. }
  2144. else
  2145. {
  2146. div.style.display = 'none';
  2147. }
  2148. if (rect.vertices.length == graph.getSelectionCount() &&
  2149. rect.vertices.length > 0 && rect.x != null &&
  2150. rect.y != null)
  2151. {
  2152. var geo = graph.getCellGeometry(rect.vertices[0]);
  2153. div2.style.display = '';
  2154. if (force || document.activeElement != left)
  2155. {
  2156. left.value = this.inUnit(rect.x) + ' ' + this.getUnit();
  2157. }
  2158. if (force || document.activeElement != top)
  2159. {
  2160. top.value = this.inUnit(rect.y) + ' ' + this.getUnit();
  2161. }
  2162. if (geo != null && geo.relative)
  2163. {
  2164. if (dx != null && (force || document.activeElement != dx))
  2165. {
  2166. dx.value = (Math.round(geo.x * 1000) / 10) + ' %';
  2167. }
  2168. if (dy != null && (force || document.activeElement != dy))
  2169. {
  2170. if (model.isEdge(model.getParent(rect.vertices[0])))
  2171. {
  2172. dy.value = this.inUnit(geo.y) + ' ' + this.getUnit();
  2173. }
  2174. else
  2175. {
  2176. dy.value = (Math.round(geo.y * 1000) / 10) + ' %';
  2177. }
  2178. }
  2179. }
  2180. }
  2181. else
  2182. {
  2183. div2.style.display = 'none';
  2184. }
  2185. });
  2186. this.listeners.push({destroy: function() { model.removeListener(listener); }});
  2187. model.addListener(mxEvent.CHANGE, listener);
  2188. this.addKeyHandler(left, listener);
  2189. this.addKeyHandler(top, listener);
  2190. listener();
  2191. leftUpdate = this.addGeometryHandler(left, function(geo, value)
  2192. {
  2193. value = panel.fromUnit(value);
  2194. if (geo.relative)
  2195. {
  2196. geo.offset = (geo.offset != null) ? geo.offset : new mxPoint();
  2197. geo.offset.x = value;
  2198. }
  2199. else
  2200. {
  2201. geo.x = value;
  2202. }
  2203. });
  2204. topUpdate = this.addGeometryHandler(top, function(geo, value)
  2205. {
  2206. value = panel.fromUnit(value);
  2207. if (geo.relative)
  2208. {
  2209. geo.offset = (geo.offset != null) ? geo.offset : new mxPoint();
  2210. geo.offset.y = value;
  2211. }
  2212. else
  2213. {
  2214. geo.y = value;
  2215. }
  2216. });
  2217. if (rect.movable)
  2218. {
  2219. if (rect.edges.length == 0 && rect.vertices.length == 1 &&
  2220. model.isEdge(model.getParent(rect.vertices[0])))
  2221. {
  2222. var geo = graph.getCellGeometry(rect.vertices[0]);
  2223. if (geo != null && geo.relative)
  2224. {
  2225. var btn = mxUtils.button(mxResources.get('center'), mxUtils.bind(this, function(evt)
  2226. {
  2227. model.beginUpdate();
  2228. try
  2229. {
  2230. geo = geo.clone();
  2231. geo.x = 0;
  2232. geo.y = 0;
  2233. geo.offset = new mxPoint();
  2234. model.setGeometry(rect.vertices[0], geo);
  2235. }
  2236. finally
  2237. {
  2238. model.endUpdate();
  2239. }
  2240. }));
  2241. btn.setAttribute('title', mxResources.get('center'));
  2242. btn.style.width = '134px';
  2243. btn.style.left = '89px';
  2244. btn.style.position = 'absolute';
  2245. mxUtils.br(div2);
  2246. mxUtils.br(div2);
  2247. div2.appendChild(btn);
  2248. }
  2249. }
  2250. container.appendChild(div2);
  2251. }
  2252. };
  2253. /**
  2254. *
  2255. */
  2256. ArrangePanel.prototype.addGeometryHandler = function(input, fn)
  2257. {
  2258. var ui = this.editorUi;
  2259. var graph = ui.editor.graph;
  2260. var initialValue = null;
  2261. var panel = this;
  2262. function update(evt)
  2263. {
  2264. if (input.value != '')
  2265. {
  2266. var value = parseFloat(input.value);
  2267. if (isNaN(value))
  2268. {
  2269. input.value = initialValue + ' ' + panel.getUnit();
  2270. }
  2271. else if (value != initialValue)
  2272. {
  2273. graph.getModel().beginUpdate();
  2274. try
  2275. {
  2276. var cells = ui.getSelectionState().cells;
  2277. for (var i = 0; i < cells.length; i++)
  2278. {
  2279. if (graph.getModel().isVertex(cells[i]))
  2280. {
  2281. var geo = graph.getCellGeometry(cells[i]);
  2282. if (geo != null)
  2283. {
  2284. geo = geo.clone();
  2285. if (!fn(geo, value, cells[i]))
  2286. {
  2287. var state = graph.view.getState(cells[i]);
  2288. if (state != null && graph.isRecursiveVertexResize(state))
  2289. {
  2290. graph.resizeChildCells(cells[i], geo);
  2291. }
  2292. graph.getModel().setGeometry(cells[i], geo);
  2293. graph.constrainChildCells(cells[i]);
  2294. }
  2295. }
  2296. }
  2297. }
  2298. }
  2299. finally
  2300. {
  2301. graph.getModel().endUpdate();
  2302. }
  2303. initialValue = value;
  2304. input.value = value + ' ' + panel.getUnit();
  2305. }
  2306. }
  2307. mxEvent.consume(evt);
  2308. };
  2309. mxEvent.addListener(input, 'blur', update);
  2310. mxEvent.addListener(input, 'change', update);
  2311. mxEvent.addListener(input, 'focus', function()
  2312. {
  2313. initialValue = input.value;
  2314. });
  2315. return update;
  2316. };
  2317. ArrangePanel.prototype.addEdgeGeometryHandler = function(input, fn)
  2318. {
  2319. var ui = this.editorUi;
  2320. var graph = ui.editor.graph;
  2321. var initialValue = null;
  2322. function update(evt)
  2323. {
  2324. if (input.value != '')
  2325. {
  2326. var value = parseFloat(input.value);
  2327. if (isNaN(value))
  2328. {
  2329. input.value = initialValue + ' pt';
  2330. }
  2331. else if (value != initialValue)
  2332. {
  2333. graph.getModel().beginUpdate();
  2334. try
  2335. {
  2336. var cells = ui.getSelectionState().cells;
  2337. for (var i = 0; i < cells.length; i++)
  2338. {
  2339. if (graph.getModel().isEdge(cells[i]))
  2340. {
  2341. var geo = graph.getCellGeometry(cells[i]);
  2342. if (geo != null)
  2343. {
  2344. geo = geo.clone();
  2345. fn(geo, value);
  2346. graph.getModel().setGeometry(cells[i], geo);
  2347. }
  2348. }
  2349. }
  2350. }
  2351. finally
  2352. {
  2353. graph.getModel().endUpdate();
  2354. }
  2355. initialValue = value;
  2356. input.value = value + ' pt';
  2357. }
  2358. }
  2359. mxEvent.consume(evt);
  2360. };
  2361. mxEvent.addListener(input, 'blur', update);
  2362. mxEvent.addListener(input, 'change', update);
  2363. mxEvent.addListener(input, 'focus', function()
  2364. {
  2365. initialValue = input.value;
  2366. });
  2367. return update;
  2368. };
  2369. /**
  2370. *
  2371. */
  2372. ArrangePanel.prototype.addEdgeGeometry = function(container)
  2373. {
  2374. var panel = this;
  2375. var ui = this.editorUi;
  2376. var graph = ui.editor.graph;
  2377. var rect = ui.getSelectionState();
  2378. var div = this.createPanel();
  2379. var span = document.createElement('div');
  2380. span.style.position = 'absolute';
  2381. span.style.width = '70px';
  2382. span.style.marginTop = '0px';
  2383. span.style.fontWeight = 'bold';
  2384. mxUtils.write(span, mxResources.get('width'));
  2385. div.appendChild(span);
  2386. var widthUpdate, xtUpdate, ytUpdate, xsUpdate, ysUpdate;
  2387. var width = this.addUnitInput(div, 'pt', 12, 44, function()
  2388. {
  2389. widthUpdate.apply(this, arguments);
  2390. });
  2391. mxUtils.br(div);
  2392. this.addKeyHandler(width, listener);
  2393. var widthUpdate = mxUtils.bind(this, function(evt)
  2394. {
  2395. // Maximum stroke width is 999
  2396. var value = parseInt(width.value);
  2397. value = Math.min(999, Math.max(1, (isNaN(value)) ? 1 : value));
  2398. if (value != mxUtils.getValue(rect.style, 'width', mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth))
  2399. {
  2400. var cells = ui.getSelectionState().cells;
  2401. graph.setCellStyles('width', value, cells);
  2402. ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['width'],
  2403. 'values', [value], 'cells', cells));
  2404. }
  2405. width.value = value + ' pt';
  2406. mxEvent.consume(evt);
  2407. });
  2408. mxEvent.addListener(width, 'blur', widthUpdate);
  2409. mxEvent.addListener(width, 'change', widthUpdate);
  2410. container.appendChild(div);
  2411. var divs = this.createPanel();
  2412. divs.style.paddingBottom = '30px';
  2413. var span = document.createElement('div');
  2414. span.style.position = 'absolute';
  2415. span.style.width = '70px';
  2416. span.style.marginTop = '0px';
  2417. mxUtils.write(span, mxResources.get('linestart'));
  2418. divs.appendChild(span);
  2419. var xs = this.addUnitInput(divs, this.getUnit(), 87, 52, function()
  2420. {
  2421. xsUpdate.apply(this, arguments);
  2422. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2423. var ys = this.addUnitInput(divs, this.getUnit(), 16, 52, function()
  2424. {
  2425. ysUpdate.apply(this, arguments);
  2426. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2427. mxUtils.br(divs);
  2428. this.addLabel(divs, mxResources.get('left'), 87, 64);
  2429. this.addLabel(divs, mxResources.get('top'), 16, 64);
  2430. container.appendChild(divs);
  2431. this.addKeyHandler(xs, listener);
  2432. this.addKeyHandler(ys, listener);
  2433. var divt = this.createPanel();
  2434. divt.style.paddingBottom = '30px';
  2435. var span = document.createElement('div');
  2436. span.style.position = 'absolute';
  2437. span.style.width = '70px';
  2438. span.style.marginTop = '0px';
  2439. mxUtils.write(span, mxResources.get('lineend'));
  2440. divt.appendChild(span);
  2441. var xt = this.addUnitInput(divt, this.getUnit(), 87, 52, function()
  2442. {
  2443. xtUpdate.apply(this, arguments);
  2444. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2445. var yt = this.addUnitInput(divt, this.getUnit(), 16, 52, function()
  2446. {
  2447. ytUpdate.apply(this, arguments);
  2448. }, this.getUnitStep(), null, null, this.isFloatUnit());
  2449. mxUtils.br(divt);
  2450. this.addLabel(divt, mxResources.get('left'), 87, 64);
  2451. this.addLabel(divt, mxResources.get('top'), 16, 64);
  2452. container.appendChild(divt);
  2453. this.addKeyHandler(xt, listener);
  2454. this.addKeyHandler(yt, listener);
  2455. var listener = mxUtils.bind(this, function(sender, evt, force)
  2456. {
  2457. rect = ui.getSelectionState();
  2458. var cell = rect.cells[0];
  2459. if (rect.style.shape == 'link' || rect.style.shape == 'flexArrow')
  2460. {
  2461. div.style.display = '';
  2462. if (force || document.activeElement != width)
  2463. {
  2464. var value = mxUtils.getValue(rect.style, 'width',
  2465. mxCellRenderer.defaultShapes['flexArrow'].prototype.defaultWidth);
  2466. width.value = value + ' pt';
  2467. }
  2468. }
  2469. else
  2470. {
  2471. div.style.display = 'none';
  2472. }
  2473. if (rect.cells.length == 1 && graph.model.isEdge(cell))
  2474. {
  2475. var geo = graph.model.getGeometry(cell);
  2476. if (geo != null && geo.sourcePoint != null &&
  2477. graph.model.getTerminal(cell, true) == null)
  2478. {
  2479. xs.value = this.inUnit(geo.sourcePoint.x) + ' ' + this.getUnit();
  2480. ys.value = this.inUnit(geo.sourcePoint.y) + ' ' + this.getUnit();
  2481. }
  2482. else
  2483. {
  2484. divs.style.display = 'none';
  2485. }
  2486. if (geo != null && geo.targetPoint != null &&
  2487. graph.model.getTerminal(cell, false) == null)
  2488. {
  2489. xt.value = this.inUnit(geo.targetPoint.x) + ' ' + this.getUnit();
  2490. yt.value = this.inUnit(geo.targetPoint.y) + ' ' + this.getUnit();
  2491. }
  2492. else
  2493. {
  2494. divt.style.display = 'none';
  2495. }
  2496. }
  2497. else
  2498. {
  2499. divs.style.display = 'none';
  2500. divt.style.display = 'none';
  2501. }
  2502. });
  2503. xsUpdate = this.addEdgeGeometryHandler(xs, function(geo, value)
  2504. {
  2505. geo.sourcePoint.x = panel.fromUnit(value);
  2506. });
  2507. ysUpdate = this.addEdgeGeometryHandler(ys, function(geo, value)
  2508. {
  2509. geo.sourcePoint.y = panel.fromUnit(value);
  2510. });
  2511. xtUpdate = this.addEdgeGeometryHandler(xt, function(geo, value)
  2512. {
  2513. geo.targetPoint.x = panel.fromUnit(value);
  2514. });
  2515. ytUpdate = this.addEdgeGeometryHandler(yt, function(geo, value)
  2516. {
  2517. geo.targetPoint.y = panel.fromUnit(value);
  2518. });
  2519. graph.getModel().addListener(mxEvent.CHANGE, listener);
  2520. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  2521. listener();
  2522. };
  2523. /**
  2524. * Adds the label menu items to the given menu and parent.
  2525. */
  2526. TextFormatPanel = function(format, editorUi, container)
  2527. {
  2528. BaseFormatPanel.call(this, format, editorUi, container);
  2529. this.init();
  2530. };
  2531. mxUtils.extend(TextFormatPanel, BaseFormatPanel);
  2532. /**
  2533. * Adds the label menu items to the given menu and parent.
  2534. */
  2535. TextFormatPanel.prototype.init = function()
  2536. {
  2537. this.container.style.borderBottom = 'none';
  2538. this.addFont(this.container);
  2539. // Allows to lock/unload button to be added
  2540. this.container.appendChild(this.addFontOps(this.createPanel()));
  2541. };
  2542. /**
  2543. *
  2544. */
  2545. TextFormatPanel.prototype.addFontOps = function(div)
  2546. {
  2547. var ui = this.editorUi;
  2548. div.style.paddingTop = '8px';
  2549. div.style.paddingBottom = '6px';
  2550. var count = this.addActions(div, ['removeFormat']);
  2551. if (count == 0)
  2552. {
  2553. div.style.display = 'none';
  2554. }
  2555. return div;
  2556. };
  2557. /**
  2558. * Adds the label menu items to the given menu and parent.
  2559. */
  2560. TextFormatPanel.prototype.addFont = function(container)
  2561. {
  2562. var ui = this.editorUi;
  2563. var editor = ui.editor;
  2564. var graph = editor.graph;
  2565. var ss = ui.getSelectionState();
  2566. var title = this.createTitle(mxResources.get('font'));
  2567. title.style.paddingLeft = '14px';
  2568. title.style.paddingTop = '10px';
  2569. title.style.paddingBottom = '6px';
  2570. container.appendChild(title);
  2571. var stylePanel = this.createPanel();
  2572. stylePanel.style.paddingTop = '2px';
  2573. stylePanel.style.paddingBottom = '2px';
  2574. stylePanel.style.position = 'relative';
  2575. stylePanel.style.marginLeft = '-2px';
  2576. stylePanel.style.borderWidth = '0px';
  2577. stylePanel.className = 'geToolbarContainer';
  2578. if (graph.cellEditor.isContentEditing())
  2579. {
  2580. var cssPanel = stylePanel.cloneNode();
  2581. var cssMenu = this.editorUi.toolbar.addMenu(mxResources.get('style'),
  2582. mxResources.get('style'), true, 'formatBlock', cssPanel, null, true);
  2583. this.addArrow(cssMenu);
  2584. cssMenu.style.width = '211px';
  2585. cssMenu.style.alignItems = 'center';
  2586. cssMenu.style.justifyContent = 'center';
  2587. cssMenu.style.whiteSpace = 'nowrap';
  2588. cssMenu.style.overflow = 'hidden';
  2589. cssMenu.style.margin = '0px';
  2590. cssMenu.style.position = 'relative';
  2591. var arrow = cssMenu.getElementsByTagName('div')[0];
  2592. arrow.style.position = 'absolute';
  2593. arrow.style.right = '2px';
  2594. container.appendChild(cssPanel);
  2595. }
  2596. container.appendChild(stylePanel);
  2597. var colorPanel = this.createPanel();
  2598. colorPanel.style.marginTop = '8px';
  2599. colorPanel.style.borderWidth = '1px';
  2600. colorPanel.style.borderStyle = 'solid';
  2601. colorPanel.style.paddingTop = '6px';
  2602. colorPanel.style.paddingBottom = '2px';
  2603. var fontMenu = this.editorUi.toolbar.addMenu('Helvetica', mxResources.get('fontFamily'),
  2604. true, 'fontFamily', stylePanel, null, true);
  2605. this.addArrow(fontMenu);
  2606. fontMenu.style.width = '211px';
  2607. fontMenu.style.alignItems = 'center';
  2608. fontMenu.style.justifyContent = 'center';
  2609. fontMenu.style.whiteSpace = 'nowrap';
  2610. fontMenu.style.overflow = 'hidden';
  2611. fontMenu.style.margin = '0px';
  2612. fontMenu.style.position = 'relative';
  2613. var arrow = fontMenu.getElementsByTagName('div')[0];
  2614. arrow.style.position = 'absolute';
  2615. arrow.style.right = '2px';
  2616. var stylePanel2 = stylePanel.cloneNode(false);
  2617. stylePanel2.style.marginLeft = '-3px';
  2618. var fontStyleItems = this.editorUi.toolbar.addItems(['bold', 'italic', 'underline'], stylePanel2, true);
  2619. fontStyleItems[0].setAttribute('title', mxResources.get('bold') + ' (' + this.editorUi.actions.get('bold').shortcut + ')');
  2620. fontStyleItems[1].setAttribute('title', mxResources.get('italic') + ' (' + this.editorUi.actions.get('italic').shortcut + ')');
  2621. fontStyleItems[2].setAttribute('title', mxResources.get('underline') + ' (' + this.editorUi.actions.get('underline').shortcut + ')');
  2622. var verticalItem = this.editorUi.toolbar.addItems(['vertical'], stylePanel2, true)[0];
  2623. container.appendChild(stylePanel2);
  2624. this.styleButtons(fontStyleItems);
  2625. this.styleButtons([verticalItem]);
  2626. var stylePanel3 = stylePanel.cloneNode(false);
  2627. stylePanel3.style.marginLeft = '-3px';
  2628. stylePanel3.style.paddingBottom = '0px';
  2629. // Helper function to return a wrapper function does not pass any arguments
  2630. var callFn = function(fn)
  2631. {
  2632. return function()
  2633. {
  2634. return fn();
  2635. };
  2636. };
  2637. var left = this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'),
  2638. (graph.cellEditor.isContentEditing()) ?
  2639. function(evt)
  2640. {
  2641. graph.cellEditor.alignText(mxConstants.ALIGN_LEFT, evt);
  2642. ui.fireEvent(new mxEventObject('styleChanged',
  2643. 'keys', [mxConstants.STYLE_ALIGN],
  2644. 'values', [mxConstants.ALIGN_LEFT],
  2645. 'cells', ss.cells));
  2646. } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_LEFT])), stylePanel3);
  2647. var center = this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'),
  2648. (graph.cellEditor.isContentEditing()) ?
  2649. function(evt)
  2650. {
  2651. graph.cellEditor.alignText(mxConstants.ALIGN_CENTER, evt);
  2652. ui.fireEvent(new mxEventObject('styleChanged',
  2653. 'keys', [mxConstants.STYLE_ALIGN],
  2654. 'values', [mxConstants.ALIGN_CENTER],
  2655. 'cells', ss.cells));
  2656. } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_CENTER])), stylePanel3);
  2657. var right = this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'),
  2658. (graph.cellEditor.isContentEditing()) ?
  2659. function(evt)
  2660. {
  2661. graph.cellEditor.alignText(mxConstants.ALIGN_RIGHT, evt);
  2662. ui.fireEvent(new mxEventObject('styleChanged',
  2663. 'keys', [mxConstants.STYLE_ALIGN],
  2664. 'values', [mxConstants.ALIGN_RIGHT],
  2665. 'cells', ss.cells));
  2666. } : callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_ALIGN], [mxConstants.ALIGN_RIGHT])), stylePanel3);
  2667. this.styleButtons([left, center, right]);
  2668. // Quick hack for strikethrough
  2669. // TODO: Add translations and toggle state
  2670. if (graph.cellEditor.isContentEditing())
  2671. {
  2672. var strike = this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('strikethrough'),
  2673. function()
  2674. {
  2675. document.execCommand('strikeThrough', false, null);
  2676. }, stylePanel2);
  2677. this.styleButtons([strike]);
  2678. strike.firstChild.style.background = 'url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PGRlZnM+PHBhdGggaWQ9ImEiIGQ9Ik0wIDBoMjR2MjRIMFYweiIvPjwvZGVmcz48Y2xpcFBhdGggaWQ9ImIiPjx1c2UgeGxpbms6aHJlZj0iI2EiIG92ZXJmbG93PSJ2aXNpYmxlIi8+PC9jbGlwUGF0aD48cGF0aCBjbGlwLXBhdGg9InVybCgjYikiIGZpbGw9IiMwMTAxMDEiIGQ9Ik03LjI0IDguNzVjLS4yNi0uNDgtLjM5LTEuMDMtLjM5LTEuNjcgMC0uNjEuMTMtMS4xNi40LTEuNjcuMjYtLjUuNjMtLjkzIDEuMTEtMS4yOS40OC0uMzUgMS4wNS0uNjMgMS43LS44My42Ni0uMTkgMS4zOS0uMjkgMi4xOC0uMjkuODEgMCAxLjU0LjExIDIuMjEuMzQuNjYuMjIgMS4yMy41NCAxLjY5Ljk0LjQ3LjQuODMuODggMS4wOCAxLjQzLjI1LjU1LjM4IDEuMTUuMzggMS44MWgtMy4wMWMwLS4zMS0uMDUtLjU5LS4xNS0uODUtLjA5LS4yNy0uMjQtLjQ5LS40NC0uNjgtLjItLjE5LS40NS0uMzMtLjc1LS40NC0uMy0uMS0uNjYtLjE2LTEuMDYtLjE2LS4zOSAwLS43NC4wNC0xLjAzLjEzLS4yOS4wOS0uNTMuMjEtLjcyLjM2LS4xOS4xNi0uMzQuMzQtLjQ0LjU1LS4xLjIxLS4xNS40My0uMTUuNjYgMCAuNDguMjUuODguNzQgMS4yMS4zOC4yNS43Ny40OCAxLjQxLjdINy4zOWMtLjA1LS4wOC0uMTEtLjE3LS4xNS0uMjV6TTIxIDEydi0ySDN2Mmg5LjYyYy4xOC4wNy40LjE0LjU1LjIuMzcuMTcuNjYuMzQuODcuNTEuMjEuMTcuMzUuMzYuNDMuNTcuMDcuMi4xMS40My4xMS42OSAwIC4yMy0uMDUuNDUtLjE0LjY2LS4wOS4yLS4yMy4zOC0uNDIuNTMtLjE5LjE1LS40Mi4yNi0uNzEuMzUtLjI5LjA4LS42My4xMy0xLjAxLjEzLS40MyAwLS44My0uMDQtMS4xOC0uMTNzLS42Ni0uMjMtLjkxLS40MmMtLjI1LS4xOS0uNDUtLjQ0LS41OS0uNzUtLjE0LS4zMS0uMjUtLjc2LS4yNS0xLjIxSDYuNGMwIC41NS4wOCAxLjEzLjI0IDEuNTguMTYuNDUuMzcuODUuNjUgMS4yMS4yOC4zNS42LjY2Ljk4LjkyLjM3LjI2Ljc4LjQ4IDEuMjIuNjUuNDQuMTcuOS4zIDEuMzguMzkuNDguMDguOTYuMTMgMS40NC4xMy44IDAgMS41My0uMDkgMi4xOC0uMjhzMS4yMS0uNDUgMS42Ny0uNzljLjQ2LS4zNC44Mi0uNzcgMS4wNy0xLjI3cy4zOC0xLjA3LjM4LTEuNzFjMC0uNi0uMS0xLjE0LS4zMS0xLjYxLS4wNS0uMTEtLjExLS4yMy0uMTctLjMzSDIxeiIvPjwvc3ZnPg==)';
  2679. strike.firstChild.style.backgroundPosition = '2px 2px';
  2680. strike.firstChild.style.backgroundSize = '18px 18px';
  2681. this.styleButtons([strike]);
  2682. }
  2683. var top = this.editorUi.toolbar.addButton('geSprite-top', mxResources.get('top'),
  2684. callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
  2685. [mxConstants.ALIGN_TOP])), stylePanel3);
  2686. var middle = this.editorUi.toolbar.addButton('geSprite-middle', mxResources.get('middle'),
  2687. callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
  2688. [mxConstants.ALIGN_MIDDLE])), stylePanel3);
  2689. var bottom = this.editorUi.toolbar.addButton('geSprite-bottom', mxResources.get('bottom'),
  2690. callFn(this.editorUi.menus.createStyleChangeFunction([mxConstants.STYLE_VERTICAL_ALIGN],
  2691. [mxConstants.ALIGN_BOTTOM])), stylePanel3);
  2692. this.styleButtons([top, middle, bottom]);
  2693. container.appendChild(stylePanel3);
  2694. // Hack for updating UI state below based on current text selection
  2695. // currentTable is the current selected DOM table updated below
  2696. var sub, sup, full, tableWrapper, currentTable, tableCell, tableRow;
  2697. if (graph.cellEditor.isContentEditing())
  2698. {
  2699. top.style.display = 'none';
  2700. middle.style.display = 'none';
  2701. bottom.style.display = 'none';
  2702. verticalItem.style.display = 'none';
  2703. full = this.editorUi.toolbar.addButton('geSprite-justifyfull', mxResources.get('block'),
  2704. function()
  2705. {
  2706. if (full.style.opacity == 1)
  2707. {
  2708. document.execCommand('justifyfull', false, null);
  2709. }
  2710. }, stylePanel3);
  2711. full.style.marginRight = '9px';
  2712. full.style.opacity = 1;
  2713. this.styleButtons([full,
  2714. sub = this.editorUi.toolbar.addButton('geSprite-subscript',
  2715. mxResources.get('subscript') + ' (' + Editor.ctrlKey + '+,)',
  2716. function()
  2717. {
  2718. document.execCommand('subscript', false, null);
  2719. }, stylePanel3), sup = this.editorUi.toolbar.addButton('geSprite-superscript',
  2720. mxResources.get('superscript') + ' (' + Editor.ctrlKey + '+.)',
  2721. function()
  2722. {
  2723. document.execCommand('superscript', false, null);
  2724. }, stylePanel3)]);
  2725. sub.style.marginLeft = '10px';
  2726. var tmp = stylePanel3.cloneNode(false);
  2727. tmp.style.paddingTop = '4px';
  2728. var btns = [this.editorUi.toolbar.addButton('geSprite-orderedlist', mxResources.get('numberedList'),
  2729. function()
  2730. {
  2731. document.execCommand('insertorderedlist', false, null);
  2732. }, tmp),
  2733. this.editorUi.toolbar.addButton('geSprite-unorderedlist', mxResources.get('bulletedList'),
  2734. function()
  2735. {
  2736. document.execCommand('insertunorderedlist', false, null);
  2737. }, tmp),
  2738. this.editorUi.toolbar.addButton('geSprite-outdent', mxResources.get('decreaseIndent'),
  2739. function()
  2740. {
  2741. document.execCommand('outdent', false, null);
  2742. }, tmp),
  2743. this.editorUi.toolbar.addButton('geSprite-indent', mxResources.get('increaseIndent'),
  2744. function()
  2745. {
  2746. document.execCommand('indent', false, null);
  2747. }, tmp),
  2748. this.editorUi.toolbar.addButton('geSprite-removeformat', mxResources.get('removeFormat'),
  2749. function()
  2750. {
  2751. document.execCommand('removeformat', false, null);
  2752. }, tmp),
  2753. this.editorUi.toolbar.addButton('geSprite-code', mxResources.get('html'),
  2754. function()
  2755. {
  2756. graph.cellEditor.toggleViewMode();
  2757. }, tmp)];
  2758. this.styleButtons(btns);
  2759. btns[btns.length - 2].style.marginLeft = '10px';
  2760. container.appendChild(tmp);
  2761. }
  2762. else
  2763. {
  2764. fontStyleItems[2].style.marginRight = '12px';
  2765. right.style.marginRight = '12px';
  2766. }
  2767. // Label position
  2768. var stylePanel4 = stylePanel.cloneNode(false);
  2769. stylePanel4.removeAttribute('class');
  2770. stylePanel4.style.marginLeft = '0px';
  2771. stylePanel4.style.paddingTop = '8px';
  2772. stylePanel4.style.paddingBottom = '4px';
  2773. stylePanel4.style.fontWeight = 'normal';
  2774. mxUtils.write(stylePanel4, mxResources.get('position'));
  2775. // Adds label position options
  2776. var positionSelect = document.createElement('select');
  2777. positionSelect.style.position = 'absolute';
  2778. positionSelect.style.left = '126px';
  2779. positionSelect.style.width = '98px';
  2780. positionSelect.style.borderWidth = '1px';
  2781. positionSelect.style.borderStyle = 'solid';
  2782. positionSelect.style.marginTop = '-3px';
  2783. var directions = ['topLeft', 'top', 'topRight', 'left', 'center', 'right', 'bottomLeft', 'bottom', 'bottomRight'];
  2784. var lset = {'topLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM],
  2785. 'top': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM],
  2786. 'topRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM],
  2787. 'left': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE],
  2788. 'center': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_MIDDLE],
  2789. 'right': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_MIDDLE, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_MIDDLE],
  2790. 'bottomLeft': [mxConstants.ALIGN_LEFT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_TOP],
  2791. 'bottom': [mxConstants.ALIGN_CENTER, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_CENTER, mxConstants.ALIGN_TOP],
  2792. 'bottomRight': [mxConstants.ALIGN_RIGHT, mxConstants.ALIGN_BOTTOM, mxConstants.ALIGN_LEFT, mxConstants.ALIGN_TOP]};
  2793. for (var i = 0; i < directions.length; i++)
  2794. {
  2795. var positionOption = document.createElement('option');
  2796. positionOption.setAttribute('value', directions[i]);
  2797. mxUtils.write(positionOption, mxResources.get(directions[i]));
  2798. positionSelect.appendChild(positionOption);
  2799. }
  2800. stylePanel4.appendChild(positionSelect);
  2801. // Writing direction
  2802. var stylePanel5 = stylePanel.cloneNode(false);
  2803. stylePanel5.removeAttribute('class');
  2804. stylePanel5.style.marginLeft = '0px';
  2805. stylePanel5.style.paddingTop = '4px';
  2806. stylePanel5.style.paddingBottom = '4px';
  2807. stylePanel5.style.fontWeight = 'normal';
  2808. mxUtils.write(stylePanel5, mxResources.get('writingDirection'));
  2809. // Adds writing direction options
  2810. // LATER: Handle reselect of same option in all selects (change event
  2811. // is not fired for same option so have opened state on click) and
  2812. // handle multiple different styles for current selection
  2813. var dirSelect = document.createElement('select');
  2814. dirSelect.style.position = 'absolute';
  2815. dirSelect.style.borderWidth = '1px';
  2816. dirSelect.style.borderStyle = 'solid';
  2817. dirSelect.style.left = '126px';
  2818. dirSelect.style.width = '98px';
  2819. dirSelect.style.marginTop = '-3px';
  2820. // NOTE: For automatic we use the value null since automatic
  2821. // requires the text to be non formatted and non-wrapped
  2822. var dirs = ['automatic', 'leftToRight', 'rightToLeft'];
  2823. if (ss.html)
  2824. {
  2825. dirs.push('vertical-leftToRight');
  2826. dirs.push('vertical-rightToLeft');
  2827. }
  2828. var dirSet = {'automatic': null,
  2829. 'leftToRight': mxConstants.TEXT_DIRECTION_LTR,
  2830. 'rightToLeft': mxConstants.TEXT_DIRECTION_RTL,
  2831. 'vertical-leftToRight': mxConstants.TEXT_DIRECTION_VERTICAL_LR,
  2832. 'vertical-rightToLeft': mxConstants.TEXT_DIRECTION_VERTICAL_RL};
  2833. for (var i = 0; i < dirs.length; i++)
  2834. {
  2835. var dirOption = document.createElement('option');
  2836. dirOption.setAttribute('value', dirs[i]);
  2837. if (dirs[i].substring(0, 9) == 'vertical-')
  2838. {
  2839. mxUtils.write(dirOption, mxResources.get('vertical') +
  2840. ' (' + mxResources.get(dirs[i].substring(9)) + ')');
  2841. }
  2842. else
  2843. {
  2844. mxUtils.write(dirOption, mxResources.get(dirs[i]));
  2845. }
  2846. dirSelect.appendChild(dirOption);
  2847. }
  2848. stylePanel5.appendChild(dirSelect);
  2849. if (!graph.isEditing())
  2850. {
  2851. container.appendChild(stylePanel4);
  2852. mxEvent.addListener(positionSelect, 'change', function(evt)
  2853. {
  2854. graph.getModel().beginUpdate();
  2855. try
  2856. {
  2857. var vals = lset[positionSelect.value];
  2858. if (vals != null)
  2859. {
  2860. graph.setCellStyles(mxConstants.STYLE_LABEL_POSITION, vals[0], ss.cells);
  2861. graph.setCellStyles(mxConstants.STYLE_VERTICAL_LABEL_POSITION, vals[1], ss.cells);
  2862. graph.setCellStyles(mxConstants.STYLE_ALIGN, vals[2], ss.cells);
  2863. graph.setCellStyles(mxConstants.STYLE_VERTICAL_ALIGN, vals[3], ss.cells);
  2864. }
  2865. }
  2866. finally
  2867. {
  2868. graph.getModel().endUpdate();
  2869. }
  2870. mxEvent.consume(evt);
  2871. });
  2872. // LATER: Update dir in text editor while editing and update style with label
  2873. // NOTE: The tricky part is handling and passing on the auto value
  2874. container.appendChild(stylePanel5);
  2875. mxEvent.addListener(dirSelect, 'change', function(evt)
  2876. {
  2877. graph.setCellStyles(mxConstants.STYLE_TEXT_DIRECTION, dirSet[dirSelect.value], ss.cells);
  2878. mxEvent.consume(evt);
  2879. });
  2880. }
  2881. // Fontsize
  2882. var input = document.createElement('input');
  2883. input.style.position = 'absolute';
  2884. input.style.borderWidth = '1px';
  2885. input.style.borderStyle = 'solid';
  2886. input.style.textAlign = 'right';
  2887. input.style.marginTop = '4px';
  2888. input.style.left = '161px';
  2889. input.style.width = '53px';
  2890. input.style.height = '23px';
  2891. input.style.boxSizing = 'border-box';
  2892. stylePanel2.appendChild(input);
  2893. // Workaround for font size 4 if no text is selected is update font size below
  2894. // after first character was entered (as the font element is lazy created)
  2895. var pendingFontSize = null;
  2896. var inputUpdate = this.installInputHandler(input, mxConstants.STYLE_FONTSIZE,
  2897. Menus.prototype.defaultFontSize, 1, 999, ' ' + Editor.fontSizeUnit, function(fontSize)
  2898. {
  2899. // IE does not support containsNode
  2900. // KNOWN: Fixes font size issues but bypasses undo
  2901. if (window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11)
  2902. {
  2903. var selection = window.getSelection();
  2904. var container = (selection.rangeCount > 0) ? selection.getRangeAt(0).commonAncestorContainer :
  2905. graph.cellEditor.textarea;
  2906. function updateSize(elt, ignoreContains)
  2907. {
  2908. if (graph.cellEditor.textarea != null && elt != graph.cellEditor.textarea &&
  2909. graph.cellEditor.textarea.contains(elt) &&
  2910. (ignoreContains || selection.containsNode(elt, true)))
  2911. {
  2912. if (elt.nodeName == 'FONT')
  2913. {
  2914. elt.removeAttribute('size');
  2915. elt.style.fontSize = fontSize + 'px';
  2916. }
  2917. else
  2918. {
  2919. var css = mxUtils.getCurrentStyle(elt);
  2920. if (css.fontSize != fontSize + 'px')
  2921. {
  2922. if (mxUtils.getCurrentStyle(elt.parentNode).fontSize != fontSize + 'px')
  2923. {
  2924. elt.style.fontSize = fontSize + 'px';
  2925. }
  2926. else
  2927. {
  2928. elt.style.fontSize = '';
  2929. }
  2930. }
  2931. }
  2932. }
  2933. ui.fireEvent(new mxEventObject('styleChanged',
  2934. 'keys', [mxConstants.STYLE_FONTSIZE],
  2935. 'values', [fontSize], 'cells', ss.cells));
  2936. };
  2937. // Wraps text node or mixed selection with leading text in a font element
  2938. if (container == graph.cellEditor.textarea ||
  2939. container.nodeType != mxConstants.NODETYPE_ELEMENT)
  2940. {
  2941. document.execCommand('fontSize', false, '1');
  2942. }
  2943. if (container != graph.cellEditor.textarea)
  2944. {
  2945. container = container.parentNode;
  2946. }
  2947. if (container != null && container.nodeType == mxConstants.NODETYPE_ELEMENT)
  2948. {
  2949. var elts = container.getElementsByTagName('*');
  2950. updateSize(container);
  2951. for (var i = 0; i < elts.length; i++)
  2952. {
  2953. updateSize(elts[i]);
  2954. }
  2955. // Handles font element inserted before selection text
  2956. if (selection.rangeCount > 0)
  2957. {
  2958. var container = selection.getRangeAt(0).commonAncestorContainer;
  2959. if (container != graph.cellEditor.textarea &&
  2960. graph.cellEditor.textarea.contains(container))
  2961. {
  2962. updateSize(container.parentNode);
  2963. }
  2964. }
  2965. }
  2966. input.value = fontSize + ' ' + Editor.fontSizeUnit;
  2967. }
  2968. else if (window.getSelection || document.selection)
  2969. {
  2970. // Checks selection
  2971. var par = null;
  2972. if (document.selection)
  2973. {
  2974. par = document.selection.createRange().parentElement();
  2975. }
  2976. else
  2977. {
  2978. var selection = window.getSelection();
  2979. if (selection.rangeCount > 0)
  2980. {
  2981. par = selection.getRangeAt(0).commonAncestorContainer;
  2982. }
  2983. }
  2984. // Node.contains does not work for text nodes in IE11
  2985. function isOrContains(container, node)
  2986. {
  2987. while (node != null)
  2988. {
  2989. if (node === container)
  2990. {
  2991. return true;
  2992. }
  2993. node = node.parentNode;
  2994. }
  2995. return false;
  2996. };
  2997. if (par != null && isOrContains(graph.cellEditor.textarea, par))
  2998. {
  2999. pendingFontSize = fontSize;
  3000. // Workaround for can't set font size in px is to change font size afterwards
  3001. document.execCommand('fontSize', false, '4');
  3002. var elts = graph.cellEditor.textarea.getElementsByTagName('font');
  3003. for (var i = 0; i < elts.length; i++)
  3004. {
  3005. if (elts[i].getAttribute('size') == '4')
  3006. {
  3007. elts[i].removeAttribute('size');
  3008. elts[i].style.fontSize = pendingFontSize + 'px';
  3009. // Overrides fontSize in input with the one just assigned as a workaround
  3010. // for potential fontSize values of parent elements that don't match
  3011. window.setTimeout(function()
  3012. {
  3013. input.value = pendingFontSize + ' ' + Editor.fontSizeUnit;
  3014. pendingFontSize = null;
  3015. }, 0);
  3016. break;
  3017. }
  3018. }
  3019. }
  3020. }
  3021. }, true);
  3022. var stepper = this.createStepper(input, inputUpdate, 1, 10, true, Menus.prototype.defaultFontSize);
  3023. stepper.style.display = input.style.display;
  3024. stepper.style.marginTop = '4px';
  3025. stepper.style.left = '214px';
  3026. stylePanel2.appendChild(stepper);
  3027. var arrow = fontMenu.getElementsByTagName('div')[0];
  3028. arrow.style.cssFloat = 'right';
  3029. var bgColorApply = null;
  3030. var currentBgColor = graph.shapeBackgroundColor;
  3031. var fontColorApply = null;
  3032. var currentFontColor = graph.shapeForegroundColor;
  3033. var bgPanel = (graph.cellEditor.isContentEditing()) ? this.createColorOption(mxResources.get('backgroundColor'), function()
  3034. {
  3035. return currentBgColor;
  3036. }, function(color)
  3037. {
  3038. document.execCommand('backcolor', false, (color != mxConstants.NONE) ? color : 'transparent');
  3039. ui.fireEvent(new mxEventObject('styleChanged',
  3040. 'keys', [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR],
  3041. 'values', [color], 'cells', ss.cells));
  3042. }, graph.shapeBackgroundColor,
  3043. {
  3044. install: function(apply) { bgColorApply = apply; },
  3045. destroy: function() { bgColorApply = null; }
  3046. }, null, true) : this.createCellColorOption(mxResources.get('backgroundColor'),
  3047. mxConstants.STYLE_LABEL_BACKGROUNDCOLOR, 'default', null, function(color)
  3048. {
  3049. graph.updateLabelElements(ss.cells, function(elt)
  3050. {
  3051. elt.style.backgroundColor = null;
  3052. });
  3053. }, graph.shapeBackgroundColor);
  3054. bgPanel.style.fontWeight = 'bold';
  3055. var borderPanel = this.createCellColorOption(mxResources.get('borderColor'),
  3056. mxConstants.STYLE_LABEL_BORDERCOLOR, 'default', null, null,
  3057. graph.shapeForegroundColor);
  3058. borderPanel.style.fontWeight = 'bold';
  3059. var defs = (ss.vertices.length >= 1) ?
  3060. graph.stylesheet.getDefaultVertexStyle() :
  3061. graph.stylesheet.getDefaultEdgeStyle();
  3062. var panel = (graph.cellEditor.isContentEditing()) ?
  3063. this.createColorOption(mxResources.get('fontColor'),
  3064. function()
  3065. {
  3066. return currentFontColor;
  3067. }, function(color)
  3068. {
  3069. if (mxClient.IS_FF)
  3070. {
  3071. // Workaround for Firefox that adds the font element around
  3072. // anchor elements which ignore inherited colors is to move
  3073. // the font element inside anchor elements
  3074. var tmp = graph.cellEditor.textarea.getElementsByTagName('font');
  3075. var oldFonts = [];
  3076. for (var i = 0; i < tmp.length; i++)
  3077. {
  3078. oldFonts.push(
  3079. {
  3080. node: tmp[i],
  3081. color: tmp[i].getAttribute('color')
  3082. });
  3083. }
  3084. document.execCommand('forecolor', false, (color != mxConstants.NONE) ?
  3085. color : 'transparent');
  3086. ui.fireEvent(new mxEventObject('styleChanged',
  3087. 'keys', [mxConstants.STYLE_FONTCOLOR],
  3088. 'values', [color], 'cells', ss.cells));
  3089. // Finds the new or changed font element
  3090. var newFonts = graph.cellEditor.textarea.getElementsByTagName('font');
  3091. for (var i = 0; i < newFonts.length; i++)
  3092. {
  3093. if (i >= oldFonts.length || newFonts[i] != oldFonts[i].node ||
  3094. (newFonts[i] == oldFonts[i].node &&
  3095. newFonts[i].getAttribute('color') != oldFonts[i].color))
  3096. {
  3097. var child = newFonts[i].firstChild;
  3098. // Moves the font element to inside the anchor element and adopts all children
  3099. if (child != null && child.nodeName == 'A' &&
  3100. child.nextSibling == null &&
  3101. child.firstChild != null)
  3102. {
  3103. var parent = newFonts[i].parentNode;
  3104. parent.insertBefore(child, newFonts[i]);
  3105. var tmp = child.firstChild;
  3106. while (tmp != null)
  3107. {
  3108. var next = tmp.nextSibling;
  3109. newFonts[i].appendChild(tmp);
  3110. tmp = next;
  3111. }
  3112. child.appendChild(newFonts[i]);
  3113. }
  3114. break;
  3115. }
  3116. }
  3117. }
  3118. else
  3119. {
  3120. document.execCommand('forecolor', false,
  3121. (color != mxConstants.NONE) ?
  3122. color : 'transparent');
  3123. ui.fireEvent(new mxEventObject('styleChanged',
  3124. 'keys', [mxConstants.STYLE_FONTCOLOR],
  3125. 'values', [color], 'cells', ss.cells));
  3126. }
  3127. }, (defs[mxConstants.STYLE_FONTCOLOR] != null) ?
  3128. defs[mxConstants.STYLE_FONTCOLOR] : graph.shapeForegroundColor,
  3129. {
  3130. install: function(apply) { fontColorApply = apply; },
  3131. destroy: function() { fontColorApply = null; }
  3132. }, null, true) : this.createCellColorOption(mxResources.get('fontColor'),
  3133. mxConstants.STYLE_FONTCOLOR, 'default', function(color)
  3134. {
  3135. if (color == mxConstants.NONE)
  3136. {
  3137. bgPanel.style.display = 'none';
  3138. }
  3139. else
  3140. {
  3141. bgPanel.style.display = '';
  3142. }
  3143. borderPanel.style.display = bgPanel.style.display;
  3144. }, function(color)
  3145. {
  3146. if (color == mxConstants.NONE)
  3147. {
  3148. graph.setCellStyles(mxConstants.STYLE_NOLABEL, '1', ss.cells);
  3149. }
  3150. else
  3151. {
  3152. graph.setCellStyles(mxConstants.STYLE_NOLABEL, null, ss.cells);
  3153. }
  3154. graph.setCellStyles(mxConstants.STYLE_FONTCOLOR, color, ss.cells);
  3155. graph.updateLabelElements(ss.cells, function(elt)
  3156. {
  3157. elt.removeAttribute('color');
  3158. elt.style.color = null;
  3159. });
  3160. }, graph.shapeForegroundColor);
  3161. panel.style.fontWeight = 'bold';
  3162. colorPanel.appendChild(panel);
  3163. colorPanel.appendChild(bgPanel);
  3164. var textShadow = this.createCellOption(mxResources.get('shadow'),
  3165. mxConstants.STYLE_TEXT_SHADOW, 0);
  3166. textShadow.style.width = '100%';
  3167. textShadow.style.fontWeight = 'bold';
  3168. if (!Editor.enableShadowOption)
  3169. {
  3170. textShadow.getElementsByTagName('input')[0].setAttribute('disabled', 'disabled');
  3171. mxUtils.setOpacity(textShadow, 60);
  3172. }
  3173. if (!graph.cellEditor.isContentEditing())
  3174. {
  3175. colorPanel.appendChild(borderPanel);
  3176. colorPanel.appendChild(textShadow);
  3177. }
  3178. container.appendChild(colorPanel);
  3179. var extraPanel = this.createPanel();
  3180. extraPanel.style.paddingTop = '2px';
  3181. extraPanel.style.paddingBottom = '4px';
  3182. var wwCells = graph.filterSelectionCells(mxUtils.bind(this, function(cell)
  3183. {
  3184. var state = graph.view.getState(cell);
  3185. return state == null || graph.isAutoSizeState(state) ||
  3186. graph.getModel().isEdge(cell) || (!graph.isTableRow(cell) &&
  3187. !graph.isTableCell(cell) && !graph.isCellResizable(cell));
  3188. }));
  3189. var wwOpt = this.createCellOption(mxResources.get('wordWrap'), mxConstants.STYLE_WHITE_SPACE,
  3190. null, 'wrap', 'null', null, null, true, wwCells);
  3191. wwOpt.style.fontWeight = 'bold';
  3192. // Word wrap in edge labels only supported via labelWidth style
  3193. if (wwCells.length > 0)
  3194. {
  3195. extraPanel.appendChild(wwOpt);
  3196. }
  3197. // Delegates switch of style to formattedText action as it also convertes newlines
  3198. var htmlOpt = this.createCellOption(mxResources.get('formattedText'), 'html', 0,
  3199. null, null, null, ui.actions.get('formattedText'));
  3200. htmlOpt.style.fontWeight = 'bold';
  3201. extraPanel.appendChild(htmlOpt);
  3202. var spacingPanel = this.createPanel();
  3203. spacingPanel.style.paddingTop = '10px';
  3204. spacingPanel.style.paddingBottom = '28px';
  3205. spacingPanel.style.fontWeight = 'normal';
  3206. var span = document.createElement('div');
  3207. span.style.position = 'absolute';
  3208. span.style.width = '70px';
  3209. span.style.marginTop = '0px';
  3210. span.style.fontWeight = 'bold';
  3211. mxUtils.write(span, mxResources.get('spacing'));
  3212. spacingPanel.appendChild(span);
  3213. var topUpdate, globalUpdate, leftUpdate, bottomUpdate, rightUpdate;
  3214. var topSpacing = this.addUnitInput(spacingPanel, this.getUnit(), 87, 52, function()
  3215. {
  3216. topUpdate.apply(this, arguments);
  3217. }, this.getUnitStep(), null, null, this.isFloatUnit());
  3218. var globalSpacing = this.addUnitInput(spacingPanel, this.getUnit(), 16, 52, function()
  3219. {
  3220. globalUpdate.apply(this, arguments);
  3221. }, this.getUnitStep(), null, null, this.isFloatUnit());
  3222. mxUtils.br(spacingPanel);
  3223. this.addLabel(spacingPanel, mxResources.get('top'), 87, 64);
  3224. this.addLabel(spacingPanel, mxResources.get('global'), 16, 64);
  3225. mxUtils.br(spacingPanel);
  3226. mxUtils.br(spacingPanel);
  3227. var leftSpacing = this.addUnitInput(spacingPanel, this.getUnit(), 158, 52, function()
  3228. {
  3229. leftUpdate.apply(this, arguments);
  3230. }, this.getUnitStep(), null, null, this.isFloatUnit());
  3231. var bottomSpacing = this.addUnitInput(spacingPanel, this.getUnit(), 87, 52, function()
  3232. {
  3233. bottomUpdate.apply(this, arguments);
  3234. }, this.getUnitStep(), null, null, this.isFloatUnit());
  3235. var rightSpacing = this.addUnitInput(spacingPanel, this.getUnit(), 16, 52, function()
  3236. {
  3237. rightUpdate.apply(this, arguments);
  3238. }, this.getUnitStep(), null, null, this.isFloatUnit());
  3239. mxUtils.br(spacingPanel);
  3240. this.addLabel(spacingPanel, mxResources.get('left'), 158, 64);
  3241. this.addLabel(spacingPanel, mxResources.get('bottom'), 87, 64);
  3242. this.addLabel(spacingPanel, mxResources.get('right'), 16, 64);
  3243. if (!graph.cellEditor.isContentEditing())
  3244. {
  3245. container.appendChild(extraPanel);
  3246. container.appendChild(this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_TEXT_OPACITY));
  3247. container.appendChild(spacingPanel);
  3248. }
  3249. else
  3250. {
  3251. var selState = null;
  3252. var lineHeightInput = null;
  3253. container.appendChild(this.createRelativeOption(mxResources.get('lineheight'), null, null, function(input)
  3254. {
  3255. var value = (input.value == '') ? 120 : parseInt(input.value);
  3256. value = Math.max(0, (isNaN(value)) ? 120 : value);
  3257. if (selState != null)
  3258. {
  3259. graph.cellEditor.restoreSelection(selState);
  3260. selState = null;
  3261. }
  3262. var blocks = graph.getSelectedTextBlocks();
  3263. // Adds paragraph tags if no block element is selected
  3264. if (blocks.length == 0 && graph.cellEditor.textarea != null &&
  3265. graph.cellEditor.textarea.firstChild != null)
  3266. {
  3267. if (graph.cellEditor.textarea.firstChild.nodeName != 'P')
  3268. {
  3269. graph.cellEditor.textarea.innerHTML = '<p>' + graph.cellEditor.textarea.innerHTML + '</p>';
  3270. }
  3271. blocks = [graph.cellEditor.textarea.firstChild];
  3272. }
  3273. for (var i = 0; i < blocks.length; i++)
  3274. {
  3275. blocks[i].style.lineHeight = value + '%';
  3276. }
  3277. input.value = value + ' %';
  3278. }, function(input)
  3279. {
  3280. // Used in CSS handler to update current value
  3281. lineHeightInput = input;
  3282. // KNOWN: Arrow up/down clear selection text in quirks/IE 8
  3283. // Text size via arrow button limits to 16 in IE11. Why?
  3284. mxEvent.addListener(input, 'mousedown', function()
  3285. {
  3286. if (document.activeElement == graph.cellEditor.textarea)
  3287. {
  3288. selState = graph.cellEditor.saveSelection();
  3289. }
  3290. });
  3291. mxEvent.addListener(input, 'touchstart', function()
  3292. {
  3293. if (document.activeElement == graph.cellEditor.textarea)
  3294. {
  3295. selState = graph.cellEditor.saveSelection();
  3296. }
  3297. });
  3298. input.value = '120 %';
  3299. }));
  3300. var insertPanel = stylePanel.cloneNode(false);
  3301. insertPanel.style.paddingLeft = '0px';
  3302. var insertBtns = this.editorUi.toolbar.addItems(['link', 'image'], insertPanel, true);
  3303. var btns = [
  3304. this.editorUi.toolbar.addButton('geSprite-horizontalrule', mxResources.get('insertHorizontalRule'),
  3305. function()
  3306. {
  3307. document.execCommand('inserthorizontalrule', false);
  3308. }, insertPanel),
  3309. this.editorUi.toolbar.addMenuFunctionInContainer(insertPanel, 'geSprite-table', mxResources.get('table'), false, mxUtils.bind(this, function(menu)
  3310. {
  3311. this.editorUi.menus.addInsertTableItem(menu, null, null, false);
  3312. }))];
  3313. this.styleButtons(insertBtns);
  3314. this.styleButtons(btns);
  3315. var wrapper2 = this.createPanel();
  3316. wrapper2.style.paddingTop = '10px';
  3317. wrapper2.style.paddingBottom = '10px';
  3318. wrapper2.appendChild(this.createTitle(mxResources.get('insert')));
  3319. wrapper2.appendChild(insertPanel);
  3320. container.appendChild(wrapper2);
  3321. var tablePanel = stylePanel.cloneNode(false);
  3322. tablePanel.style.paddingLeft = '0px';
  3323. var btns = [
  3324. this.editorUi.toolbar.addButton('geSprite-insertcolumnbefore', mxResources.get('insertColumnBefore'),
  3325. mxUtils.bind(this, function()
  3326. {
  3327. try
  3328. {
  3329. if (currentTable != null)
  3330. {
  3331. graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex : 0);
  3332. }
  3333. }
  3334. catch (e)
  3335. {
  3336. this.editorUi.handleError(e);
  3337. }
  3338. }), tablePanel),
  3339. this.editorUi.toolbar.addButton('geSprite-insertcolumnafter', mxResources.get('insertColumnAfter'),
  3340. mxUtils.bind(this, function()
  3341. {
  3342. try
  3343. {
  3344. if (currentTable != null)
  3345. {
  3346. graph.insertColumn(currentTable, (tableCell != null) ? tableCell.cellIndex + 1 : -1);
  3347. }
  3348. }
  3349. catch (e)
  3350. {
  3351. this.editorUi.handleError(e);
  3352. }
  3353. }), tablePanel),
  3354. this.editorUi.toolbar.addButton('geSprite-deletecolumn', mxResources.get('deleteColumn'),
  3355. mxUtils.bind(this, function()
  3356. {
  3357. try
  3358. {
  3359. if (currentTable != null && tableCell != null)
  3360. {
  3361. graph.deleteColumn(currentTable, tableCell.cellIndex);
  3362. }
  3363. }
  3364. catch (e)
  3365. {
  3366. this.editorUi.handleError(e);
  3367. }
  3368. }), tablePanel),
  3369. this.editorUi.toolbar.addButton('geSprite-insertrowbefore', mxResources.get('insertRowBefore'),
  3370. mxUtils.bind(this, function()
  3371. {
  3372. try
  3373. {
  3374. if (currentTable != null && tableRow != null)
  3375. {
  3376. graph.insertRow(currentTable, tableRow.sectionRowIndex);
  3377. }
  3378. }
  3379. catch (e)
  3380. {
  3381. this.editorUi.handleError(e);
  3382. }
  3383. }), tablePanel),
  3384. this.editorUi.toolbar.addButton('geSprite-insertrowafter', mxResources.get('insertRowAfter'),
  3385. mxUtils.bind(this, function()
  3386. {
  3387. try
  3388. {
  3389. if (currentTable != null && tableRow != null)
  3390. {
  3391. graph.insertRow(currentTable, tableRow.sectionRowIndex + 1);
  3392. }
  3393. }
  3394. catch (e)
  3395. {
  3396. this.editorUi.handleError(e);
  3397. }
  3398. }), tablePanel),
  3399. this.editorUi.toolbar.addButton('geSprite-deleterow', mxResources.get('deleteRow'),
  3400. mxUtils.bind(this, function()
  3401. {
  3402. try
  3403. {
  3404. if (currentTable != null && tableRow != null)
  3405. {
  3406. graph.deleteRow(currentTable, tableRow.sectionRowIndex);
  3407. }
  3408. }
  3409. catch (e)
  3410. {
  3411. this.editorUi.handleError(e);
  3412. }
  3413. }), tablePanel)];
  3414. this.styleButtons(btns);
  3415. btns[2].style.marginRight = '10px';
  3416. var wrapper3 = this.createPanel();
  3417. wrapper3.style.paddingTop = '10px';
  3418. wrapper3.style.paddingBottom = '10px';
  3419. wrapper3.appendChild(this.createTitle(mxResources.get('table')));
  3420. wrapper3.appendChild(tablePanel);
  3421. var tablePanel2 = stylePanel.cloneNode(false);
  3422. tablePanel2.style.paddingLeft = '0px';
  3423. var btns = [
  3424. this.editorUi.toolbar.addButton('geSprite-strokecolor', mxResources.get('borderColor'),
  3425. mxUtils.bind(this, function(evt)
  3426. {
  3427. if (currentTable != null)
  3428. {
  3429. // Converts rgb(r,g,b) values
  3430. var color = currentTable.style.borderColor.replace(
  3431. /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
  3432. function($0, $1, $2, $3) {
  3433. return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
  3434. });
  3435. this.editorUi.pickColor(color, function(newColor)
  3436. {
  3437. var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable;
  3438. graph.processElements(targetElt, function(elt)
  3439. {
  3440. elt.style.border = null;
  3441. });
  3442. if (newColor == null || newColor == mxConstants.NONE)
  3443. {
  3444. targetElt.removeAttribute('border');
  3445. targetElt.style.border = '';
  3446. targetElt.style.borderCollapse = '';
  3447. }
  3448. else
  3449. {
  3450. targetElt.setAttribute('border', '1');
  3451. targetElt.style.border = '1px solid ' + newColor;
  3452. targetElt.style.borderCollapse = 'collapse';
  3453. }
  3454. });
  3455. }
  3456. }), tablePanel2),
  3457. this.editorUi.toolbar.addButton('geSprite-fillcolor', mxResources.get('backgroundColor'),
  3458. mxUtils.bind(this, function(evt)
  3459. {
  3460. // Converts rgb(r,g,b) values
  3461. if (currentTable != null)
  3462. {
  3463. var color = currentTable.style.backgroundColor.replace(
  3464. /\brgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/g,
  3465. function($0, $1, $2, $3) {
  3466. return "#" + ("0"+Number($1).toString(16)).substr(-2) + ("0"+Number($2).toString(16)).substr(-2) + ("0"+Number($3).toString(16)).substr(-2);
  3467. });
  3468. this.editorUi.pickColor(color, function(newColor)
  3469. {
  3470. var targetElt = (tableCell != null && (evt == null || !mxEvent.isShiftDown(evt))) ? tableCell : currentTable;
  3471. graph.processElements(targetElt, function(elt)
  3472. {
  3473. elt.style.backgroundColor = null;
  3474. });
  3475. if (newColor == null || newColor == mxConstants.NONE)
  3476. {
  3477. targetElt.style.backgroundColor = '';
  3478. }
  3479. else
  3480. {
  3481. targetElt.style.backgroundColor = newColor;
  3482. }
  3483. });
  3484. }
  3485. }), tablePanel2),
  3486. this.editorUi.toolbar.addButton('geSprite-fit', mxResources.get('spacing'),
  3487. function()
  3488. {
  3489. if (currentTable != null)
  3490. {
  3491. var value = currentTable.getAttribute('cellPadding') || 0;
  3492. var dlg = new FilenameDialog(ui, value, mxResources.get('apply'),
  3493. mxUtils.bind(this, function(newValue)
  3494. {
  3495. if (newValue != null && newValue.length > 0)
  3496. {
  3497. currentTable.setAttribute('cellPadding', newValue);
  3498. }
  3499. else
  3500. {
  3501. currentTable.removeAttribute('cellPadding');
  3502. }
  3503. }), mxResources.get('spacing'));
  3504. ui.showDialog(dlg.container, 300, 80, true, true);
  3505. dlg.init();
  3506. }
  3507. }, tablePanel2),
  3508. this.editorUi.toolbar.addButton('geSprite-left', mxResources.get('left'),
  3509. function()
  3510. {
  3511. if (currentTable != null)
  3512. {
  3513. currentTable.setAttribute('align', 'left');
  3514. }
  3515. }, tablePanel2),
  3516. this.editorUi.toolbar.addButton('geSprite-center', mxResources.get('center'),
  3517. function()
  3518. {
  3519. if (currentTable != null)
  3520. {
  3521. currentTable.setAttribute('align', 'center');
  3522. }
  3523. }, tablePanel2),
  3524. this.editorUi.toolbar.addButton('geSprite-right', mxResources.get('right'),
  3525. function()
  3526. {
  3527. if (currentTable != null)
  3528. {
  3529. currentTable.setAttribute('align', 'right');
  3530. }
  3531. }, tablePanel2)];
  3532. this.styleButtons(btns);
  3533. btns[2].style.marginRight = '10px';
  3534. wrapper3.appendChild(tablePanel2);
  3535. container.appendChild(wrapper3);
  3536. tableWrapper = wrapper3;
  3537. }
  3538. function setSelected(elt, selected)
  3539. {
  3540. elt.style.backgroundImage = (selected) ? (Editor.isDarkMode() ?
  3541. 'linear-gradient(rgb(0 161 241) 0px, rgb(0, 97, 146) 100%)':
  3542. 'linear-gradient(#c5ecff 0px,#87d4fb 100%)') : '';
  3543. };
  3544. // Updates font style state before typing
  3545. for (var i = 0; i < 3; i++)
  3546. {
  3547. (function(index)
  3548. {
  3549. mxEvent.addListener(fontStyleItems[index], 'click', function()
  3550. {
  3551. setSelected(fontStyleItems[index], fontStyleItems[index].style.backgroundImage == '');
  3552. });
  3553. })(i);
  3554. }
  3555. var listener = mxUtils.bind(this, function(sender, evt, force)
  3556. {
  3557. ss = ui.getSelectionState();
  3558. var fontStyle = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSTYLE, 0);
  3559. setSelected(fontStyleItems[0], (fontStyle & mxConstants.FONT_BOLD) == mxConstants.FONT_BOLD);
  3560. setSelected(fontStyleItems[1], (fontStyle & mxConstants.FONT_ITALIC) == mxConstants.FONT_ITALIC);
  3561. setSelected(fontStyleItems[2], (fontStyle & mxConstants.FONT_UNDERLINE) == mxConstants.FONT_UNDERLINE);
  3562. fontMenu.firstChild.nodeValue = mxUtils.getValue(ss.style, mxConstants.STYLE_FONTFAMILY, Menus.prototype.defaultFont);
  3563. setSelected(verticalItem, mxUtils.getValue(ss.style, mxConstants.STYLE_HORIZONTAL, '1') == '0');
  3564. if (force || document.activeElement != input)
  3565. {
  3566. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_FONTSIZE, Menus.prototype.defaultFontSize));
  3567. input.value = (isNaN(tmp)) ? '' : tmp + ' ' + Editor.fontSizeUnit;
  3568. }
  3569. var align = mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
  3570. setSelected(left, align == mxConstants.ALIGN_LEFT);
  3571. setSelected(center, align == mxConstants.ALIGN_CENTER);
  3572. setSelected(right, align == mxConstants.ALIGN_RIGHT);
  3573. var valign = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_ALIGN, mxConstants.ALIGN_MIDDLE);
  3574. setSelected(top, valign == mxConstants.ALIGN_TOP);
  3575. setSelected(middle, valign == mxConstants.ALIGN_MIDDLE);
  3576. setSelected(bottom, valign == mxConstants.ALIGN_BOTTOM);
  3577. var pos = mxUtils.getValue(ss.style, mxConstants.STYLE_LABEL_POSITION, mxConstants.ALIGN_CENTER);
  3578. var vpos = mxUtils.getValue(ss.style, mxConstants.STYLE_VERTICAL_LABEL_POSITION, mxConstants.ALIGN_MIDDLE);
  3579. if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_TOP)
  3580. {
  3581. positionSelect.value = 'topLeft';
  3582. }
  3583. else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_TOP)
  3584. {
  3585. positionSelect.value = 'top';
  3586. }
  3587. else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_TOP)
  3588. {
  3589. positionSelect.value = 'topRight';
  3590. }
  3591. else if (pos == mxConstants.ALIGN_LEFT && vpos == mxConstants.ALIGN_BOTTOM)
  3592. {
  3593. positionSelect.value = 'bottomLeft';
  3594. }
  3595. else if (pos == mxConstants.ALIGN_CENTER && vpos == mxConstants.ALIGN_BOTTOM)
  3596. {
  3597. positionSelect.value = 'bottom';
  3598. }
  3599. else if (pos == mxConstants.ALIGN_RIGHT && vpos == mxConstants.ALIGN_BOTTOM)
  3600. {
  3601. positionSelect.value = 'bottomRight';
  3602. }
  3603. else if (pos == mxConstants.ALIGN_LEFT)
  3604. {
  3605. positionSelect.value = 'left';
  3606. }
  3607. else if (pos == mxConstants.ALIGN_RIGHT)
  3608. {
  3609. positionSelect.value = 'right';
  3610. }
  3611. else
  3612. {
  3613. positionSelect.value = 'center';
  3614. }
  3615. var dir = mxUtils.getValue(ss.style, mxConstants.STYLE_TEXT_DIRECTION, mxConstants.DEFAULT_TEXT_DIRECTION);
  3616. if (dir == mxConstants.TEXT_DIRECTION_RTL)
  3617. {
  3618. dirSelect.value = 'rightToLeft';
  3619. }
  3620. else if (dir == mxConstants.TEXT_DIRECTION_LTR)
  3621. {
  3622. dirSelect.value = 'leftToRight';
  3623. }
  3624. else if (dir == mxConstants.TEXT_DIRECTION_AUTO || !ss.html)
  3625. {
  3626. dirSelect.value = 'automatic';
  3627. }
  3628. else if (dir == mxConstants.TEXT_DIRECTION_VERTICAL_LR)
  3629. {
  3630. dirSelect.value = 'vertical-leftToRight';
  3631. }
  3632. else if (dir == mxConstants.TEXT_DIRECTION_VERTICAL_RL)
  3633. {
  3634. dirSelect.value = 'vertical-rightToLeft';
  3635. }
  3636. if (force || document.activeElement != globalSpacing)
  3637. {
  3638. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING, 2));
  3639. globalSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  3640. }
  3641. if (force || document.activeElement != topSpacing)
  3642. {
  3643. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_TOP, 0));
  3644. topSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  3645. }
  3646. if (force || document.activeElement != rightSpacing)
  3647. {
  3648. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_RIGHT, 0));
  3649. rightSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  3650. }
  3651. if (force || document.activeElement != bottomSpacing)
  3652. {
  3653. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_BOTTOM, 0));
  3654. bottomSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  3655. }
  3656. if (force || document.activeElement != leftSpacing)
  3657. {
  3658. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_SPACING_LEFT, 0));
  3659. leftSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  3660. }
  3661. });
  3662. globalUpdate = this.installInputHandler(globalSpacing, mxConstants.STYLE_SPACING, 2, -999, 999,
  3663. this.getUnit(' '), null, this.isFloatUnit(), true);
  3664. topUpdate = this.installInputHandler(topSpacing, mxConstants.STYLE_SPACING_TOP, 0, -999, 999,
  3665. this.getUnit(' '), null, this.isFloatUnit(), true);
  3666. rightUpdate = this.installInputHandler(rightSpacing, mxConstants.STYLE_SPACING_RIGHT, 0, -999, 999,
  3667. this.getUnit(' '), null, this.isFloatUnit(), true);
  3668. bottomUpdate = this.installInputHandler(bottomSpacing, mxConstants.STYLE_SPACING_BOTTOM, 0, -999, 999,
  3669. this.getUnit(' '), null, this.isFloatUnit(), true);
  3670. leftUpdate = this.installInputHandler(leftSpacing, mxConstants.STYLE_SPACING_LEFT, 0, -999, 999,
  3671. this.getUnit(' '), null, this.isFloatUnit(), true);
  3672. this.addKeyHandler(input, listener);
  3673. this.addKeyHandler(globalSpacing, listener);
  3674. this.addKeyHandler(topSpacing, listener);
  3675. this.addKeyHandler(rightSpacing, listener);
  3676. this.addKeyHandler(bottomSpacing, listener);
  3677. this.addKeyHandler(leftSpacing, listener);
  3678. graph.getModel().addListener(mxEvent.CHANGE, listener);
  3679. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  3680. listener();
  3681. if (graph.cellEditor.isContentEditing())
  3682. {
  3683. var propertiesPanel = null;
  3684. var updating = false;
  3685. var updateCssHandler = mxUtils.bind(this, function()
  3686. {
  3687. if (!updating)
  3688. {
  3689. updating = true;
  3690. window.setTimeout(mxUtils.bind(this, function()
  3691. {
  3692. var node = graph.getSelectedEditingElement();
  3693. if (node != null)
  3694. {
  3695. function getParentBlock(elt)
  3696. {
  3697. while (elt != null && elt != graph.cellEditor.textarea)
  3698. {
  3699. var css = mxUtils.getCurrentStyle(elt);
  3700. if (css.display == 'block')
  3701. {
  3702. return elt;
  3703. }
  3704. elt = elt.parentNode;
  3705. }
  3706. return null;
  3707. };
  3708. function getRelativeLineHeight(fontSize, css, elt)
  3709. {
  3710. if (elt.style != null && css != null)
  3711. {
  3712. var lineHeight = css.lineHeight
  3713. if (elt.style.lineHeight != null && elt.style.lineHeight.substring(elt.style.lineHeight.length - 1) == '%')
  3714. {
  3715. return parseInt(elt.style.lineHeight) / 100;
  3716. }
  3717. else
  3718. {
  3719. return (lineHeight.substring(lineHeight.length - 2) == 'px') ?
  3720. parseFloat(lineHeight) / fontSize : parseInt(lineHeight);
  3721. }
  3722. }
  3723. else
  3724. {
  3725. return '';
  3726. }
  3727. };
  3728. function getAbsoluteFontSize(css)
  3729. {
  3730. var fontSize = (css != null) ? css.fontSize : null;
  3731. if (fontSize != null && fontSize.substring(fontSize.length - 2) == 'px')
  3732. {
  3733. return parseFloat(fontSize);
  3734. }
  3735. else
  3736. {
  3737. return mxConstants.DEFAULT_FONTSIZE;
  3738. }
  3739. };
  3740. var css = mxUtils.getCurrentStyle(node);
  3741. var fontSize = getAbsoluteFontSize(css);
  3742. var lineHeight = getRelativeLineHeight(fontSize, css, node);
  3743. // Finds common font size
  3744. var elts = node.getElementsByTagName('*');
  3745. // IE does not support containsNode
  3746. if (elts.length > 0 && window.getSelection && !mxClient.IS_IE && !mxClient.IS_IE11)
  3747. {
  3748. var selection = window.getSelection();
  3749. for (var i = 0; i < elts.length; i++)
  3750. {
  3751. if (selection.containsNode(elts[i], true))
  3752. {
  3753. temp = mxUtils.getCurrentStyle(elts[i]);
  3754. fontSize = Math.max(getAbsoluteFontSize(temp), fontSize);
  3755. var lh = getRelativeLineHeight(fontSize, temp, elts[i]);
  3756. if (lh != lineHeight || isNaN(lh))
  3757. {
  3758. lineHeight = '';
  3759. }
  3760. }
  3761. }
  3762. }
  3763. function hasParentOrOnlyChild(name)
  3764. {
  3765. if (graph.getParentByName(node, name, graph.cellEditor.textarea) != null)
  3766. {
  3767. return true;
  3768. }
  3769. else
  3770. {
  3771. var child = node;
  3772. while (child != null && child.childNodes.length == 1)
  3773. {
  3774. child = child.childNodes[0];
  3775. if (child.nodeName == name)
  3776. {
  3777. return true;
  3778. }
  3779. }
  3780. }
  3781. return false;
  3782. };
  3783. function isEqualOrPrefixed(str, value)
  3784. {
  3785. if (str != null && value != null)
  3786. {
  3787. if (str == value)
  3788. {
  3789. return true;
  3790. }
  3791. else if (str.length > value.length + 1)
  3792. {
  3793. return str.substring(str.length - value.length - 1, str.length) == '-' + value;
  3794. }
  3795. }
  3796. return false;
  3797. };
  3798. if (css != null)
  3799. {
  3800. setSelected(fontStyleItems[0], css.fontWeight == 'bold' ||
  3801. css.fontWeight > 400 || hasParentOrOnlyChild('B') ||
  3802. hasParentOrOnlyChild('STRONG'));
  3803. setSelected(fontStyleItems[1], css.fontStyle == 'italic' ||
  3804. hasParentOrOnlyChild('I') || hasParentOrOnlyChild('EM'));
  3805. setSelected(fontStyleItems[2], hasParentOrOnlyChild('U'));
  3806. setSelected(sup, hasParentOrOnlyChild('SUP'));
  3807. setSelected(sub, hasParentOrOnlyChild('SUB'));
  3808. // Adds editing for block CSS styles
  3809. var block = getParentBlock(node);
  3810. if (block != null)
  3811. {
  3812. var blockCss = mxUtils.getCurrentStyle(block);
  3813. function checkUnit(value, unit, input, defaultValue)
  3814. {
  3815. if (parseInt(value) == value)
  3816. {
  3817. value += unit;
  3818. if (input != null)
  3819. {
  3820. input.value = value;
  3821. }
  3822. }
  3823. return value;
  3824. };
  3825. var cssProps = [];
  3826. function addLengthProperty(name, dispName)
  3827. {
  3828. cssProps.push({name: name, dispName: dispName, type: 'string',
  3829. getValue: function()
  3830. {
  3831. return blockCss[name];
  3832. }, valueChanged: function(newValue, input)
  3833. {
  3834. block.style[name] = checkUnit(newValue, 'px', input);
  3835. if (newValue == '' && input != null)
  3836. {
  3837. input.value = blockCss[name];
  3838. }
  3839. }});
  3840. };
  3841. addLengthProperty('paddingTop', 'Padding Top');
  3842. addLengthProperty('paddingRight', 'Padding Right');
  3843. addLengthProperty('paddingLeft', 'Padding Left');
  3844. addLengthProperty('paddingBottom', 'Padding Bottom');
  3845. addLengthProperty('marginTop', 'Margin Top');
  3846. addLengthProperty('marginRight', 'Margin Right');
  3847. addLengthProperty('marginLeft', 'Margin Left');
  3848. addLengthProperty('marginBottom', 'Margin Bottom');
  3849. var newPropertiesPanel = this.createPanel();
  3850. this.addProperties(newPropertiesPanel, cssProps, ss, true)
  3851. if (propertiesPanel != null)
  3852. {
  3853. propertiesPanel.parentNode.replaceChild(newPropertiesPanel, propertiesPanel);
  3854. }
  3855. else
  3856. {
  3857. container.appendChild(newPropertiesPanel);
  3858. }
  3859. propertiesPanel = newPropertiesPanel;
  3860. }
  3861. if (!graph.cellEditor.isTableSelected())
  3862. {
  3863. var align = graph.cellEditor.align || mxUtils.getValue(ss.style, mxConstants.STYLE_ALIGN, mxConstants.ALIGN_CENTER);
  3864. if (isEqualOrPrefixed(css.textAlign, 'justify'))
  3865. {
  3866. setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify'));
  3867. setSelected(left, false);
  3868. setSelected(center, false);
  3869. setSelected(right, false);
  3870. }
  3871. else
  3872. {
  3873. setSelected(full, false);
  3874. setSelected(left, align == mxConstants.ALIGN_LEFT);
  3875. setSelected(center, align == mxConstants.ALIGN_CENTER);
  3876. setSelected(right, align == mxConstants.ALIGN_RIGHT);
  3877. }
  3878. }
  3879. else
  3880. {
  3881. setSelected(full, isEqualOrPrefixed(css.textAlign, 'justify'));
  3882. setSelected(left, isEqualOrPrefixed(css.textAlign, 'left'));
  3883. setSelected(center, isEqualOrPrefixed(css.textAlign, 'center'));
  3884. setSelected(right, isEqualOrPrefixed(css.textAlign, 'right'));
  3885. }
  3886. currentTable = graph.getParentByName(node, 'TABLE', graph.cellEditor.textarea);
  3887. tableRow = (currentTable == null) ? null : graph.getParentByName(node, 'TR', currentTable);
  3888. tableCell = (currentTable == null) ? null : graph.getParentByNames(node, ['TD', 'TH'], currentTable);
  3889. tableWrapper.style.display = (currentTable != null) ? '' : 'none';
  3890. if (document.activeElement != input)
  3891. {
  3892. if (node.nodeName == 'FONT' && node.getAttribute('size') == '4' &&
  3893. pendingFontSize != null)
  3894. {
  3895. node.removeAttribute('size');
  3896. node.style.fontSize = pendingFontSize + ' pt';
  3897. pendingFontSize = null;
  3898. }
  3899. else
  3900. {
  3901. input.value = (isNaN(fontSize)) ? '' : fontSize + ' ' + Editor.fontSizeUnit;
  3902. }
  3903. var lh = parseFloat(lineHeight);
  3904. if (!isNaN(lh))
  3905. {
  3906. lineHeightInput.value = Math.round(lh * 100) + ' %';
  3907. }
  3908. else
  3909. {
  3910. lineHeightInput.value = '100 %';
  3911. }
  3912. }
  3913. // Updates the color picker for the current font
  3914. if (fontColorApply != null)
  3915. {
  3916. if (css.color == 'rgba(0, 0, 0, 0)' ||
  3917. css.color == 'transparent')
  3918. {
  3919. currentFontColor = mxConstants.NONE;
  3920. }
  3921. else
  3922. {
  3923. currentFontColor = mxUtils.rgba2hex(css.color)
  3924. }
  3925. fontColorApply(currentFontColor, true);
  3926. }
  3927. if (bgColorApply != null)
  3928. {
  3929. if (css.backgroundColor == 'rgba(0, 0, 0, 0)' ||
  3930. css.backgroundColor == 'transparent')
  3931. {
  3932. currentBgColor = mxConstants.NONE;
  3933. }
  3934. else
  3935. {
  3936. currentBgColor = mxUtils.rgba2hex(css.backgroundColor);
  3937. }
  3938. bgColorApply(currentBgColor, true);
  3939. }
  3940. // Workaround for firstChild is null or not an object
  3941. // in the log which seems to be IE8- only / 29.01.15
  3942. if (fontMenu.firstChild != null)
  3943. {
  3944. fontMenu.firstChild.nodeValue = mxUtils.getCssFontFamily(css.fontFamily);
  3945. }
  3946. }
  3947. }
  3948. updating = false;
  3949. }), 0);
  3950. }
  3951. });
  3952. if (mxClient.IS_FF || mxClient.IS_EDGE || mxClient.IS_IE || mxClient.IS_IE11)
  3953. {
  3954. mxEvent.addListener(graph.cellEditor.textarea, 'DOMSubtreeModified', updateCssHandler);
  3955. }
  3956. mxEvent.addListener(graph.cellEditor.textarea, 'input', updateCssHandler);
  3957. mxEvent.addListener(graph.cellEditor.textarea, 'touchend', updateCssHandler);
  3958. mxEvent.addListener(graph.cellEditor.textarea, 'mouseup', updateCssHandler);
  3959. mxEvent.addListener(graph.cellEditor.textarea, 'keyup', updateCssHandler);
  3960. this.listeners.push({destroy: function()
  3961. {
  3962. // No need to remove listener since textarea is destroyed after edit
  3963. }});
  3964. updateCssHandler();
  3965. }
  3966. return container;
  3967. };
  3968. /**
  3969. * Adds the label menu items to the given menu and parent.
  3970. */
  3971. StyleFormatPanel = function(format, editorUi, container)
  3972. {
  3973. BaseFormatPanel.call(this, format, editorUi, container);
  3974. this.init();
  3975. };
  3976. mxUtils.extend(StyleFormatPanel, BaseFormatPanel);
  3977. /**
  3978. *
  3979. */
  3980. StyleFormatPanel.prototype.defaultStrokeColor = 'black';
  3981. /**
  3982. * Adds the label menu items to the given menu and parent.
  3983. */
  3984. StyleFormatPanel.prototype.init = function()
  3985. {
  3986. var ui = this.editorUi;
  3987. var ss = ui.getSelectionState();
  3988. if (!ss.containsLabel && ss.cells.length > 0)
  3989. {
  3990. if (ss.containsImage && ss.vertices.length == 1 && ss.style.shape == 'image' &&
  3991. ss.style.image != null && String(ss.style.image).
  3992. substring(0, 19) == 'data:image/svg+xml;')
  3993. {
  3994. this.container.appendChild(this.addSvgStyles(this.createPanel()));
  3995. }
  3996. if (ss.fill)
  3997. {
  3998. this.container.appendChild(this.addFill(this.createPanel()));
  3999. }
  4000. this.container.appendChild(this.addStroke(this.createPanel()));
  4001. this.container.appendChild(this.addLineJumps(this.createPanel()));
  4002. var opacityPanel = this.createRelativeOption(mxResources.get('opacity'), mxConstants.STYLE_OPACITY);
  4003. opacityPanel.style.paddingTop = '8px';
  4004. opacityPanel.style.paddingBottom = '10px';
  4005. this.container.appendChild(opacityPanel);
  4006. this.container.appendChild(this.addEffects(this.createPanel()));
  4007. }
  4008. var opsPanel = this.createPanel();
  4009. opsPanel.style.paddingTop = '8px';
  4010. if (ss.cells.length == 1)
  4011. {
  4012. this.addEditOps(opsPanel);
  4013. if (opsPanel.firstChild != null)
  4014. {
  4015. mxUtils.br(opsPanel);
  4016. }
  4017. }
  4018. if (ss.cells.length >= 1)
  4019. {
  4020. this.addStyleOps(opsPanel);
  4021. }
  4022. if (opsPanel.firstChild != null)
  4023. {
  4024. this.container.appendChild(opsPanel);
  4025. }
  4026. };
  4027. /**
  4028. * Use browser for parsing CSS.
  4029. */
  4030. StyleFormatPanel.prototype.getCssRules = function(css)
  4031. {
  4032. var doc = document.implementation.createHTMLDocument('');
  4033. var styleElement = document.createElement('style');
  4034. mxUtils.setTextContent(styleElement, css);
  4035. doc.body.appendChild(styleElement);
  4036. return styleElement.sheet.cssRules;
  4037. };
  4038. /**
  4039. * Adds the label menu items to the given menu and parent.
  4040. */
  4041. StyleFormatPanel.prototype.addSvgStyles = function(container)
  4042. {
  4043. var ui = this.editorUi;
  4044. var ss = ui.getSelectionState();
  4045. container.style.paddingTop = '6px';
  4046. container.style.paddingBottom = '6px';
  4047. container.style.fontWeight = 'bold';
  4048. container.style.display = 'none';
  4049. try
  4050. {
  4051. var exp = ss.style.editableCssRules;
  4052. if (exp != null)
  4053. {
  4054. var regex = new RegExp(exp);
  4055. var data = ss.style.image.substring(ss.style.image.indexOf(',') + 1);
  4056. var xml = (window.atob) ? decodeURIComponent(escape(atob((data)))) :
  4057. Base64.decode(data, true);
  4058. var svg = mxUtils.parseXml(xml);
  4059. if (svg != null)
  4060. {
  4061. var styles = svg.getElementsByTagName('style');
  4062. for (var i = 0; i < styles.length; i++)
  4063. {
  4064. var rules = this.getCssRules(mxUtils.getTextContent(styles[i]));
  4065. for (var j = 0; j < rules.length; j++)
  4066. {
  4067. this.addSvgRule(container, rules[j], svg, styles[i], rules, j, regex);
  4068. }
  4069. }
  4070. }
  4071. }
  4072. }
  4073. catch (e)
  4074. {
  4075. // ignore
  4076. }
  4077. return container;
  4078. };
  4079. /**
  4080. * Adds the label menu items to the given menu and parent.
  4081. */
  4082. StyleFormatPanel.prototype.addSvgRule = function(container, rule, svg, styleElem, rules, ruleIndex, regex)
  4083. {
  4084. var ui = this.editorUi;
  4085. var graph = ui.editor.graph;
  4086. if (regex.test(rule.selectorText))
  4087. {
  4088. function rgb2hex(rgb)
  4089. {
  4090. rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
  4091. return (rgb && rgb.length === 4) ? "#" +
  4092. ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
  4093. ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
  4094. ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : '';
  4095. };
  4096. var addStyleRule = mxUtils.bind(this, function(rule, key, label)
  4097. {
  4098. var value = mxUtils.trim(rule.style[key]);
  4099. if (value != '' && value.substring(0, 4) != 'url(')
  4100. {
  4101. var option = this.createColorOption(label + ' ' + rule.selectorText, function()
  4102. {
  4103. return rgb2hex(value);
  4104. }, mxUtils.bind(this, function(color)
  4105. {
  4106. rules[ruleIndex].style[key] = color;
  4107. var cssTxt = '';
  4108. for (var i = 0; i < rules.length; i++)
  4109. {
  4110. cssTxt += rules[i].cssText + ' ';
  4111. }
  4112. styleElem.textContent = cssTxt;
  4113. var xml = mxUtils.getXml(svg.documentElement);
  4114. graph.setCellStyles(mxConstants.STYLE_IMAGE, 'data:image/svg+xml,' +
  4115. ((window.btoa) ? btoa(unescape(encodeURIComponent(xml))) :
  4116. Base64.encode(xml, true)),
  4117. ui.getSelectionState().cells);
  4118. }), '#ffffff',
  4119. {
  4120. install: function(apply)
  4121. {
  4122. // ignore
  4123. },
  4124. destroy: function()
  4125. {
  4126. // ignore
  4127. }
  4128. });
  4129. container.appendChild(option);
  4130. // Shows container if rules are added
  4131. container.style.display = '';
  4132. }
  4133. });
  4134. addStyleRule(rule, 'fill', mxResources.get('fill'));
  4135. addStyleRule(rule, 'stroke', mxResources.get('line'));
  4136. addStyleRule(rule, 'stop-color', mxResources.get('gradient'));
  4137. }
  4138. };
  4139. /**
  4140. * Adds the label menu items to the given menu and parent.
  4141. */
  4142. StyleFormatPanel.prototype.addEditOps = function(div)
  4143. {
  4144. var ss = this.editorUi.getSelectionState();
  4145. if (ss.cells.length == 1)
  4146. {
  4147. var editSelect = document.createElement('select');
  4148. editSelect.style.width = '210px';
  4149. editSelect.style.textAlign = 'center';
  4150. editSelect.style.marginBottom = '2px';
  4151. var ops = ['edit', 'copyAsText', 'editLink', 'editShape', 'editImage',
  4152. 'editData', 'copyData', 'pasteData', 'editConnectionPoints',
  4153. 'editGeometry', 'editTooltip', 'editStyle'];
  4154. var libs = null;
  4155. if (this.editorUi.sidebar != null)
  4156. {
  4157. var keyStyle = this.editorUi.sidebar.getKeyStyle(ss.cells[0].style);
  4158. libs = this.editorUi.sidebar.getLibsForStyle(keyStyle);
  4159. // Adds open library action and updates search index when invoked
  4160. // if no libs were found but the shape name is likely to be known
  4161. if (libs == null && !this.editorUi.sidebar.isSearchIndexLoaded() &&
  4162. ss.style.shape != null && String(ss.style.shape).
  4163. substring(0, 8) == 'mxgraph.')
  4164. {
  4165. libs = [];
  4166. }
  4167. }
  4168. if (libs != null)
  4169. {
  4170. ops.push('openLibrary');
  4171. }
  4172. for (var i = 0; i < ops.length; i++)
  4173. {
  4174. var action = this.editorUi.actions.get(ops[i]);
  4175. if (action == null || action.enabled)
  4176. {
  4177. var editOption = document.createElement('option');
  4178. editOption.setAttribute('value', ops[i]);
  4179. var title = mxResources.get(ops[i]);
  4180. mxUtils.write(editOption, title + ((ops[i] == 'edit') ? '' : '...'));
  4181. if (action != null && action.shortcut != null)
  4182. {
  4183. title += ' (' + action.shortcut + ')';
  4184. }
  4185. editOption.setAttribute('title', title);
  4186. editSelect.appendChild(editOption);
  4187. }
  4188. }
  4189. if (editSelect.children.length > 1)
  4190. {
  4191. div.appendChild(editSelect);
  4192. mxEvent.addListener(editSelect, 'change', mxUtils.bind(this, function(evt)
  4193. {
  4194. if (editSelect.value == 'openLibrary')
  4195. {
  4196. if (libs != null && libs.length == 0)
  4197. {
  4198. // Updates search index and tries again
  4199. this.editorUi.sidebar.updateSearchIndex();
  4200. var keyStyle = this.editorUi.sidebar.getKeyStyle(ss.cells[0].style);
  4201. libs = this.editorUi.sidebar.getLibsForStyle(keyStyle);
  4202. }
  4203. if (libs != null && libs.length > 0)
  4204. {
  4205. this.editorUi.sidebar.openLibraries(libs);
  4206. }
  4207. else
  4208. {
  4209. this.editorUi.handleError({message: mxResources.get('objectNotFound')});
  4210. }
  4211. editSelect.value = 'edit';
  4212. }
  4213. else
  4214. {
  4215. var action = this.editorUi.actions.get(editSelect.value);
  4216. editSelect.value = 'edit';
  4217. if (action != null)
  4218. {
  4219. action.funct();
  4220. }
  4221. }
  4222. }));
  4223. if (ss.image)
  4224. {
  4225. var graph = this.editorUi.editor.graph;
  4226. var state = graph.view.getState(graph.getSelectionCell());
  4227. if (state != null && mxUtils.getValue(state.style, mxConstants.STYLE_IMAGE, null) != null)
  4228. {
  4229. var btn = mxUtils.button(mxResources.get('crop') + '...',
  4230. mxUtils.bind(this, function(evt)
  4231. {
  4232. this.editorUi.actions.get('crop').funct();
  4233. }));
  4234. btn.setAttribute('title', mxResources.get('crop'));
  4235. editSelect.style.width = '104px';
  4236. btn.style.width = '104px';
  4237. btn.style.marginLeft = '2px';
  4238. btn.style.marginBottom = '2px';
  4239. div.appendChild(btn);
  4240. }
  4241. }
  4242. }
  4243. }
  4244. return div;
  4245. };
  4246. /**
  4247. * Adds the label menu items to the given menu and parent.
  4248. */
  4249. StyleFormatPanel.prototype.addFill = function(container)
  4250. {
  4251. var ui = this.editorUi;
  4252. var graph = ui.editor.graph;
  4253. var ss = ui.getSelectionState();
  4254. container.style.paddingTop = '6px';
  4255. container.style.paddingBottom = '6px';
  4256. // Adds gradient direction option
  4257. var gradientSelect = document.createElement('select');
  4258. gradientSelect.style.position = 'absolute';
  4259. gradientSelect.style.left = '104px';
  4260. gradientSelect.style.width = '70px';
  4261. gradientSelect.style.height = '22px';
  4262. gradientSelect.style.padding = '0px';
  4263. gradientSelect.style.marginTop = '-3px';
  4264. gradientSelect.style.borderWidth = '1px';
  4265. gradientSelect.style.borderStyle = 'solid';
  4266. gradientSelect.style.boxSizing = 'border-box';
  4267. var fillStyleSelect = gradientSelect.cloneNode(false);
  4268. // Stops events from bubbling to color option event handler
  4269. mxEvent.addListener(gradientSelect, 'click', function(evt)
  4270. {
  4271. mxEvent.consume(evt);
  4272. });
  4273. mxEvent.addListener(fillStyleSelect, 'click', function(evt)
  4274. {
  4275. mxEvent.consume(evt);
  4276. });
  4277. var gradientPanel = this.createCellColorOption(mxResources.get('gradient'),
  4278. mxConstants.STYLE_GRADIENTCOLOR, 'default', function(color)
  4279. {
  4280. if (color == null || color == mxConstants.NONE)
  4281. {
  4282. gradientSelect.style.display = 'none';
  4283. }
  4284. else
  4285. {
  4286. gradientSelect.style.display = '';
  4287. }
  4288. }, function(color)
  4289. {
  4290. graph.updateCellStyles({'gradientColor': color}, graph.getSelectionCells());
  4291. }, graph.getDefaultColor(ss.style, mxConstants.STYLE_GRADIENTCOLOR,
  4292. graph.shapeForegroundColor, graph.shapeBackgroundColor));
  4293. var fillKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BACKGROUND : mxConstants.STYLE_FILLCOLOR;
  4294. var fillPanel = this.createCellColorOption(mxResources.get('fill'),
  4295. fillKey, 'default', null, mxUtils.bind(this, function(color)
  4296. {
  4297. graph.setCellStyles(fillKey, color, ss.cells);
  4298. }), graph.getDefaultColor(ss.style, fillKey, graph.shapeBackgroundColor,
  4299. graph.shapeForegroundColor));
  4300. fillPanel.style.fontWeight = 'bold';
  4301. var tmpColor = mxUtils.getValue(ss.style, fillKey, null);
  4302. gradientPanel.style.display = (tmpColor != null && tmpColor != mxConstants.NONE &&
  4303. ss.fill && ss.style.shape != 'image') ? '' : 'none';
  4304. var directions = [mxConstants.DIRECTION_NORTH, mxConstants.DIRECTION_EAST,
  4305. mxConstants.DIRECTION_SOUTH, mxConstants.DIRECTION_WEST,
  4306. mxConstants.DIRECTION_RADIAL];
  4307. for (var i = 0; i < directions.length; i++)
  4308. {
  4309. var gradientOption = document.createElement('option');
  4310. gradientOption.setAttribute('value', directions[i]);
  4311. mxUtils.write(gradientOption, mxResources.get(directions[i]));
  4312. gradientSelect.appendChild(gradientOption);
  4313. }
  4314. gradientPanel.appendChild(gradientSelect);
  4315. var curFillStyle;
  4316. function populateFillStyle()
  4317. {
  4318. fillStyleSelect.innerHTML = '';
  4319. curFillStyle = 1;
  4320. for (var i = 0; i < Editor.fillStyles.length; i++)
  4321. {
  4322. var fillStyleOption = document.createElement('option');
  4323. fillStyleOption.setAttribute('value', Editor.fillStyles[i].val);
  4324. mxUtils.write(fillStyleOption, Editor.fillStyles[i].dispName);
  4325. fillStyleSelect.appendChild(fillStyleOption);
  4326. }
  4327. };
  4328. function populateRoughFillStyle()
  4329. {
  4330. fillStyleSelect.innerHTML = '';
  4331. curFillStyle = 2;
  4332. for (var i = 0; i < Editor.roughFillStyles.length; i++)
  4333. {
  4334. var fillStyleOption = document.createElement('option');
  4335. fillStyleOption.setAttribute('value', Editor.roughFillStyles[i].val);
  4336. mxUtils.write(fillStyleOption, Editor.roughFillStyles[i].dispName);
  4337. fillStyleSelect.appendChild(fillStyleOption);
  4338. }
  4339. fillStyleSelect.value = 'auto';
  4340. };
  4341. populateFillStyle();
  4342. if (ss.gradient)
  4343. {
  4344. fillPanel.appendChild(fillStyleSelect);
  4345. }
  4346. var listener = mxUtils.bind(this, function()
  4347. {
  4348. ss = ui.getSelectionState();
  4349. var value = mxUtils.getValue(ss.style, mxConstants.STYLE_GRADIENT_DIRECTION,
  4350. mxConstants.DIRECTION_SOUTH);
  4351. var fillStyle = mxUtils.getValue(ss.style, 'fillStyle', 'auto');
  4352. // Handles empty string which is not allowed as a value
  4353. if (value == '')
  4354. {
  4355. value = mxConstants.DIRECTION_SOUTH;
  4356. }
  4357. gradientSelect.value = value;
  4358. container.style.display = (ss.fill) ? '' : 'none';
  4359. var fillColor = mxUtils.getValue(ss.style, fillKey, null);
  4360. if (!ss.fill || fillColor == null || fillColor == mxConstants.NONE ||
  4361. ss.style.shape == 'filledEdge')
  4362. {
  4363. fillStyleSelect.style.display = 'none';
  4364. gradientPanel.style.display = 'none';
  4365. }
  4366. else
  4367. {
  4368. if (ss.style.sketch == '1')
  4369. {
  4370. if (curFillStyle != 2)
  4371. {
  4372. populateRoughFillStyle()
  4373. }
  4374. }
  4375. else if (curFillStyle != 1)
  4376. {
  4377. populateFillStyle();
  4378. }
  4379. fillStyleSelect.value = fillStyle;
  4380. //In case of switching from sketch to regular and fill type is not there
  4381. if (!fillStyleSelect.value)
  4382. {
  4383. fillStyle = 'auto';
  4384. fillStyleSelect.value = fillStyle;
  4385. }
  4386. fillStyleSelect.style.display = ss.style.sketch == '1' ||
  4387. gradientSelect.style.display == 'none'? '' : 'none';
  4388. gradientPanel.style.display = (ss.gradient &&
  4389. !ss.containsImage && (ss.style.sketch != '1' ||
  4390. fillStyle == 'solid' || fillStyle == 'auto')) ?
  4391. '' : 'none';
  4392. }
  4393. });
  4394. graph.getModel().addListener(mxEvent.CHANGE, listener);
  4395. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  4396. listener();
  4397. mxEvent.addListener(gradientSelect, 'change', function(evt)
  4398. {
  4399. graph.setCellStyles(mxConstants.STYLE_GRADIENT_DIRECTION, gradientSelect.value, ss.cells);
  4400. ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_GRADIENT_DIRECTION],
  4401. 'values', [gradientSelect.value], 'cells', ss.cells));
  4402. mxEvent.consume(evt);
  4403. });
  4404. mxEvent.addListener(fillStyleSelect, 'change', function(evt)
  4405. {
  4406. graph.setCellStyles('fillStyle', fillStyleSelect.value, ss.cells);
  4407. ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['fillStyle'],
  4408. 'values', [fillStyleSelect.value], 'cells', ss.cells));
  4409. mxEvent.consume(evt);
  4410. });
  4411. container.appendChild(fillPanel);
  4412. container.appendChild(gradientPanel);
  4413. // Adds custom colors
  4414. var custom = this.getCustomColors();
  4415. for (var i = 0; i < custom.length; i++)
  4416. {
  4417. container.appendChild(this.createCellColorOption(custom[i].title,
  4418. custom[i].key, custom[i].defaultValue));
  4419. }
  4420. return container;
  4421. };
  4422. /**
  4423. * Adds the label menu items to the given menu and parent.
  4424. */
  4425. StyleFormatPanel.prototype.getCustomColors = function()
  4426. {
  4427. var ss = this.editorUi.getSelectionState();
  4428. var result = [];
  4429. if (ss.swimlane)
  4430. {
  4431. result.push({title: mxResources.get('laneColor'),
  4432. key: 'swimlaneFillColor', defaultValue: 'default'});
  4433. }
  4434. return result;
  4435. };
  4436. /**
  4437. * Adds the label menu items to the given menu and parent.
  4438. */
  4439. StyleFormatPanel.prototype.addStroke = function(container)
  4440. {
  4441. var panel = this;
  4442. var ui = this.editorUi;
  4443. var graph = ui.editor.graph;
  4444. var ss = ui.getSelectionState();
  4445. container.style.paddingTop = '6px';
  4446. container.style.paddingBottom = '4px';
  4447. container.style.whiteSpace = 'normal';
  4448. var colorPanel = document.createElement('div');
  4449. colorPanel.style.fontWeight = 'bold';
  4450. if (!ss.stroke)
  4451. {
  4452. colorPanel.style.display = 'none';
  4453. }
  4454. // Adds gradient direction option
  4455. var styleSelect = document.createElement('select');
  4456. styleSelect.style.position = 'absolute';
  4457. styleSelect.style.height = '22px';
  4458. styleSelect.style.padding = '0px';
  4459. styleSelect.style.marginTop = '-3px';
  4460. styleSelect.style.textAlign = 'center';
  4461. styleSelect.style.boxSizing = 'border-box';
  4462. styleSelect.style.left = '90px';
  4463. styleSelect.style.width = '83px';
  4464. styleSelect.style.borderWidth = '1px';
  4465. styleSelect.style.borderStyle = 'solid';
  4466. var styles = ['sharp', 'rounded', 'curved'];
  4467. for (var i = 0; i < styles.length; i++)
  4468. {
  4469. var styleOption = document.createElement('option');
  4470. styleOption.setAttribute('value', styles[i]);
  4471. mxUtils.write(styleOption, mxResources.get(styles[i]));
  4472. styleSelect.appendChild(styleOption);
  4473. }
  4474. mxEvent.addListener(styleSelect, 'change', function(evt)
  4475. {
  4476. graph.getModel().beginUpdate();
  4477. try
  4478. {
  4479. var keys = [mxConstants.STYLE_ROUNDED, mxConstants.STYLE_CURVED];
  4480. var values = ['0', '0'];
  4481. if (styleSelect.value == 'rounded')
  4482. {
  4483. values = ['1', '0'];
  4484. }
  4485. else if (styleSelect.value == 'curved')
  4486. {
  4487. values = ['0', '1'];
  4488. }
  4489. for (var i = 0; i < keys.length; i++)
  4490. {
  4491. graph.setCellStyles(keys[i], values[i], ss.cells);
  4492. }
  4493. ui.fireEvent(new mxEventObject('styleChanged', 'keys', keys,
  4494. 'values', values, 'cells', ss.cells));
  4495. }
  4496. finally
  4497. {
  4498. graph.getModel().endUpdate();
  4499. }
  4500. mxEvent.consume(evt);
  4501. });
  4502. // Stops events from bubbling to color option event handler
  4503. mxEvent.addListener(styleSelect, 'click', function(evt)
  4504. {
  4505. mxEvent.consume(evt);
  4506. });
  4507. var strokeKey = (ss.style.shape == 'image') ? mxConstants.STYLE_IMAGE_BORDER : mxConstants.STYLE_STROKECOLOR;
  4508. var label = (ss.style.shape == 'image') ? mxResources.get('border') : mxResources.get('line');
  4509. var lineColor = this.createCellColorOption(label, strokeKey, 'default', null, mxUtils.bind(this, function(color)
  4510. {
  4511. graph.setCellStyles(strokeKey, color, ss.cells);
  4512. // Sets strokeColor to inherit for rows and cells in tables
  4513. if (color == null || color == mxConstants.NONE)
  4514. {
  4515. var tableCells = [];
  4516. for (var i = 0; i < ss.cells.length; i++)
  4517. {
  4518. if (graph.isTableCell(ss.cells[i]) ||
  4519. graph.isTableRow(ss.cells[i]))
  4520. {
  4521. tableCells.push(ss.cells[i]);
  4522. }
  4523. }
  4524. if (tableCells.length > 0)
  4525. {
  4526. graph.setCellStyles(strokeKey, 'inherit', tableCells);
  4527. }
  4528. }
  4529. }), graph.shapeForegroundColor);
  4530. lineColor.appendChild(styleSelect);
  4531. colorPanel.appendChild(lineColor);
  4532. // Used if only edges selected
  4533. var stylePanel = colorPanel.cloneNode(false);
  4534. stylePanel.style.display = 'inline-flex';
  4535. stylePanel.style.alignItems = 'top';
  4536. stylePanel.style.fontWeight = 'normal';
  4537. stylePanel.style.whiteSpace = 'nowrap';
  4538. stylePanel.style.position = 'relative';
  4539. stylePanel.style.paddingLeft = '5px';
  4540. stylePanel.style.overflow = 'hidden';
  4541. stylePanel.style.marginTop = '2px';
  4542. stylePanel.style.width = '220px';
  4543. var addItem = mxUtils.bind(this, function(menu, width, cssName, keys, values)
  4544. {
  4545. var item = this.editorUi.menus.styleChange(menu, '', keys, values, 'geIcon', null);
  4546. var pat = document.createElement('div');
  4547. pat.style.width = width + 'px';
  4548. pat.style.height = '1px';
  4549. pat.style.borderBottom = '1px ' + cssName + ' ' + this.defaultStrokeColor;
  4550. pat.style.paddingTop = '6px';
  4551. item.firstChild.firstChild.style.padding = '0px 4px 0px 4px';
  4552. item.firstChild.firstChild.style.width = width + 'px';
  4553. item.firstChild.firstChild.appendChild(pat);
  4554. return item;
  4555. });
  4556. var pattern = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu)
  4557. {
  4558. addItem(menu, 75, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid'));
  4559. addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed') + ' (1)');
  4560. addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '8 8']).setAttribute('title', mxResources.get('dashed') + ' (2)');
  4561. addItem(menu, 75, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '12 12']).setAttribute('title', mxResources.get('dashed') + ' (3)');
  4562. addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)');
  4563. addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)');
  4564. addItem(menu, 75, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)');
  4565. }));
  4566. // Used for mixed selection (vertices and edges)
  4567. var altStylePanel = stylePanel.cloneNode(false);
  4568. var edgeShape = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-connection', mxResources.get('connection'), false, mxUtils.bind(this, function(menu)
  4569. {
  4570. this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
  4571. [null, null, null, null], 'geIcon geSprite geSprite-connection', null, null, null, true).setAttribute('title', mxResources.get('line'));
  4572. this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
  4573. ['link', null, null, null], 'geIcon geSprite geSprite-linkedge', null, null, null, true).setAttribute('title', mxResources.get('link'));
  4574. this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
  4575. ['flexArrow', null, null, null], 'geIcon geSprite geSprite-arrow', null, null, null, true).setAttribute('title', mxResources.get('arrow'));
  4576. this.editorUi.menus.styleChange(menu, '', [mxConstants.STYLE_SHAPE, mxConstants.STYLE_STARTSIZE, mxConstants.STYLE_ENDSIZE, 'width'],
  4577. ['arrow', null, null, null], 'geIcon geSprite geSprite-simplearrow', null, null, null, true).setAttribute('title', mxResources.get('simpleArrow'));
  4578. }));
  4579. var altPattern = this.editorUi.toolbar.addMenuFunctionInContainer(altStylePanel, 'geSprite-orthogonal', mxResources.get('pattern'), false, mxUtils.bind(this, function(menu)
  4580. {
  4581. addItem(menu, 33, 'solid', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], [null, null]).setAttribute('title', mxResources.get('solid'));
  4582. addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', null]).setAttribute('title', mxResources.get('dashed') + ' (1)');
  4583. addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '8 8']).setAttribute('title', mxResources.get('dashed') + ' (2)');
  4584. addItem(menu, 33, 'dashed', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '12 12']).setAttribute('title', mxResources.get('dashed') + ' (3)');
  4585. addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 1']).setAttribute('title', mxResources.get('dotted') + ' (1)');
  4586. addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 2']).setAttribute('title', mxResources.get('dotted') + ' (2)');
  4587. addItem(menu, 33, 'dotted', [mxConstants.STYLE_DASHED, mxConstants.STYLE_DASH_PATTERN], ['1', '1 4']).setAttribute('title', mxResources.get('dotted') + ' (3)');
  4588. }));
  4589. var stylePanel2 = stylePanel.cloneNode(false);
  4590. // Stroke width
  4591. var input = document.createElement('input');
  4592. input.style.position = 'absolute';
  4593. input.style.textAlign = 'right';
  4594. input.style.marginTop = '2px';
  4595. input.style.width = '52px';
  4596. input.style.height = '22px';
  4597. input.style.left = '146px';
  4598. input.style.borderWidth = '1px';
  4599. input.style.borderStyle = 'solid';
  4600. input.style.boxSizing = 'border-box';
  4601. input.setAttribute('title', mxResources.get('linewidth'));
  4602. stylePanel.appendChild(input);
  4603. var altInput = input.cloneNode(true);
  4604. altStylePanel.appendChild(altInput);
  4605. function update(evt)
  4606. {
  4607. // Maximum stroke width is 999
  4608. var value = panel.fromUnit(parseFloat(input.value));
  4609. value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value));
  4610. if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1))
  4611. {
  4612. graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
  4613. ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH],
  4614. 'values', [value], 'cells', ss.cells));
  4615. }
  4616. input.value = panel.inUnit(value) + ' ' + panel.getUnit();
  4617. mxEvent.consume(evt);
  4618. };
  4619. function altUpdate(evt)
  4620. {
  4621. // Maximum stroke width is 999
  4622. var value = panel.fromUnit(parseFloat(altInput.value));
  4623. value = Math.min(999, Math.max(0, (isNaN(value)) ? 1 : value));
  4624. if (value != mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1))
  4625. {
  4626. graph.setCellStyles(mxConstants.STYLE_STROKEWIDTH, value, ss.cells);
  4627. ui.fireEvent(new mxEventObject('styleChanged', 'keys', [mxConstants.STYLE_STROKEWIDTH],
  4628. 'values', [value], 'cells', ss.cells));
  4629. }
  4630. altInput.value = panel.inUnit(value) + ' ' + panel.getUnit();
  4631. mxEvent.consume(evt);
  4632. };
  4633. var stepper = this.createStepper(input, update, this.getUnitStep(), 9, null, null, this.isFloatUnit());
  4634. stepper.style.display = input.style.display;
  4635. stepper.style.top = '2px';
  4636. stepper.style.left = '198px';
  4637. stylePanel.appendChild(stepper);
  4638. var altStepper = this.createStepper(altInput, altUpdate, this.getUnitStep(), 9, null, null, this.isFloatUnit());
  4639. altStepper.style.display = altInput.style.display;
  4640. altInput.style.position = 'absolute';
  4641. altStepper.style.top = '2px';
  4642. altStepper.style.left = '198px';
  4643. altStylePanel.appendChild(altStepper);
  4644. mxEvent.addListener(input, 'blur', update);
  4645. mxEvent.addListener(input, 'change', update);
  4646. mxEvent.addListener(altInput, 'blur', altUpdate);
  4647. mxEvent.addListener(altInput, 'change', altUpdate);
  4648. var edgeStyle = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-orthogonal', mxResources.get('waypoints'), false, mxUtils.bind(this, function(menu)
  4649. {
  4650. if (ss.style.shape != 'arrow')
  4651. {
  4652. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], [null, null, null], 'geIcon geSprite geSprite-straight', null, true).setAttribute('title', mxResources.get('straight'));
  4653. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', null, null], 'geIcon geSprite geSprite-orthogonal', null, true).setAttribute('title', mxResources.get('orthogonal'));
  4654. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalelbow', null, true).setAttribute('title', mxResources.get('vertical'));
  4655. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['elbowEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalelbow', null, true).setAttribute('title', mxResources.get('horizontal'));
  4656. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', null, null, null], 'geIcon geSprite geSprite-horizontalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
  4657. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_ELBOW, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['isometricEdgeStyle', 'vertical', null, null], 'geIcon geSprite geSprite-verticalisometric', null, true).setAttribute('title', mxResources.get('isometric'));
  4658. if (ss.style.shape == 'connector')
  4659. {
  4660. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['orthogonalEdgeStyle', '1', null], 'geIcon geSprite geSprite-curved', null, true).setAttribute('title', mxResources.get('curved'));
  4661. }
  4662. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_EDGE, mxConstants.STYLE_CURVED, mxConstants.STYLE_NOEDGESTYLE], ['entityRelationEdgeStyle', null, null], 'geIcon geSprite geSprite-entity', null, true).setAttribute('title', mxResources.get('entityRelation'));
  4663. }
  4664. }));
  4665. var lineStart = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-startclassic', mxResources.get('linestart'), false, mxUtils.bind(this, function(menu)
  4666. {
  4667. if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
  4668. {
  4669. var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.NONE, 0], 'geIcon', null, false);
  4670. item.setAttribute('title', mxResources.get('none'));
  4671. var font = document.createElement('span');
  4672. font.style.fontSize = '11px';
  4673. mxUtils.write(font, mxResources.get('none'));
  4674. item.firstChild.firstChild.appendChild(font);
  4675. if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
  4676. {
  4677. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src));
  4678. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src));
  4679. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src));
  4680. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src));
  4681. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src));
  4682. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src));
  4683. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src));
  4684. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src));
  4685. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src));
  4686. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src));
  4687. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src));
  4688. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src));
  4689. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src));
  4690. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src));
  4691. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src));
  4692. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src));
  4693. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src));
  4694. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src));
  4695. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src));
  4696. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src));
  4697. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src));
  4698. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src));
  4699. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src));
  4700. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src));
  4701. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['circle', 1], null, null, false, Format.circleMarkerImage.src));
  4702. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src));
  4703. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src));
  4704. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src));
  4705. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src));
  4706. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src));
  4707. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src));
  4708. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src));
  4709. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src));
  4710. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW, 'startFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src));
  4711. }
  4712. else
  4713. {
  4714. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_STARTARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-startblocktrans', null, false).setAttribute('title', mxResources.get('block'));
  4715. }
  4716. menu.div.style.width = '40px';
  4717. window.setTimeout(mxUtils.bind(this, function()
  4718. {
  4719. if (menu.div != null)
  4720. {
  4721. mxUtils.fit(menu.div);
  4722. }
  4723. }), 0);
  4724. }
  4725. }));
  4726. var lineEnd = this.editorUi.toolbar.addMenuFunctionInContainer(stylePanel2, 'geSprite-endclassic', mxResources.get('lineend'), false, mxUtils.bind(this, function(menu)
  4727. {
  4728. if (ss.style.shape == 'connector' || ss.style.shape == 'flexArrow' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
  4729. {
  4730. var item = this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.NONE, 0], 'geIcon', null, false);
  4731. item.setAttribute('title', mxResources.get('none'));
  4732. var font = document.createElement('span');
  4733. font.style.fontSize = '11px';
  4734. mxUtils.write(font, mxResources.get('none'));
  4735. item.firstChild.firstChild.appendChild(font);
  4736. if (ss.style.shape == 'connector' || ss.style.shape == 'filledEdge' || ss.style.shape == 'wire')
  4737. {
  4738. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 1], null, null, false, Format.classicFilledMarkerImage.src), 'scaleX(-1)');
  4739. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 1], null, null, false, Format.classicThinFilledMarkerImage.src), 'scaleX(-1)');
  4740. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN, 0], null, null, false, Format.openFilledMarkerImage.src), 'scaleX(-1)');
  4741. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OPEN_THIN, 0], null, null, false, Format.openThinFilledMarkerImage.src), 'scaleX(-1)');
  4742. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['openAsync', 0], null, null, false, Format.openAsyncFilledMarkerImage.src), 'scaleX(-1)');
  4743. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 1], null, null, false, Format.blockFilledMarkerImage.src), 'scaleX(-1)');
  4744. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 1], null, null, false, Format.blockThinFilledMarkerImage.src), 'scaleX(-1)');
  4745. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 1], null, null, false, Format.asyncFilledMarkerImage.src), 'scaleX(-1)');
  4746. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 1], null, null, false, Format.ovalFilledMarkerImage.src), 'scaleX(-1)');
  4747. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 1], null, null, false, Format.diamondFilledMarkerImage.src), 'scaleX(-1)');
  4748. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 1], null, null, false, Format.diamondThinFilledMarkerImage.src), 'scaleX(-1)');
  4749. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC, 0], null, null, false, Format.classicMarkerImage.src), 'scaleX(-1)');
  4750. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_CLASSIC_THIN, 0], null, null, false, Format.classicThinMarkerImage.src), 'scaleX(-1)');
  4751. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK, 0], null, null, false, Format.blockMarkerImage.src), 'scaleX(-1)');
  4752. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_BLOCK_THIN, 0], null, null, false, Format.blockThinMarkerImage.src), 'scaleX(-1)');
  4753. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['async', 0], null, null, false, Format.asyncMarkerImage.src), 'scaleX(-1)');
  4754. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_OVAL, 0], null, null, false, Format.ovalMarkerImage.src), 'scaleX(-1)');
  4755. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND, 0], null, null, false, Format.diamondMarkerImage.src), 'scaleX(-1)');
  4756. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], [mxConstants.ARROW_DIAMOND_THIN, 0], null, null, false, Format.diamondThinMarkerImage.src), 'scaleX(-1)');
  4757. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['box', 0], null, null, false, Format.boxMarkerImage.src), 'scaleX(-1)');
  4758. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['halfCircle', 0], null, null, false, Format.halfCircleMarkerImage.src), 'scaleX(-1)');
  4759. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['dash', 0], null, null, false, Format.dashMarkerImage.src), 'scaleX(-1)');
  4760. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['cross', 0], null, null, false, Format.crossMarkerImage.src), 'scaleX(-1)');
  4761. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circlePlus', 0], null, null, false, Format.circlePlusMarkerImage.src), 'scaleX(-1)');
  4762. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['circle', 0], null, null, false, Format.circleMarkerImage.src), 'scaleX(-1)');
  4763. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['baseDash', 0], null, null, false, Format.baseDashMarkerImage.src), 'scaleX(-1)');
  4764. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERone', 0], null, null, false, Format.EROneMarkerImage.src), 'scaleX(-1)');
  4765. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmandOne', 0], null, null, false, Format.ERmandOneMarkerImage.src), 'scaleX(-1)');
  4766. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERmany', 0], null, null, false, Format.ERmanyMarkerImage.src), 'scaleX(-1)');
  4767. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERoneToMany', 0], null, null, false, Format.ERoneToManyMarkerImage.src), 'scaleX(-1)');
  4768. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToOne', 0], null, null, false, Format.ERzeroToOneMarkerImage.src), 'scaleX(-1)');
  4769. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['ERzeroToMany', 0], null, null, false, Format.ERzeroToManyMarkerImage.src), 'scaleX(-1)');
  4770. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 0], null, null, false, Format.doubleBlockMarkerImage.src), 'scaleX(-1)');
  4771. Format.processMenuIcon(this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW, 'endFill'], ['doubleBlock', 1], null, null, false, Format.doubleBlockFilledMarkerImage.src), 'scaleX(-1)');
  4772. }
  4773. else
  4774. {
  4775. this.editorUi.menus.edgeStyleChange(menu, '', [mxConstants.STYLE_ENDARROW], [mxConstants.ARROW_BLOCK], 'geIcon geSprite geSprite-endblocktrans', null, false).setAttribute('title', mxResources.get('block'));
  4776. }
  4777. menu.div.style.width = '40px';
  4778. window.setTimeout(mxUtils.bind(this, function()
  4779. {
  4780. if (menu.div != null)
  4781. {
  4782. mxUtils.fit(menu.div);
  4783. }
  4784. }), 0);
  4785. }
  4786. }));
  4787. this.addArrow(edgeShape);
  4788. this.addArrow(edgeStyle).style.marginTop = '-1px';
  4789. this.addArrow(lineStart);
  4790. this.addArrow(lineEnd);
  4791. var symbol = this.addArrow(pattern);
  4792. symbol.className = 'geIcon';
  4793. pattern.style.width = '134px';
  4794. var altSymbol = this.addArrow(altPattern);
  4795. altSymbol.className = 'geIcon';
  4796. altSymbol.style.width = '22px';
  4797. var solid = document.createElement('div');
  4798. solid.style.width = '102px';
  4799. solid.style.height = '10px';
  4800. solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
  4801. solid.style.marginLeft = '10px';
  4802. symbol.appendChild(solid);
  4803. var altSolid = document.createElement('div');
  4804. altSolid.style.width = '30px';
  4805. altSolid.style.height = '10px';
  4806. altSolid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
  4807. altSolid.style.marginLeft = '10px';
  4808. altSymbol.appendChild(altSolid);
  4809. container.appendChild(colorPanel);
  4810. container.appendChild(altStylePanel);
  4811. container.appendChild(stylePanel);
  4812. var arrowPanel = stylePanel.cloneNode(false);
  4813. arrowPanel.style.display = 'block';
  4814. arrowPanel.style.padding = '5px 4px 6px 0px';
  4815. arrowPanel.style.fontWeight = 'normal';
  4816. var span = document.createElement('div');
  4817. span.style.position = 'absolute';
  4818. span.style.maxWidth = '78px';
  4819. span.style.overflow = 'hidden';
  4820. span.style.textOverflow = 'ellipsis';
  4821. span.style.marginLeft = '0px';
  4822. span.style.marginBottom = '12px';
  4823. span.style.marginTop = '2px';
  4824. span.style.fontWeight = 'normal';
  4825. mxUtils.write(span, mxResources.get('lineend'));
  4826. arrowPanel.appendChild(span);
  4827. var endSpacingUpdate, endSizeUpdate;
  4828. var endSpacing = this.addUnitInput(arrowPanel, this.getUnit(), 98, 52, function()
  4829. {
  4830. endSpacingUpdate.apply(this, arguments);
  4831. }, this.getUnitStep(), null, null, this.isFloatUnit());
  4832. var endSize = this.addUnitInput(arrowPanel, this.getUnit(), 30, 52, function()
  4833. {
  4834. endSizeUpdate.apply(this, arguments);
  4835. }, this.getUnitStep(), null, null, this.isFloatUnit());
  4836. mxUtils.br(arrowPanel);
  4837. var spacer = document.createElement('div');
  4838. spacer.style.height = '8px';
  4839. arrowPanel.appendChild(spacer);
  4840. span = span.cloneNode(false);
  4841. mxUtils.write(span, mxResources.get('linestart'));
  4842. arrowPanel.appendChild(span);
  4843. var startSpacingUpdate, startSizeUpdate;
  4844. var startSpacing = this.addUnitInput(arrowPanel, this.getUnit(), 98, 52, function()
  4845. {
  4846. startSpacingUpdate.apply(this, arguments);
  4847. }, this.getUnitStep(), null, null, this.isFloatUnit());
  4848. var startSize = this.addUnitInput(arrowPanel, this.getUnit(), 30, 52, function()
  4849. {
  4850. startSizeUpdate.apply(this, arguments);
  4851. }, this.getUnitStep(), null, null, this.isFloatUnit());
  4852. mxUtils.br(arrowPanel);
  4853. this.addLabel(arrowPanel, mxResources.get('spacing'),
  4854. 98, 64).style.fontSize = '11px';
  4855. this.addLabel(arrowPanel, mxResources.get('size'),
  4856. 30, 64).style.fontSize = '11px';
  4857. mxUtils.br(arrowPanel);
  4858. var perimeterPanel = colorPanel.cloneNode(false);
  4859. perimeterPanel.style.fontWeight = 'normal';
  4860. perimeterPanel.style.position = 'relative';
  4861. perimeterPanel.style.paddingLeft = '16px'
  4862. perimeterPanel.style.marginBottom = '2px';
  4863. perimeterPanel.style.marginTop = '6px';
  4864. perimeterPanel.style.borderWidth = '0px';
  4865. perimeterPanel.style.paddingBottom = '18px';
  4866. var span = document.createElement('div');
  4867. span.style.position = 'absolute';
  4868. span.style.marginLeft = '3px';
  4869. span.style.marginBottom = '12px';
  4870. span.style.marginTop = '1px';
  4871. span.style.fontWeight = 'normal';
  4872. span.style.width = '120px';
  4873. mxUtils.write(span, mxResources.get('perimeter'));
  4874. perimeterPanel.appendChild(span);
  4875. var perimeterUpdate;
  4876. var perimeterSpacing = this.addUnitInput(perimeterPanel, this.getUnit(), 30, 52, function()
  4877. {
  4878. perimeterUpdate.apply(this, arguments);
  4879. }, this.getUnitStep(), null, null, this.isFloatUnit());
  4880. if (ss.edges.length == ss.cells.length)
  4881. {
  4882. container.appendChild(stylePanel2);
  4883. container.appendChild(arrowPanel);
  4884. }
  4885. else if (ss.vertices.length == ss.cells.length)
  4886. {
  4887. container.appendChild(perimeterPanel);
  4888. }
  4889. var listener = mxUtils.bind(this, function(sender, evt, force)
  4890. {
  4891. ss = ui.getSelectionState();
  4892. if (force || document.activeElement != input)
  4893. {
  4894. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1));
  4895. input.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  4896. }
  4897. if (force || document.activeElement != altInput)
  4898. {
  4899. var tmp = parseFloat(mxUtils.getValue(ss.style, mxConstants.STYLE_STROKEWIDTH, 1));
  4900. altInput.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  4901. }
  4902. styleSelect.style.visibility = (ss.style.shape == 'connector' ||
  4903. ss.style.shape == 'filledEdge' || ss.style.shape == 'wire') ?
  4904. '' : 'hidden';
  4905. if (mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1')
  4906. {
  4907. styleSelect.value = 'curved';
  4908. }
  4909. else if (mxUtils.getValue(ss.style, mxConstants.STYLE_ROUNDED, null) == '1')
  4910. {
  4911. styleSelect.value = 'rounded';
  4912. }
  4913. if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASHED, null) == '1')
  4914. {
  4915. if (mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, null) == null ||
  4916. String(mxUtils.getValue(ss.style, mxConstants.STYLE_DASH_PATTERN, '')).substring(0, 2) != '1 ')
  4917. {
  4918. solid.style.borderBottom = '1px dashed ' + this.defaultStrokeColor;
  4919. }
  4920. else
  4921. {
  4922. solid.style.borderBottom = '1px dotted ' + this.defaultStrokeColor;
  4923. }
  4924. }
  4925. else
  4926. {
  4927. solid.style.borderBottom = '1px solid ' + this.defaultStrokeColor;
  4928. }
  4929. altSolid.style.borderBottom = solid.style.borderBottom;
  4930. // Updates toolbar icon for edge style
  4931. var edgeStyleDiv = edgeStyle.getElementsByTagName('div')[0];
  4932. if (edgeStyleDiv != null)
  4933. {
  4934. var es = mxUtils.getValue(ss.style, mxConstants.STYLE_EDGE, null);
  4935. if (mxUtils.getValue(ss.style, mxConstants.STYLE_NOEDGESTYLE, null) == '1')
  4936. {
  4937. es = null;
  4938. }
  4939. if (es == 'orthogonalEdgeStyle' && mxUtils.getValue(ss.style, mxConstants.STYLE_CURVED, null) == '1')
  4940. {
  4941. edgeStyleDiv.className = 'geSprite geSprite-curved';
  4942. }
  4943. else if (es == 'straight' || es == 'none' || es == null)
  4944. {
  4945. edgeStyleDiv.className = 'geSprite geSprite-straight';
  4946. }
  4947. else if (es == 'entityRelationEdgeStyle')
  4948. {
  4949. edgeStyleDiv.className = 'geSprite geSprite-entity';
  4950. }
  4951. else if (es == 'elbowEdgeStyle')
  4952. {
  4953. edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style,
  4954. mxConstants.STYLE_ELBOW, null) == 'vertical') ?
  4955. 'geSprite-verticalelbow' : 'geSprite-horizontalelbow');
  4956. }
  4957. else if (es == 'isometricEdgeStyle')
  4958. {
  4959. edgeStyleDiv.className = 'geSprite ' + ((mxUtils.getValue(ss.style,
  4960. mxConstants.STYLE_ELBOW, null) == 'vertical') ?
  4961. 'geSprite-verticalisometric' : 'geSprite-horizontalisometric');
  4962. }
  4963. else
  4964. {
  4965. edgeStyleDiv.className = 'geSprite geSprite-orthogonal';
  4966. }
  4967. }
  4968. // Updates icon for edge shape
  4969. var edgeShapeDiv = edgeShape.getElementsByTagName('div')[0];
  4970. if (edgeShapeDiv != null)
  4971. {
  4972. if (ss.style.shape == 'link')
  4973. {
  4974. edgeShapeDiv.className = 'geSprite geSprite-linkedge';
  4975. }
  4976. else if (ss.style.shape == 'flexArrow')
  4977. {
  4978. edgeShapeDiv.className = 'geSprite geSprite-arrow';
  4979. }
  4980. else if (ss.style.shape == 'arrow')
  4981. {
  4982. edgeShapeDiv.className = 'geSprite geSprite-simplearrow';
  4983. }
  4984. else
  4985. {
  4986. edgeShapeDiv.className = 'geSprite geSprite-connection';
  4987. }
  4988. }
  4989. if (ss.edges.length == ss.cells.length)
  4990. {
  4991. altStylePanel.style.display = '';
  4992. stylePanel.style.display = 'none';
  4993. }
  4994. else
  4995. {
  4996. altStylePanel.style.display = 'none';
  4997. stylePanel.style.display = '';
  4998. }
  4999. if (Graph.lineJumpsEnabled && ss.edges.length > 0 &&
  5000. ss.vertices.length == 0 && ss.lineJumps)
  5001. {
  5002. container.style.borderBottomStyle = 'none';
  5003. }
  5004. function updateArrow(marker, fill, elt, prefix)
  5005. {
  5006. var markerDiv = elt.getElementsByTagName('div')[0];
  5007. if (markerDiv != null)
  5008. {
  5009. ui.updateCssForMarker(markerDiv, prefix, ss.style.shape, marker, fill);
  5010. }
  5011. return markerDiv;
  5012. };
  5013. var sourceDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTARROW, null),
  5014. mxUtils.getValue(ss.style, 'startFill', '1'), lineStart, 'start');
  5015. var targetDiv = updateArrow(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDARROW, null),
  5016. mxUtils.getValue(ss.style, 'endFill', '1'), lineEnd, 'end');
  5017. // Special cases for markers
  5018. if (sourceDiv != null && targetDiv != null)
  5019. {
  5020. if (ss.style.shape == 'arrow')
  5021. {
  5022. sourceDiv.className = 'geSprite geSprite-noarrow';
  5023. targetDiv.className = 'geSprite geSprite-endblocktrans';
  5024. }
  5025. else if (ss.style.shape == 'link')
  5026. {
  5027. sourceDiv.className = 'geSprite geSprite-noarrow';
  5028. targetDiv.className = 'geSprite geSprite-noarrow';
  5029. }
  5030. }
  5031. mxUtils.setOpacity(edgeStyle, (ss.style.shape == 'arrow') ? 30 : 100);
  5032. if (ss.style.shape != 'connector' && ss.style.shape != 'flexArrow' &&
  5033. ss.style.shape != 'filledEdge' && ss.style.shape != 'wire')
  5034. {
  5035. mxUtils.setOpacity(lineStart, 30);
  5036. mxUtils.setOpacity(lineEnd, 30);
  5037. }
  5038. else
  5039. {
  5040. mxUtils.setOpacity(lineStart, 100);
  5041. mxUtils.setOpacity(lineEnd, 100);
  5042. }
  5043. if (force || document.activeElement != startSize)
  5044. {
  5045. var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE));
  5046. startSize.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5047. }
  5048. if (force || document.activeElement != startSpacing)
  5049. {
  5050. var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0));
  5051. startSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5052. }
  5053. if (force || document.activeElement != endSize)
  5054. {
  5055. var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE));
  5056. endSize.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5057. }
  5058. if (force || document.activeElement != startSpacing)
  5059. {
  5060. var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0));
  5061. endSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5062. }
  5063. if (force || document.activeElement != perimeterSpacing)
  5064. {
  5065. var tmp = parseInt(mxUtils.getValue(ss.style, mxConstants.STYLE_PERIMETER_SPACING, 0));
  5066. perimeterSpacing.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5067. }
  5068. });
  5069. startSizeUpdate = this.installInputHandler(startSize, mxConstants.STYLE_STARTSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999,
  5070. this.getUnit(' '), null, this.isFloatUnit(), true);
  5071. startSpacingUpdate = this.installInputHandler(startSpacing, mxConstants.STYLE_SOURCE_PERIMETER_SPACING, 0, -999, 999,
  5072. this.getUnit(' '), null, this.isFloatUnit(), true);
  5073. endSizeUpdate = this.installInputHandler(endSize, mxConstants.STYLE_ENDSIZE, mxConstants.DEFAULT_MARKERSIZE, 0, 999,
  5074. this.getUnit(' '), null, this.isFloatUnit(), true);
  5075. endSpacingUpdate = this.installInputHandler(endSpacing, mxConstants.STYLE_TARGET_PERIMETER_SPACING, 0, -999, 999,
  5076. this.getUnit(' '), null, this.isFloatUnit(), true);
  5077. perimeterUpdate = this.installInputHandler(perimeterSpacing, mxConstants.STYLE_PERIMETER_SPACING, 0, 0, 999,
  5078. this.getUnit(' '), null, this.isFloatUnit(), true);
  5079. this.addKeyHandler(input, listener);
  5080. this.addKeyHandler(startSize, listener);
  5081. this.addKeyHandler(startSpacing, listener);
  5082. this.addKeyHandler(endSize, listener);
  5083. this.addKeyHandler(endSpacing, listener);
  5084. this.addKeyHandler(perimeterSpacing, listener);
  5085. graph.getModel().addListener(mxEvent.CHANGE, listener);
  5086. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  5087. listener();
  5088. return container;
  5089. };
  5090. /**
  5091. * Adds UI for configuring line jumps.
  5092. */
  5093. StyleFormatPanel.prototype.addLineJumps = function(container)
  5094. {
  5095. var ui = this.editorUi;
  5096. var editor = ui.editor;
  5097. var graph = editor.graph;
  5098. var ss = ui.getSelectionState();
  5099. if (Graph.lineJumpsEnabled && ss.edges.length > 0 &&
  5100. ss.vertices.length == 0 && ss.lineJumps)
  5101. {
  5102. container.style.padding = '2px 0px 24px 14px';
  5103. var span = document.createElement('div');
  5104. span.style.position = 'absolute';
  5105. span.style.maxWidth = '78px';
  5106. span.style.overflow = 'hidden';
  5107. span.style.textOverflow = 'ellipsis';
  5108. mxUtils.write(span, mxResources.get('lineJumps'));
  5109. container.appendChild(span);
  5110. var styleSelect = document.createElement('select');
  5111. styleSelect.style.position = 'absolute';
  5112. styleSelect.style.height = '21px';
  5113. styleSelect.style.padding = '0px';
  5114. styleSelect.style.marginTop = '-2px';
  5115. styleSelect.style.boxSizing = 'border-box';
  5116. styleSelect.style.textAlign = 'center';
  5117. styleSelect.style.right = '84px';
  5118. styleSelect.style.width = '64px';
  5119. styleSelect.style.borderWidth = '1px';
  5120. styleSelect.style.borderStyle = 'solid';
  5121. var styles = ['none', 'arc', 'gap', 'sharp', 'line'];
  5122. for (var i = 0; i < styles.length; i++)
  5123. {
  5124. var styleOption = document.createElement('option');
  5125. styleOption.setAttribute('value', styles[i]);
  5126. mxUtils.write(styleOption, mxResources.get(styles[i]));
  5127. styleSelect.appendChild(styleOption);
  5128. }
  5129. mxEvent.addListener(styleSelect, 'change', function(evt)
  5130. {
  5131. graph.getModel().beginUpdate();
  5132. try
  5133. {
  5134. graph.setCellStyles('jumpStyle', styleSelect.value, ss.cells);
  5135. ui.fireEvent(new mxEventObject('styleChanged', 'keys', ['jumpStyle'],
  5136. 'values', [styleSelect.value], 'cells', ss.cells));
  5137. }
  5138. finally
  5139. {
  5140. graph.getModel().endUpdate();
  5141. }
  5142. mxEvent.consume(evt);
  5143. });
  5144. // Stops events from bubbling to color option event handler
  5145. mxEvent.addListener(styleSelect, 'click', function(evt)
  5146. {
  5147. mxEvent.consume(evt);
  5148. });
  5149. container.appendChild(styleSelect);
  5150. var jumpSizeUpdate;
  5151. var jumpSize = this.addUnitInput(container, this.getUnit(), 16, 52, function()
  5152. {
  5153. jumpSizeUpdate.apply(this, arguments);
  5154. }, this.getUnitStep(), null, null, this.isFloatUnit());
  5155. jumpSizeUpdate = this.installInputHandler(jumpSize, 'jumpSize', Graph.defaultJumpSize,
  5156. 0, 999, this.getUnit(' '), null, this.isFloatUnit(), true);
  5157. var listener = mxUtils.bind(this, function(sender, evt, force)
  5158. {
  5159. ss = ui.getSelectionState();
  5160. styleSelect.value = mxUtils.getValue(ss.style, 'jumpStyle', 'none');
  5161. if (force || document.activeElement != jumpSize)
  5162. {
  5163. var tmp = parseInt(mxUtils.getValue(ss.style, 'jumpSize', Graph.defaultJumpSize));
  5164. jumpSize.value = (isNaN(tmp)) ? '' : this.inUnit(tmp) + ' ' + this.getUnit();
  5165. }
  5166. });
  5167. this.addKeyHandler(jumpSize, listener);
  5168. graph.getModel().addListener(mxEvent.CHANGE, listener);
  5169. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  5170. listener();
  5171. }
  5172. else
  5173. {
  5174. container.style.display = 'none';
  5175. }
  5176. return container;
  5177. };
  5178. /**
  5179. * Adds the label menu items to the given menu and parent.
  5180. */
  5181. StyleFormatPanel.prototype.addEffects = function(div)
  5182. {
  5183. var ui = this.editorUi;
  5184. var editor = ui.editor;
  5185. var graph = editor.graph;
  5186. var ss = ui.getSelectionState();
  5187. div.style.paddingTop = '4px';
  5188. div.style.paddingBottom = '4px';
  5189. var table = document.createElement('table');
  5190. table.style.width = '210px';
  5191. table.style.fontWeight = 'bold';
  5192. table.style.tableLayout = 'fixed';
  5193. var tbody = document.createElement('tbody');
  5194. var row = document.createElement('tr');
  5195. row.style.padding = '0px';
  5196. var left = document.createElement('td');
  5197. left.style.padding = '0px';
  5198. left.style.width = '50%';
  5199. left.setAttribute('valign', 'top');
  5200. var right = left.cloneNode(true);
  5201. right.style.paddingLeft = '8px';
  5202. row.appendChild(left);
  5203. row.appendChild(right);
  5204. tbody.appendChild(row);
  5205. table.appendChild(tbody);
  5206. div.appendChild(table);
  5207. var current = left;
  5208. var addOption = mxUtils.bind(this, function(label, key, defaultValue, fn)
  5209. {
  5210. var opt = this.createCellOption(label, key, defaultValue, null, null, fn);
  5211. opt.style.width = '100%';
  5212. current.appendChild(opt);
  5213. current = (current == left) ? right : left;
  5214. return opt;
  5215. });
  5216. var listener = mxUtils.bind(this, function(sender, evt, force)
  5217. {
  5218. ss = ui.getSelectionState();
  5219. left.innerText = '';
  5220. right.innerText = '';
  5221. current = left;
  5222. if (ss.rounded)
  5223. {
  5224. addOption(mxResources.get('rounded'), mxConstants.STYLE_ROUNDED, 0);
  5225. }
  5226. if (ss.swimlane)
  5227. {
  5228. addOption(mxResources.get('divider'), 'swimlaneLine', 1);
  5229. }
  5230. addOption(mxResources.get('sketch'), 'sketch', 0, function(cells, enabled)
  5231. {
  5232. graph.updateCellStyles({'sketch': (enabled) ? '1' : null,
  5233. 'curveFitting': (enabled) ? Editor.sketchDefaultCurveFitting : null,
  5234. 'jiggle': (enabled) ? Editor.sketchDefaultJiggle : null}, cells);
  5235. });
  5236. if (ss.glass)
  5237. {
  5238. addOption(mxResources.get('glass'), mxConstants.STYLE_GLASS, 0);
  5239. }
  5240. var option = addOption(mxResources.get('shadow'), mxConstants.STYLE_SHADOW, 0);
  5241. if (!Editor.enableShadowOption)
  5242. {
  5243. option.getElementsByTagName('input')[0].setAttribute('disabled', 'disabled');
  5244. mxUtils.setOpacity(option, 60);
  5245. }
  5246. if (ss.edges.length > 0 && ss.vertices.length == 0)
  5247. {
  5248. addOption(mxResources.get('flowAnimation', null, 'Flow Animation'), 'flowAnimation', 0);
  5249. }
  5250. });
  5251. graph.getModel().addListener(mxEvent.CHANGE, listener);
  5252. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  5253. listener();
  5254. return div;
  5255. }
  5256. /**
  5257. * Adds the label menu items to the given menu and parent.
  5258. */
  5259. StyleFormatPanel.prototype.addStyleOps = function(div)
  5260. {
  5261. var ss = this.editorUi.getSelectionState();
  5262. if (ss.cells.length == 1)
  5263. {
  5264. this.addActions(div, ['setAsDefaultStyle']);
  5265. }
  5266. return div;
  5267. };
  5268. /**
  5269. * Adds the label menu items to the given menu and parent.
  5270. */
  5271. DiagramStylePanel = function(format, editorUi, container)
  5272. {
  5273. BaseFormatPanel.call(this, format, editorUi, container);
  5274. this.init();
  5275. };
  5276. mxUtils.extend(DiagramStylePanel, BaseFormatPanel);
  5277. /**
  5278. * Adds the label menu items to the given menu and parent.
  5279. */
  5280. DiagramStylePanel.prototype.init = function()
  5281. {
  5282. var ui = this.editorUi;
  5283. this.darkModeChangedListener = mxUtils.bind(this, function()
  5284. {
  5285. this.format.cachedStyleEntries = [];
  5286. });
  5287. ui.addListener('darkModeChanged', this.darkModeChangedListener);
  5288. this.container.appendChild(this.addView(this.createPanel()));
  5289. };
  5290. /**
  5291. * Adds the label menu items to the given menu and parent.
  5292. */
  5293. DiagramStylePanel.prototype.getGlobalStyleButtons = function()
  5294. {
  5295. var ui = this.editorUi;
  5296. var editor = ui.editor;
  5297. var graph = editor.graph;
  5298. var sketchDiv = document.createElement('div');
  5299. sketchDiv.style.fontWeight = 'bold';
  5300. sketchDiv.style.alignItems = 'center';
  5301. sketchDiv.style.textAlign = 'left';
  5302. sketchDiv.style.display = 'flex';
  5303. sketchDiv.style.padding = '4px';
  5304. var sketchInput = document.createElement('input');
  5305. sketchInput.setAttribute('type', 'checkbox');
  5306. sketchInput.style.margin = '1px 6px 0px 0px';
  5307. sketchInput.checked = Editor.sketchMode;
  5308. sketchDiv.appendChild(sketchInput);
  5309. mxUtils.write(sketchDiv, mxResources.get('sketch'));
  5310. mxEvent.addListener(sketchDiv, 'click', function(evt)
  5311. {
  5312. if (graph.isEnabled())
  5313. {
  5314. var value = !Editor.sketchMode;
  5315. // Temporary overrides sketch mode to avoid flickering
  5316. // for the first async update after updating cells
  5317. Editor.sketchMode = value;
  5318. graph.updateCellStyles({'sketch': (value) ? '1' : null,
  5319. 'curveFitting': (value) ? Editor.sketchDefaultCurveFitting : null,
  5320. 'jiggle': (value) ? Editor.sketchDefaultJiggle : null},
  5321. graph.getVerticesAndEdges());
  5322. mxEvent.consume(evt);
  5323. // Restores and udpates sketch mode asynchronously
  5324. window.setTimeout(function()
  5325. {
  5326. Editor.sketchMode = !value;
  5327. ui.setSketchMode(value);
  5328. });
  5329. }
  5330. });
  5331. var buttons = [sketchDiv, mxUtils.button(mxResources.get('rounded'),
  5332. mxUtils.bind(this, function(evt)
  5333. {
  5334. // Checks if all cells are rounded
  5335. var cells = graph.getVerticesAndEdges();
  5336. var rounded = true;
  5337. if (cells.length > 0)
  5338. {
  5339. for (var i = 0; i < cells.length; i++)
  5340. {
  5341. var style = graph.getCellStyle(cells[i]);
  5342. if (mxUtils.getValue(style, mxConstants.STYLE_ROUNDED, 0) == 0)
  5343. {
  5344. rounded = false;
  5345. break;
  5346. }
  5347. }
  5348. }
  5349. rounded = !rounded;
  5350. graph.updateCellStyles({'rounded': (rounded) ? '1' : '0'}, cells);
  5351. if (rounded)
  5352. {
  5353. graph.currentEdgeStyle['rounded'] = '1';
  5354. graph.currentVertexStyle['rounded'] = '1';
  5355. }
  5356. else
  5357. {
  5358. delete graph.currentEdgeStyle['rounded'];
  5359. delete graph.currentVertexStyle['rounded'];
  5360. }
  5361. mxEvent.consume(evt);
  5362. }
  5363. ))];
  5364. if (!graph.isEnabled())
  5365. {
  5366. for (var i = 0; i < buttons.length; i++)
  5367. {
  5368. if (buttons[i].nodeName == 'BUTTON')
  5369. {
  5370. buttons[i].setAttribute('disabled', 'disabled');
  5371. }
  5372. else
  5373. {
  5374. var inp = buttons[i].getElementsByTagName('input');
  5375. if (inp.length > 0)
  5376. {
  5377. inp[0].setAttribute('disabled', 'disabled');
  5378. }
  5379. }
  5380. }
  5381. }
  5382. return buttons;
  5383. };
  5384. /**
  5385. * Adds the label menu items to the given menu and parent.
  5386. */
  5387. DiagramStylePanel.prototype.addView = function(div)
  5388. {
  5389. var ui = this.editorUi;
  5390. var editor = ui.editor;
  5391. var graph = editor.graph;
  5392. div.style.paddingTop = '2px';
  5393. div.style.whiteSpace = 'normal';
  5394. var opts = document.createElement('div');
  5395. opts.style.marginRight = '16px';
  5396. opts.style.paddingBottom = '2px';
  5397. var table = document.createElement('table');
  5398. table.style.width = '204px';
  5399. var tbody = document.createElement('tbody');
  5400. var row = document.createElement('tr');
  5401. row.style.padding = '0px';
  5402. var left = document.createElement('td');
  5403. left.style.textAlign = 'center';
  5404. left.style.padding = '2px';
  5405. left.style.width = '50%';
  5406. var right = left.cloneNode(true);
  5407. var buttons = this.getGlobalStyleButtons();
  5408. for (var i = 0; i < buttons.length; i += 2)
  5409. {
  5410. var btn = buttons[i];
  5411. btn.style.height = '22px';
  5412. btn.style.width = '92px';
  5413. left.appendChild(btn);
  5414. row.appendChild(left);
  5415. btn = buttons[i + 1];
  5416. if (btn != null)
  5417. {
  5418. btn.style.height = '22px';
  5419. btn.style.width = '92px';
  5420. right.appendChild(btn);
  5421. }
  5422. row.appendChild(right);
  5423. tbody.appendChild(row);
  5424. left = left.cloneNode(false);
  5425. right = right.cloneNode(false);
  5426. row = row.cloneNode(false);
  5427. }
  5428. table.appendChild(tbody);
  5429. opts.appendChild(table);
  5430. div.appendChild(opts);
  5431. if (graph.isEnabled())
  5432. {
  5433. this.addGraphStyles(div);
  5434. }
  5435. return div;
  5436. };
  5437. /**
  5438. * Adds the label menu items to the given menu and parent.
  5439. */
  5440. DiagramStylePanel.prototype.addGraphStyles = function(div)
  5441. {
  5442. var ui = this.editorUi;
  5443. var editor = ui.editor;
  5444. var graph = editor.graph;
  5445. var model = graph.getModel();
  5446. var gridColor = graph.view.gridColor;
  5447. var defaultStyles = ['fillColor', 'strokeColor', 'fontColor', 'gradientColor'];
  5448. div.style.whiteSpace = 'normal';
  5449. div.style.paddingLeft = '18px';
  5450. div.style.paddingTop = '6px';
  5451. var updateCells = mxUtils.bind(this, function(styles, graphStyle)
  5452. {
  5453. var cells = graph.getVerticesAndEdges();
  5454. model.beginUpdate();
  5455. try
  5456. {
  5457. for (var i = 0; i < cells.length; i++)
  5458. {
  5459. var style = graph.getCellStyle(cells[i]);
  5460. // Handles special label background color
  5461. if (!ignoreGraphStyle && style['labelBackgroundColor'] != null)
  5462. {
  5463. graph.updateCellStyles({'labelBackgroundColor': (graphStyle != null) ?
  5464. graphStyle.background : null}, [cells[i]]);
  5465. }
  5466. else if (ignoreGraphStyle)
  5467. {
  5468. graph.updateCellStyles({'labelBackgroundColor': mxConstants.NONE}, [cells[i]]);
  5469. }
  5470. var edge = model.isEdge(cells[i]);
  5471. var newStyle = model.getStyle(cells[i]);
  5472. var current = (edge) ? graph.currentEdgeStyle : graph.currentVertexStyle;
  5473. for (var j = 0; j < styles.length; j++)
  5474. {
  5475. if ((style[styles[j]] != null && style[styles[j]] != mxConstants.NONE) ||
  5476. (styles[j] != mxConstants.STYLE_FILLCOLOR &&
  5477. styles[j] != mxConstants.STYLE_STROKECOLOR))
  5478. {
  5479. if (ignoreGraphStyle && edge && styles[j] == mxConstants.STYLE_FONTCOLOR)
  5480. {
  5481. newStyle = mxUtils.setStyle(newStyle, styles[j], 'default');
  5482. }
  5483. else
  5484. {
  5485. newStyle = mxUtils.setStyle(newStyle, styles[j], current[styles[j]]);
  5486. }
  5487. }
  5488. }
  5489. model.setStyle(cells[i], newStyle);
  5490. }
  5491. }
  5492. finally
  5493. {
  5494. model.endUpdate();
  5495. }
  5496. });
  5497. var removeStyles = mxUtils.bind(this, function(style, styles, defaultStyle)
  5498. {
  5499. if (style != null)
  5500. {
  5501. for (var j = 0; j < styles.length; j++)
  5502. {
  5503. if (((style[styles[j]] != null &&
  5504. style[styles[j]] != mxConstants.NONE) ||
  5505. (styles[j] != mxConstants.STYLE_FILLCOLOR &&
  5506. styles[j] != mxConstants.STYLE_STROKECOLOR)))
  5507. {
  5508. style[styles[j]] = defaultStyle[styles[j]];
  5509. }
  5510. }
  5511. }
  5512. });
  5513. var ignoreGraphStyle = true;
  5514. var applyStyle = mxUtils.bind(this, function(style, result, cell, graphStyle, theGraph)
  5515. {
  5516. if (style != null)
  5517. {
  5518. if (cell != null)
  5519. {
  5520. // Handles special label background color
  5521. if (!ignoreGraphStyle && result['labelBackgroundColor'] != null)
  5522. {
  5523. var bg = (graphStyle != null) ? graphStyle.background : null;
  5524. theGraph = (theGraph != null) ? theGraph : graph;
  5525. if (bg == null)
  5526. {
  5527. bg = theGraph.background;
  5528. }
  5529. if (bg == null)
  5530. {
  5531. bg = theGraph.defaultPageBackgroundColor;
  5532. }
  5533. result['labelBackgroundColor'] = bg;
  5534. }
  5535. else if (ignoreGraphStyle)
  5536. {
  5537. result['labelBackgroundColor'] = mxConstants.NONE;
  5538. }
  5539. }
  5540. for (var key in style)
  5541. {
  5542. if (cell == null || ((result[key] != null &&
  5543. result[key] != mxConstants.NONE) ||
  5544. (key != mxConstants.STYLE_FILLCOLOR &&
  5545. key != mxConstants.STYLE_STROKECOLOR)))
  5546. {
  5547. if (ignoreGraphStyle && model.isEdge(cell) &&
  5548. key == mxConstants.STYLE_FONTCOLOR)
  5549. {
  5550. result[key] = 'default';
  5551. }
  5552. else
  5553. {
  5554. result[key] = style[key];
  5555. }
  5556. }
  5557. }
  5558. }
  5559. });
  5560. var createPreview = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, container)
  5561. {
  5562. // Wrapper needed to catch events
  5563. var div = document.createElement('div');
  5564. div.style.background = (Editor.isDarkMode() ? '#2a252f' : '#f1f3f4');
  5565. div.style.position = 'absolute';
  5566. div.style.display = 'inline-block';
  5567. div.style.overflow = 'hidden';
  5568. div.style.pointerEvents = 'none';
  5569. div.style.width = '100%';
  5570. div.style.height = '100%';
  5571. container.appendChild(div);
  5572. var graph2 = new Graph(div, null, null, graph.getStylesheet());
  5573. graph2.shapeBackgroundColor = div.style.background;
  5574. graph2.resetViewOnRootChange = false;
  5575. graph2.foldingEnabled = false;
  5576. graph2.gridEnabled = false;
  5577. graph2.autoScroll = false;
  5578. graph2.setTooltips(false);
  5579. graph2.setConnectable(false);
  5580. graph2.setPanning(false);
  5581. graph2.setEnabled(false);
  5582. graph2.getCellStyle = function(cell, resolve)
  5583. {
  5584. resolve = (resolve != null) ? resolve : true;
  5585. var result = mxUtils.clone(graph.getCellStyle.apply(this, arguments));
  5586. var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
  5587. var appliedStyle = vertexStyle;
  5588. if (model.isEdge(cell))
  5589. {
  5590. defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
  5591. appliedStyle = edgeStyle;
  5592. }
  5593. removeStyles(result, defaultStyles, defaultStyle);
  5594. applyStyle(commonStyle, result, cell, graphStyle, graph2);
  5595. applyStyle(appliedStyle, result, cell, graphStyle, graph2);
  5596. if (resolve)
  5597. {
  5598. result = graph.postProcessCellStyle(cell, result);
  5599. }
  5600. return result;
  5601. };
  5602. // Avoid HTML labels to capture events in bubble phase
  5603. graph2.model.beginUpdate();
  5604. try
  5605. {
  5606. var v1 = graph2.insertVertex(graph2.getDefaultParent(), null, 'Shape', 14, 8, 70, 36, 'strokeWidth=2;');
  5607. var e1 = graph2.insertEdge(graph2.getDefaultParent(), null, 'Connector', v1, v1,
  5608. 'edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;endSize=5;strokeWidth=2;')
  5609. e1.geometry.points = [new mxPoint(32, 66)];
  5610. e1.geometry.offset = new mxPoint(0, 8);
  5611. }
  5612. finally
  5613. {
  5614. graph2.model.endUpdate();
  5615. }
  5616. });
  5617. // Entries
  5618. var entries = document.createElement('div');
  5619. entries.style.position = 'relative';
  5620. entries.style.width = '210px';
  5621. div.appendChild(entries);
  5622. // Cached entries
  5623. if (this.format.cachedStyleEntries == null)
  5624. {
  5625. this.format.cachedStyleEntries = [];
  5626. }
  5627. function addKeys(style, result)
  5628. {
  5629. for (var key in style)
  5630. {
  5631. result.push(key);
  5632. }
  5633. return result;
  5634. };
  5635. var addEntry = mxUtils.bind(this, function(commonStyle, vertexStyle, edgeStyle, graphStyle, index)
  5636. {
  5637. var panel = this.format.cachedStyleEntries[index];
  5638. if (panel == null)
  5639. {
  5640. panel = document.createElement('div');
  5641. panel.style.display = 'inline-block';
  5642. panel.style.position = 'relative';
  5643. panel.style.width = '96px';
  5644. panel.style.height = '86px';
  5645. panel.style.cursor = 'pointer';
  5646. panel.style.border = '1px solid gray';
  5647. panel.style.borderRadius = '8px';
  5648. panel.style.margin = '1px 2px';
  5649. panel.style.overflow = 'hidden';
  5650. if (!ignoreGraphStyle && graphStyle != null && graphStyle.background != null)
  5651. {
  5652. panel.style.backgroundColor = graphStyle.background;
  5653. }
  5654. createPreview(commonStyle, vertexStyle, edgeStyle, graphStyle, panel);
  5655. mxEvent.addGestureListeners(panel, mxUtils.bind(this, function(evt)
  5656. {
  5657. panel.style.opacity = 0.5;
  5658. }), null, mxUtils.bind(this, function(evt)
  5659. {
  5660. panel.style.opacity = 1;
  5661. graph.currentVertexStyle = mxUtils.clone(graph.defaultVertexStyle);
  5662. graph.currentEdgeStyle = mxUtils.clone(graph.defaultEdgeStyle);
  5663. applyStyle(commonStyle, graph.currentVertexStyle);
  5664. applyStyle(commonStyle, graph.currentEdgeStyle);
  5665. applyStyle(vertexStyle, graph.currentVertexStyle);
  5666. applyStyle(edgeStyle, graph.currentEdgeStyle);
  5667. model.beginUpdate();
  5668. try
  5669. {
  5670. updateCells(addKeys(commonStyle, defaultStyles.slice()), graphStyle);
  5671. if (!ignoreGraphStyle)
  5672. {
  5673. var change = new ChangePageSetup(ui, (graphStyle != null) ? graphStyle.background : null);
  5674. change.ignoreImage = true;
  5675. model.execute(change);
  5676. model.execute(new ChangeGridColor(ui,
  5677. (graphStyle != null && graphStyle.gridColor != null) ?
  5678. graphStyle.gridColor : gridColor));
  5679. }
  5680. }
  5681. finally
  5682. {
  5683. model.endUpdate();
  5684. }
  5685. }));
  5686. mxEvent.addListener(panel, 'mouseenter', mxUtils.bind(this, function(evt)
  5687. {
  5688. var prev = graph.getCellStyle;
  5689. var prevBg = graph.background;
  5690. var prevGrid = graph.view.gridColor;
  5691. if (!ignoreGraphStyle)
  5692. {
  5693. graph.background = (graphStyle != null) ? graphStyle.background : null;
  5694. graph.view.gridColor = (graphStyle != null && graphStyle.gridColor != null) ?
  5695. graphStyle.gridColor : gridColor;
  5696. }
  5697. graph.getCellStyle = function(cell, resolve)
  5698. {
  5699. resolve = (resolve != null) ? resolve : true;
  5700. var result = mxUtils.clone(prev.apply(this, arguments));
  5701. var defaultStyle = graph.stylesheet.getDefaultVertexStyle();
  5702. var appliedStyle = vertexStyle;
  5703. if (model.isEdge(cell))
  5704. {
  5705. defaultStyle = graph.stylesheet.getDefaultEdgeStyle();
  5706. appliedStyle = edgeStyle;
  5707. }
  5708. removeStyles(result, defaultStyles, defaultStyle);
  5709. applyStyle(commonStyle, result, cell, graphStyle);
  5710. applyStyle(appliedStyle, result, cell, graphStyle);
  5711. if (resolve)
  5712. {
  5713. result = this.postProcessCellStyle(cell, result);
  5714. }
  5715. return result;
  5716. };
  5717. graph.refresh();
  5718. graph.getCellStyle = prev;
  5719. graph.background = prevBg;
  5720. graph.view.gridColor = prevGrid;
  5721. }));
  5722. mxEvent.addListener(panel, 'mouseleave', mxUtils.bind(this, function(evt)
  5723. {
  5724. graph.refresh();
  5725. }));
  5726. // Workaround for broken cache in IE11
  5727. if (!mxClient.IS_IE && !mxClient.IS_IE11)
  5728. {
  5729. this.format.cachedStyleEntries[index] = panel;
  5730. }
  5731. }
  5732. entries.appendChild(panel);
  5733. });
  5734. // Maximum palettes to switch the switcher
  5735. var maxEntries = 10;
  5736. var pageCount = Math.ceil(Editor.styles.length / maxEntries);
  5737. this.format.currentStylePage = (this.format.currentStylePage != null) ? this.format.currentStylePage : 0;
  5738. var dots = [];
  5739. var addEntries = mxUtils.bind(this, function()
  5740. {
  5741. if (dots.length > 0)
  5742. {
  5743. dots[this.format.currentStylePage].style.background = '#84d7ff';
  5744. }
  5745. for (var i = this.format.currentStylePage * maxEntries;
  5746. i < Math.min((this.format.currentStylePage + 1) * maxEntries,
  5747. Editor.styles.length); i++)
  5748. {
  5749. var s = Editor.styles[i];
  5750. addEntry(s.commonStyle, s.vertexStyle, s.edgeStyle, s.graph, i);
  5751. }
  5752. });
  5753. var selectPage = mxUtils.bind(this, function(index)
  5754. {
  5755. if (index >= 0 && index < pageCount)
  5756. {
  5757. dots[this.format.currentStylePage].style.background = 'transparent';
  5758. entries.innerText = '';
  5759. this.format.currentStylePage = index;
  5760. addEntries();
  5761. }
  5762. });
  5763. if (pageCount > 1)
  5764. {
  5765. // Selector
  5766. var switcher = document.createElement('div');
  5767. switcher.style.whiteSpace = 'nowrap';
  5768. switcher.style.position = 'relative';
  5769. switcher.style.textAlign = 'center';
  5770. switcher.style.paddingTop = '4px';
  5771. switcher.style.width = '210px';
  5772. for (var i = 0; i < pageCount; i++)
  5773. {
  5774. var dot = document.createElement('div');
  5775. dot.style.display = 'inline-block';
  5776. dot.style.width = '6px';
  5777. dot.style.height = '6px';
  5778. dot.style.marginLeft = '4px';
  5779. dot.style.marginRight = '3px';
  5780. dot.style.borderRadius = '3px';
  5781. dot.style.cursor = 'pointer';
  5782. dot.style.background = 'transparent';
  5783. dot.style.border = '1px solid #b5b6b7';
  5784. (mxUtils.bind(this, function(index, elt)
  5785. {
  5786. mxEvent.addListener(dot, 'click', mxUtils.bind(this, function()
  5787. {
  5788. selectPage(index);
  5789. }));
  5790. }))(i, dot);
  5791. switcher.appendChild(dot);
  5792. dots.push(dot);
  5793. }
  5794. div.appendChild(switcher);
  5795. addEntries();
  5796. if (pageCount < 15)
  5797. {
  5798. var left = document.createElement('div');
  5799. left.className = 'geAdaptiveAsset';
  5800. left.style.position = 'absolute';
  5801. left.style.left = '0px';
  5802. left.style.top = '0px';
  5803. left.style.bottom = '0px';
  5804. left.style.width = '24px';
  5805. left.style.height = '24px';
  5806. left.style.margin = '0px';
  5807. left.style.cursor = 'pointer';
  5808. left.style.opacity = '0.5';
  5809. left.style.backgroundRepeat = 'no-repeat';
  5810. left.style.backgroundPosition = 'center center';
  5811. left.style.backgroundSize = '24px 24px';
  5812. left.style.backgroundImage = 'url(' + Editor.previousImage + ')';
  5813. var right = left.cloneNode(false);
  5814. right.style.backgroundImage = 'url(' + Editor.nextImage + ')';
  5815. right.style.left = '';
  5816. right.style.right = '2px';
  5817. switcher.appendChild(left);
  5818. switcher.appendChild(right);
  5819. mxEvent.addListener(left, 'click', mxUtils.bind(this, function()
  5820. {
  5821. selectPage(mxUtils.mod(this.format.currentStylePage - 1, pageCount));
  5822. }));
  5823. mxEvent.addListener(right, 'click', mxUtils.bind(this, function()
  5824. {
  5825. selectPage(mxUtils.mod(this.format.currentStylePage + 1, pageCount));
  5826. }));
  5827. // Hover state
  5828. function addHoverState(elt)
  5829. {
  5830. mxEvent.addListener(elt, 'mouseenter', function()
  5831. {
  5832. elt.style.opacity = '1';
  5833. });
  5834. mxEvent.addListener(elt, 'mouseleave', function()
  5835. {
  5836. elt.style.opacity = '0.5';
  5837. });
  5838. };
  5839. addHoverState(left);
  5840. addHoverState(right);
  5841. }
  5842. }
  5843. else
  5844. {
  5845. addEntries();
  5846. }
  5847. return div;
  5848. };
  5849. /**
  5850. * Adds the label menu items to the given menu and parent.
  5851. */
  5852. DiagramStylePanel.prototype.destroy = function()
  5853. {
  5854. BaseFormatPanel.prototype.destroy.apply(this, arguments);
  5855. if (this.darkModeChangedListener)
  5856. {
  5857. this.editorUi.removeListener(this.darkModeChangedListener);
  5858. this.darkModeChangedListener = null;
  5859. }
  5860. };
  5861. /**
  5862. * Adds the label menu items to the given menu and parent.
  5863. */
  5864. DiagramFormatPanel = function(format, editorUi, container)
  5865. {
  5866. BaseFormatPanel.call(this, format, editorUi, container);
  5867. this.init();
  5868. };
  5869. mxUtils.extend(DiagramFormatPanel, BaseFormatPanel);
  5870. /**
  5871. * Switch to disable page view.
  5872. */
  5873. DiagramFormatPanel.showPageView = true;
  5874. /**
  5875. * Specifies if the background image option should be shown. Default is true.
  5876. */
  5877. DiagramFormatPanel.prototype.showBackgroundImageOption = true;
  5878. /**
  5879. * Adds the label menu items to the given menu and parent.
  5880. */
  5881. DiagramFormatPanel.prototype.init = function()
  5882. {
  5883. var ui = this.editorUi;
  5884. var editor = ui.editor;
  5885. var graph = editor.graph;
  5886. this.container.appendChild(this.addView(this.createPanel()));
  5887. if (graph.isEnabled())
  5888. {
  5889. this.container.appendChild(this.addOptions(this.createPanel()));
  5890. this.container.appendChild(this.addPaperSize(this.createPanel()));
  5891. this.container.appendChild(this.addStyleOps(this.createPanel()));
  5892. }
  5893. };
  5894. /**
  5895. * Adds the label menu items to the given menu and parent.
  5896. */
  5897. DiagramFormatPanel.prototype.addView = function(div)
  5898. {
  5899. var ui = this.editorUi;
  5900. var editor = ui.editor;
  5901. var graph = editor.graph;
  5902. div.appendChild(this.createTitle(mxResources.get('view')));
  5903. // Grid
  5904. this.addGridOption(div);
  5905. // Page View
  5906. if (DiagramFormatPanel.showPageView)
  5907. {
  5908. div.appendChild(this.createOption(mxResources.get('pageView'), function()
  5909. {
  5910. return graph.pageVisible;
  5911. }, function(checked)
  5912. {
  5913. ui.actions.get('pageView').funct();
  5914. },
  5915. {
  5916. install: function(apply)
  5917. {
  5918. this.listener = function()
  5919. {
  5920. apply(graph.pageVisible);
  5921. };
  5922. ui.addListener('pageViewChanged', this.listener);
  5923. },
  5924. destroy: function()
  5925. {
  5926. ui.removeListener(this.listener);
  5927. }
  5928. }));
  5929. }
  5930. if (graph.isEnabled())
  5931. {
  5932. if (this.showBackgroundImageOption)
  5933. {
  5934. var bg = this.createOption(mxResources.get('background'), function()
  5935. {
  5936. return graph.backgroundImage != null;
  5937. }, function(checked)
  5938. {
  5939. if (!checked)
  5940. {
  5941. var change = new ChangePageSetup(ui, null, null);
  5942. change.ignoreColor = true;
  5943. graph.model.execute(change);
  5944. }
  5945. },
  5946. {
  5947. install: function(apply)
  5948. {
  5949. this.listener = function()
  5950. {
  5951. apply(graph.backgroundImage != null);
  5952. };
  5953. ui.addListener('backgroundImageChanged', this.listener);
  5954. },
  5955. destroy: function()
  5956. {
  5957. ui.removeListener(this.listener);
  5958. }
  5959. });
  5960. var input = bg.getElementsByTagName('input')[0];
  5961. if (input != null)
  5962. {
  5963. input.style.visibility = graph.backgroundImage != null ? 'visible' : 'hidden';
  5964. }
  5965. var label = bg.getElementsByTagName('div')[0];
  5966. if (label != null)
  5967. {
  5968. label.style.display = 'inline-block';
  5969. label.style.textOverflow = 'ellipsis';
  5970. label.style.overflow = 'hidden';
  5971. label.style.maxWidth = '80px';
  5972. }
  5973. if (mxClient.IS_FF)
  5974. {
  5975. label.style.marginTop = '1px';
  5976. }
  5977. var btn = mxUtils.button(mxResources.get('change') + '...', function(evt)
  5978. {
  5979. ui.showBackgroundImageDialog(null,
  5980. ui.editor.graph.backgroundImage,
  5981. ui.editor.graph.background);
  5982. mxEvent.consume(evt);
  5983. })
  5984. btn.style.position = 'absolute';
  5985. btn.style.height = '22px';
  5986. btn.style.left = '47%';
  5987. btn.style.marginLeft = '1px';
  5988. btn.style.width = '110px';
  5989. btn.style.maxWidth = '110px';
  5990. bg.appendChild(btn);
  5991. div.appendChild(bg);
  5992. }
  5993. var bgColor = this.createColorOption(mxResources.get('backgroundColor'), function()
  5994. {
  5995. return graph.background;
  5996. }, function(color)
  5997. {
  5998. var change = new ChangePageSetup(ui, color);
  5999. change.ignoreImage = true;
  6000. graph.model.execute(change);
  6001. }, '#ffffff');
  6002. bgColor.style.padding = '5px 0 1px 0';
  6003. div.appendChild(bgColor);
  6004. var option = this.createOption(mxResources.get('shadow'), function()
  6005. {
  6006. return graph.shadowVisible;
  6007. }, function(checked)
  6008. {
  6009. var change = new ChangePageSetup(ui);
  6010. change.ignoreColor = true;
  6011. change.ignoreImage = true;
  6012. change.shadowVisible = checked;
  6013. graph.model.execute(change);
  6014. },
  6015. {
  6016. install: function(apply)
  6017. {
  6018. this.listener = function()
  6019. {
  6020. apply(graph.shadowVisible);
  6021. };
  6022. ui.addListener('shadowVisibleChanged', this.listener);
  6023. },
  6024. destroy: function()
  6025. {
  6026. ui.removeListener(this.listener);
  6027. }
  6028. });
  6029. if (!Editor.enableShadowOption)
  6030. {
  6031. option.getElementsByTagName('input')[0].setAttribute('disabled', 'disabled');
  6032. mxUtils.setOpacity(option, 60);
  6033. }
  6034. option.style.display = 'inline-flex';
  6035. option.style.width = '100px';
  6036. option.style.maxWidth = '100px';
  6037. option.style.marginRight = '4px';
  6038. div.appendChild(option);
  6039. var sketchOption = this.createOption(mxResources.get('sketch'), function()
  6040. {
  6041. return Editor.sketchMode;
  6042. }, function(checked)
  6043. {
  6044. ui.setSketchMode(checked);
  6045. },
  6046. {
  6047. install: function(apply)
  6048. {
  6049. this.listener = function()
  6050. {
  6051. apply(Editor.sketchMode);
  6052. };
  6053. ui.addListener('sketchModeChanged', this.listener);
  6054. },
  6055. destroy: function()
  6056. {
  6057. ui.removeListener(this.listener);
  6058. }
  6059. });
  6060. sketchOption.style.display = 'inline-flex';
  6061. sketchOption.style.width = '104px';
  6062. sketchOption.style.maxWidth = '104px';
  6063. div.appendChild(sketchOption);
  6064. }
  6065. return div;
  6066. };
  6067. /**
  6068. * Adds the label menu items to the given menu and parent.
  6069. */
  6070. DiagramFormatPanel.prototype.addOptions = function(div)
  6071. {
  6072. var ui = this.editorUi;
  6073. var editor = ui.editor;
  6074. var graph = editor.graph;
  6075. div.appendChild(this.createTitle(mxResources.get('options')));
  6076. if (graph.isEnabled())
  6077. {
  6078. // Connection arrows
  6079. div.appendChild(this.createOption(mxResources.get('connectionArrows'), function()
  6080. {
  6081. return graph.connectionArrowsEnabled;
  6082. }, function(checked)
  6083. {
  6084. ui.actions.get('connectionArrows').funct();
  6085. },
  6086. {
  6087. install: function(apply)
  6088. {
  6089. this.listener = function()
  6090. {
  6091. apply(graph.connectionArrowsEnabled);
  6092. };
  6093. ui.addListener('connectionArrowsChanged', this.listener);
  6094. },
  6095. destroy: function()
  6096. {
  6097. ui.removeListener(this.listener);
  6098. }
  6099. }));
  6100. // Connection points
  6101. div.appendChild(this.createOption(mxResources.get('connectionPoints'), function()
  6102. {
  6103. return graph.connectionHandler.isEnabled();
  6104. }, function(checked)
  6105. {
  6106. ui.actions.get('connectionPoints').funct();
  6107. },
  6108. {
  6109. install: function(apply)
  6110. {
  6111. this.listener = function()
  6112. {
  6113. apply(graph.connectionHandler.isEnabled());
  6114. };
  6115. ui.addListener('connectionPointsChanged', this.listener);
  6116. },
  6117. destroy: function()
  6118. {
  6119. ui.removeListener(this.listener);
  6120. }
  6121. }));
  6122. // Guides
  6123. div.appendChild(this.createOption(mxResources.get('guides'), function()
  6124. {
  6125. return graph.graphHandler.guidesEnabled;
  6126. }, function(checked)
  6127. {
  6128. ui.actions.get('guides').funct();
  6129. },
  6130. {
  6131. install: function(apply)
  6132. {
  6133. this.listener = function()
  6134. {
  6135. apply(graph.graphHandler.guidesEnabled);
  6136. };
  6137. ui.addListener('guidesEnabledChanged', this.listener);
  6138. },
  6139. destroy: function()
  6140. {
  6141. ui.removeListener(this.listener);
  6142. }
  6143. }));
  6144. }
  6145. return div;
  6146. };
  6147. /**
  6148. *
  6149. */
  6150. DiagramFormatPanel.prototype.addGridOption = function(container)
  6151. {
  6152. var fPanel = this;
  6153. var ui = this.editorUi;
  6154. var graph = ui.editor.graph;
  6155. var input = document.createElement('input');
  6156. input.style.position = 'absolute';
  6157. input.style.textAlign = 'right';
  6158. input.style.width = '48px';
  6159. input.style.marginTop = '-2px';
  6160. input.style.height = '21px';
  6161. input.style.borderWidth = '1px';
  6162. input.style.borderStyle = 'solid';
  6163. input.style.boxSizing = 'border-box';
  6164. input.value = this.inUnit(graph.getGridSize()) + ' ' + this.getUnit();
  6165. var stepper = this.createStepper(input, update, this.getUnitStep(), null, null, null, this.isFloatUnit());
  6166. input.style.display = (graph.isGridEnabled()) ? '' : 'none';
  6167. stepper.style.display = input.style.display;
  6168. mxEvent.addListener(input, 'keydown', function(e)
  6169. {
  6170. if (e.keyCode == 13)
  6171. {
  6172. graph.container.focus();
  6173. mxEvent.consume(e);
  6174. }
  6175. else if (e.keyCode == 27)
  6176. {
  6177. input.value = graph.getGridSize();
  6178. graph.container.focus();
  6179. mxEvent.consume(e);
  6180. }
  6181. });
  6182. function update(evt)
  6183. {
  6184. var value = fPanel.isFloatUnit()? parseFloat(input.value) : parseInt(input.value);
  6185. value = fPanel.fromUnit(Math.max(fPanel.inUnit(1), (isNaN(value)) ? fPanel.inUnit(10) : value));
  6186. if (value != graph.getGridSize())
  6187. {
  6188. mxGraph.prototype.gridSize = value;
  6189. graph.setGridSize(value)
  6190. }
  6191. input.value = fPanel.inUnit(value) + ' ' + fPanel.getUnit();
  6192. mxEvent.consume(evt);
  6193. };
  6194. mxEvent.addListener(input, 'blur', update);
  6195. mxEvent.addListener(input, 'change', update);
  6196. input.style.right = '78px';
  6197. stepper.style.marginTop = (mxClient.IS_MAC && mxClient.IS_GC) ?
  6198. '-16px' : ((mxClient.IS_WIN) ? '-18px' : '-17px');
  6199. stepper.style.right = '66px';
  6200. var panel = this.createColorOption(mxResources.get('grid'), function()
  6201. {
  6202. var color = graph.view.gridColor;
  6203. return (graph.isGridEnabled()) ? color : null;
  6204. }, function(color)
  6205. {
  6206. var enabled = graph.isGridEnabled();
  6207. if (color == mxConstants.NONE)
  6208. {
  6209. graph.setGridEnabled(false);
  6210. }
  6211. else
  6212. {
  6213. graph.setGridEnabled(true);
  6214. ui.setGridColor(color);
  6215. }
  6216. input.style.display = (graph.isGridEnabled()) ? '' : 'none';
  6217. stepper.style.display = input.style.display;
  6218. if (enabled != graph.isGridEnabled())
  6219. {
  6220. graph.defaultGridEnabled = graph.isGridEnabled();
  6221. ui.fireEvent(new mxEventObject('gridEnabledChanged'));
  6222. }
  6223. }, Editor.isDarkMode() ? graph.view.defaultDarkGridColor : graph.view.defaultGridColor,
  6224. {
  6225. install: function(apply)
  6226. {
  6227. this.listener = function()
  6228. {
  6229. apply((graph.isGridEnabled()) ? graph.view.gridColor : null);
  6230. };
  6231. ui.addListener('gridColorChanged', this.listener);
  6232. ui.addListener('gridEnabledChanged', this.listener);
  6233. },
  6234. destroy: function()
  6235. {
  6236. ui.removeListener(this.listener);
  6237. }
  6238. });
  6239. panel.style.padding = '6px 0 0 0';
  6240. panel.appendChild(input);
  6241. panel.appendChild(stepper);
  6242. container.appendChild(panel);
  6243. };
  6244. /**
  6245. * Adds the label menu items to the given menu and parent.
  6246. */
  6247. DiagramFormatPanel.prototype.addDocumentProperties = function(div)
  6248. {
  6249. div.appendChild(this.createTitle(mxResources.get('options')));
  6250. return div;
  6251. };
  6252. /**
  6253. * Adds the label menu items to the given menu and parent.
  6254. */
  6255. DiagramFormatPanel.prototype.addPaperSize = function(div)
  6256. {
  6257. var ui = this.editorUi;
  6258. var editor = ui.editor;
  6259. var graph = editor.graph;
  6260. div.appendChild(this.createTitle(mxResources.get('paperSize')));
  6261. var accessor = PageSetupDialog.addPageFormatPanel(div, 'formatpanel', graph.pageFormat, function(pageFormat)
  6262. {
  6263. if (graph.pageFormat == null || graph.pageFormat.width != pageFormat.width ||
  6264. graph.pageFormat.height != pageFormat.height)
  6265. {
  6266. var change = new ChangePageSetup(ui, null, null, pageFormat);
  6267. change.ignoreColor = true;
  6268. change.ignoreImage = true;
  6269. graph.model.execute(change);
  6270. }
  6271. });
  6272. this.addKeyHandler(accessor.widthInput, function()
  6273. {
  6274. accessor.set(graph.pageFormat);
  6275. });
  6276. this.addKeyHandler(accessor.heightInput, function()
  6277. {
  6278. accessor.set(graph.pageFormat);
  6279. });
  6280. var listener = function()
  6281. {
  6282. accessor.set(graph.pageFormat);
  6283. };
  6284. ui.addListener('pageFormatChanged', listener);
  6285. this.listeners.push({destroy: function() { ui.removeListener(listener); }});
  6286. graph.getModel().addListener(mxEvent.CHANGE, listener);
  6287. this.listeners.push({destroy: function() { graph.getModel().removeListener(listener); }});
  6288. return div;
  6289. };
  6290. /**
  6291. * Adds the label menu items to the given menu and parent.
  6292. */
  6293. DiagramFormatPanel.prototype.addStyleOps = function(div)
  6294. {
  6295. this.addActions(div, ['editData']);
  6296. this.addActions(div, ['clearDefaultStyle']);
  6297. return div;
  6298. };
  6299. /**
  6300. * Adds the label menu items to the given menu and parent.
  6301. */
  6302. DiagramFormatPanel.prototype.destroy = function()
  6303. {
  6304. BaseFormatPanel.prototype.destroy.apply(this, arguments);
  6305. if (this.gridEnabledListener)
  6306. {
  6307. this.editorUi.removeListener(this.gridEnabledListener);
  6308. this.gridEnabledListener = null;
  6309. }
  6310. };