oryx.debug.js 921 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186251872518825189251902519125192251932519425195251962519725198251992520025201252022520325204252052520625207252082520925210252112521225213252142521525216252172521825219252202522125222252232522425225252262522725228252292523025231252322523325234252352523625237252382523925240252412524225243252442524525246252472524825249252502525125252252532525425255252562525725258252592526025261252622526325264252652526625267252682526925270252712527225273252742527525276252772527825279252802528125282252832528425285252862528725288252892529025291252922529325294252952529625297252982529925300253012530225303253042530525306253072530825309253102531125312253132531425315253162531725318253192532025321253222532325324253252532625327253282532925330253312533225333253342533525336253372533825339253402534125342253432534425345253462534725348253492535025351253522535325354253552535625357253582535925360253612536225363253642536525366253672536825369253702537125372253732537425375253762537725378253792538025381253822538325384253852538625387253882538925390253912539225393253942539525396253972539825399254002540125402254032540425405254062540725408254092541025411254122541325414254152541625417254182541925420254212542225423254242542525426254272542825429254302543125432254332543425435254362543725438254392544025441254422544325444254452544625447254482544925450254512545225453254542545525456254572545825459254602546125462254632546425465254662546725468254692547025471254722547325474254752547625477254782547925480254812548225483254842548525486254872548825489254902549125492254932549425495254962549725498254992550025501255022550325504255052550625507255082550925510255112551225513255142551525516255172551825519255202552125522255232552425525255262552725528255292553025531255322553325534255352553625537255382553925540255412554225543255442554525546255472554825549255502555125552255532555425555255562555725558255592556025561255622556325564255652556625567255682556925570255712557225573255742557525576255772557825579255802558125582255832558425585255862558725588255892559025591255922559325594255952559625597255982559925600256012560225603256042560525606256072560825609256102561125612256132561425615256162561725618256192562025621256222562325624256252562625627256282562925630256312563225633256342563525636256372563825639256402564125642256432564425645256462564725648256492565025651256522565325654256552565625657256582565925660256612566225663256642566525666256672566825669256702567125672256732567425675256762567725678256792568025681256822568325684256852568625687256882568925690256912569225693256942569525696256972569825699257002570125702257032570425705257062570725708257092571025711257122571325714257152571625717257182571925720257212572225723257242572525726257272572825729257302573125732257332573425735257362573725738257392574025741257422574325744257452574625747257482574925750257512575225753257542575525756257572575825759257602576125762257632576425765257662576725768257692577025771257722577325774257752577625777257782577925780257812578225783257842578525786257872578825789257902579125792257932579425795257962579725798257992580025801258022580325804258052580625807258082580925810258112581225813258142581525816258172581825819258202582125822258232582425825258262582725828258292583025831258322583325834258352583625837258382583925840258412584225843258442584525846258472584825849258502585125852258532585425855258562585725858258592586025861258622586325864258652586625867258682586925870258712587225873258742587525876258772587825879258802588125882258832588425885258862588725888258892589025891258922589325894258952589625897258982589925900259012590225903259042590525906259072590825909259102591125912259132591425915259162591725918259192592025921259222592325924259252592625927259282592925930259312593225933259342593525936259372593825939259402594125942259432594425945259462594725948259492595025951259522595325954259552595625957259582595925960259612596225963259642596525966259672596825969259702597125972259732597425975259762597725978259792598025981259822598325984259852598625987259882598925990259912599225993259942599525996259972599825999260002600126002260032600426005260062600726008260092601026011260122601326014260152601626017260182601926020260212602226023260242602526026260272602826029260302603126032260332603426035260362603726038260392604026041260422604326044260452604626047260482604926050260512605226053260542605526056260572605826059260602606126062260632606426065260662606726068260692607026071260722607326074260752607626077260782607926080260812608226083260842608526086260872608826089260902609126092260932609426095260962609726098260992610026101261022610326104261052610626107261082610926110261112611226113261142611526116261172611826119261202612126122261232612426125261262612726128261292613026131261322613326134261352613626137261382613926140261412614226143261442614526146261472614826149261502615126152261532615426155261562615726158261592616026161261622616326164261652616626167261682616926170261712617226173261742617526176261772617826179261802618126182261832618426185261862618726188261892619026191261922619326194261952619626197261982619926200262012620226203262042620526206262072620826209262102621126212262132621426215262162621726218262192622026221262222622326224262252622626227262282622926230262312623226233262342623526236262372623826239262402624126242262432624426245262462624726248262492625026251262522625326254262552625626257262582625926260262612626226263262642626526266262672626826269262702627126272262732627426275262762627726278262792628026281262822628326284262852628626287262882628926290262912629226293262942629526296262972629826299263002630126302263032630426305263062630726308263092631026311263122631326314263152631626317263182631926320263212632226323263242632526326263272632826329263302633126332263332633426335263362633726338263392634026341263422634326344263452634626347263482634926350263512635226353263542635526356263572635826359263602636126362263632636426365263662636726368263692637026371263722637326374263752637626377263782637926380263812638226383263842638526386263872638826389263902639126392263932639426395263962639726398263992640026401264022640326404264052640626407264082640926410264112641226413264142641526416264172641826419264202642126422264232642426425264262642726428264292643026431264322643326434264352643626437264382643926440264412644226443264442644526446264472644826449264502645126452264532645426455264562645726458264592646026461264622646326464264652646626467264682646926470264712647226473264742647526476264772647826479264802648126482264832648426485264862648726488264892649026491264922649326494264952649626497264982649926500265012650226503265042650526506265072650826509265102651126512265132651426515265162651726518265192652026521265222652326524265252652626527265282652926530265312653226533265342653526536265372653826539265402654126542265432654426545265462654726548265492655026551265522655326554265552655626557265582655926560265612656226563265642656526566265672656826569265702657126572265732657426575265762657726578265792658026581265822658326584265852658626587265882658926590265912659226593265942659526596265972659826599266002660126602266032660426605266062660726608266092661026611266122661326614266152661626617266182661926620266212662226623266242662526626266272662826629266302663126632266332663426635266362663726638266392664026641266422664326644266452664626647266482664926650266512665226653266542665526656266572665826659266602666126662266632666426665266662666726668266692667026671266722667326674266752667626677266782667926680266812668226683266842668526686266872668826689266902669126692266932669426695266962669726698266992670026701267022670326704267052670626707267082670926710267112671226713267142671526716267172671826719267202672126722267232672426725267262672726728267292673026731267322673326734267352673626737267382673926740267412674226743267442674526746267472674826749267502675126752267532675426755267562675726758267592676026761267622676326764267652676626767267682676926770267712677226773267742677526776267772677826779267802678126782267832678426785267862678726788267892679026791267922679326794267952679626797267982679926800268012680226803268042680526806268072680826809268102681126812268132681426815268162681726818268192682026821268222682326824268252682626827268282682926830268312683226833268342683526836268372683826839268402684126842268432684426845268462684726848268492685026851268522685326854268552685626857268582685926860268612686226863268642686526866268672686826869268702687126872268732687426875268762687726878268792688026881268822688326884268852688626887268882688926890268912689226893268942689526896268972689826899269002690126902269032690426905269062690726908269092691026911269122691326914269152691626917269182691926920269212692226923269242692526926269272692826929269302693126932269332693426935269362693726938269392694026941269422694326944269452694626947269482694926950269512695226953269542695526956269572695826959269602696126962269632696426965269662696726968269692697026971269722697326974269752697626977269782697926980269812698226983269842698526986269872698826989269902699126992269932699426995269962699726998269992700027001270022700327004270052700627007270082700927010270112701227013270142701527016270172701827019270202702127022270232702427025270262702727028270292703027031270322703327034270352703627037270382703927040270412704227043270442704527046270472704827049270502705127052270532705427055270562705727058270592706027061270622706327064270652706627067270682706927070270712707227073270742707527076270772707827079270802708127082270832708427085270862708727088270892709027091270922709327094270952709627097270982709927100271012710227103271042710527106271072710827109271102711127112271132711427115271162711727118271192712027121271222712327124271252712627127271282712927130271312713227133271342713527136271372713827139271402714127142271432714427145271462714727148271492715027151271522715327154271552715627157271582715927160271612716227163271642716527166271672716827169271702717127172271732717427175271762717727178271792718027181271822718327184271852718627187271882718927190271912719227193271942719527196271972719827199272002720127202272032720427205272062720727208272092721027211272122721327214272152721627217272182721927220272212722227223272242722527226272272722827229272302723127232272332723427235272362723727238272392724027241272422724327244272452724627247272482724927250272512725227253272542725527256272572725827259272602726127262272632726427265272662726727268272692727027271272722727327274272752727627277272782727927280272812728227283272842728527286272872728827289272902729127292272932729427295272962729727298272992730027301273022730327304273052730627307273082730927310273112731227313273142731527316273172731827319273202732127322273232732427325273262732727328273292733027331273322733327334273352733627337273382733927340273412734227343273442734527346273472734827349273502735127352273532735427355273562735727358273592736027361273622736327364273652736627367273682736927370273712737227373273742737527376273772737827379273802738127382273832738427385273862738727388273892739027391273922739327394273952739627397273982739927400274012740227403274042740527406274072740827409274102741127412274132741427415274162741727418274192742027421274222742327424274252742627427274282742927430274312743227433274342743527436274372743827439274402744127442274432744427445274462744727448274492745027451274522745327454274552745627457274582745927460274612746227463274642746527466274672746827469274702747127472274732747427475274762747727478274792748027481274822748327484274852748627487274882748927490274912749227493274942749527496274972749827499275002750127502275032750427505275062750727508275092751027511275122751327514275152751627517275182751927520275212752227523275242752527526275272752827529275302753127532275332753427535275362753727538275392754027541275422754327544275452754627547275482754927550275512755227553275542755527556275572755827559275602756127562275632756427565275662756727568275692757027571275722757327574275752757627577275782757927580275812758227583275842758527586275872758827589275902759127592275932759427595275962759727598275992760027601276022760327604276052760627607276082760927610276112761227613276142761527616276172761827619276202762127622276232762427625276262762727628276292763027631276322763327634276352763627637276382763927640276412764227643276442764527646276472764827649276502765127652276532765427655276562765727658276592766027661276622766327664276652766627667276682766927670276712767227673276742767527676276772767827679276802768127682276832768427685276862768727688276892769027691276922769327694276952769627697276982769927700277012770227703277042770527706277072770827709277102771127712277132771427715277162771727718277192772027721277222772327724277252772627727277282772927730277312773227733277342773527736277372773827739277402774127742277432774427745277462774727748277492775027751277522775327754277552775627757277582775927760277612776227763277642776527766277672776827769277702777127772277732777427775277762777727778277792778027781277822778327784277852778627787277882778927790277912779227793277942779527796277972779827799278002780127802278032780427805278062780727808278092781027811278122781327814278152781627817278182781927820278212782227823278242782527826278272782827829278302783127832278332783427835278362783727838278392784027841278422784327844278452784627847278482784927850278512785227853278542785527856278572785827859278602786127862278632786427865278662786727868278692787027871278722787327874278752787627877278782787927880278812788227883278842788527886278872788827889278902789127892278932789427895278962789727898278992790027901279022790327904279052790627907279082790927910279112791227913279142791527916279172791827919279202792127922279232792427925279262792727928279292793027931279322793327934279352793627937279382793927940279412794227943279442794527946279472794827949279502795127952279532795427955279562795727958279592796027961279622796327964279652796627967279682796927970279712797227973279742797527976279772797827979279802798127982279832798427985279862798727988279892799027991279922799327994279952799627997279982799928000280012800228003280042800528006280072800828009280102801128012280132801428015280162801728018280192802028021280222802328024280252802628027280282802928030280312803228033280342803528036280372803828039280402804128042280432804428045280462804728048280492805028051280522805328054280552805628057280582805928060280612806228063280642806528066280672806828069280702807128072280732807428075280762807728078280792808028081280822808328084280852808628087280882808928090280912809228093280942809528096280972809828099281002810128102281032810428105281062810728108281092811028111281122811328114281152811628117281182811928120281212812228123281242812528126281272812828129281302813128132281332813428135281362813728138281392814028141281422814328144281452814628147281482814928150281512815228153281542815528156281572815828159281602816128162281632816428165281662816728168281692817028171281722817328174281752817628177281782817928180281812818228183281842818528186281872818828189281902819128192281932819428195281962819728198281992820028201282022820328204282052820628207282082820928210282112821228213282142821528216282172821828219282202822128222282232822428225282262822728228282292823028231282322823328234282352823628237282382823928240282412824228243282442824528246282472824828249282502825128252282532825428255282562825728258282592826028261282622826328264282652826628267282682826928270282712827228273282742827528276282772827828279282802828128282282832828428285282862828728288282892829028291282922829328294282952829628297282982829928300283012830228303283042830528306283072830828309283102831128312283132831428315283162831728318283192832028321283222832328324283252832628327283282832928330283312833228333283342833528336283372833828339283402834128342283432834428345283462834728348283492835028351283522835328354283552835628357283582835928360283612836228363283642836528366283672836828369283702837128372283732837428375283762837728378283792838028381283822838328384283852838628387283882838928390283912839228393283942839528396283972839828399284002840128402284032840428405284062840728408284092841028411284122841328414284152841628417284182841928420284212842228423284242842528426284272842828429284302843128432284332843428435284362843728438284392844028441284422844328444284452844628447284482844928450284512845228453284542845528456284572845828459284602846128462284632846428465284662846728468284692847028471284722847328474284752847628477284782847928480284812848228483284842848528486284872848828489284902849128492284932849428495284962849728498284992850028501285022850328504285052850628507285082850928510285112851228513285142851528516285172851828519285202852128522285232852428525285262852728528285292853028531285322853328534285352853628537285382853928540285412854228543285442854528546285472854828549285502855128552285532855428555285562855728558285592856028561285622856328564285652856628567285682856928570285712857228573285742857528576285772857828579285802858128582285832858428585285862858728588285892859028591285922859328594285952859628597285982859928600286012860228603286042860528606286072860828609286102861128612286132861428615286162861728618286192862028621286222862328624286252862628627286282862928630286312863228633286342863528636286372863828639286402864128642286432864428645286462864728648286492865028651286522865328654286552865628657286582865928660286612866228663286642866528666286672866828669286702867128672286732867428675286762867728678286792868028681286822868328684286852868628687286882868928690286912869228693286942869528696286972869828699287002870128702287032870428705287062870728708287092871028711287122871328714287152871628717287182871928720287212872228723287242872528726287272872828729287302873128732287332873428735287362873728738287392874028741287422874328744287452874628747287482874928750287512875228753287542875528756287572875828759287602876128762287632876428765287662876728768287692877028771287722877328774287752877628777287782877928780287812878228783287842878528786287872878828789287902879128792287932879428795287962879728798287992880028801288022880328804288052880628807288082880928810288112881228813288142881528816288172881828819288202882128822288232882428825288262882728828288292883028831288322883328834288352883628837288382883928840288412884228843288442884528846288472884828849288502885128852288532885428855288562885728858288592886028861288622886328864288652886628867288682886928870288712887228873288742887528876288772887828879288802888128882288832888428885288862888728888288892889028891288922889328894288952889628897288982889928900289012890228903289042890528906289072890828909289102891128912289132891428915289162891728918289192892028921289222892328924289252892628927289282892928930289312893228933289342893528936289372893828939289402894128942289432894428945289462894728948289492895028951289522895328954289552895628957289582895928960289612896228963289642896528966289672896828969289702897128972289732897428975289762897728978289792898028981289822898328984289852898628987289882898928990289912899228993289942899528996289972899828999290002900129002290032900429005290062900729008290092901029011290122901329014290152901629017290182901929020290212902229023290242902529026290272902829029290302903129032290332903429035290362903729038290392904029041290422904329044290452904629047290482904929050290512905229053290542905529056290572905829059290602906129062290632906429065290662906729068290692907029071290722907329074290752907629077290782907929080290812908229083290842908529086290872908829089290902909129092290932909429095290962909729098290992910029101291022910329104291052910629107291082910929110291112911229113291142911529116291172911829119291202912129122291232912429125291262912729128291292913029131291322913329134291352913629137291382913929140291412914229143291442914529146291472914829149291502915129152291532915429155291562915729158291592916029161291622916329164291652916629167291682916929170291712917229173291742917529176291772917829179291802918129182291832918429185291862918729188291892919029191291922919329194291952919629197291982919929200292012920229203292042920529206292072920829209292102921129212292132921429215292162921729218292192922029221292222922329224292252922629227292282922929230292312923229233292342923529236292372923829239292402924129242292432924429245292462924729248292492925029251292522925329254292552925629257292582925929260292612926229263292642926529266292672926829269292702927129272292732927429275292762927729278292792928029281292822928329284292852928629287292882928929290292912929229293292942929529296292972929829299293002930129302293032930429305293062930729308293092931029311293122931329314293152931629317293182931929320293212932229323293242932529326293272932829329293302933129332293332933429335293362933729338293392934029341293422934329344293452934629347293482934929350293512935229353293542935529356293572935829359293602936129362293632936429365293662936729368293692937029371293722937329374293752937629377293782937929380293812938229383293842938529386293872938829389293902939129392293932939429395293962939729398293992940029401294022940329404294052940629407294082940929410294112941229413294142941529416294172941829419294202942129422294232942429425294262942729428294292943029431294322943329434294352943629437294382943929440294412944229443294442944529446294472944829449294502945129452294532945429455294562945729458294592946029461294622946329464294652946629467294682946929470294712947229473294742947529476294772947829479294802948129482294832948429485294862948729488294892949029491294922949329494294952949629497294982949929500295012950229503295042950529506295072950829509295102951129512295132951429515295162951729518295192952029521295222952329524295252952629527295282952929530295312953229533295342953529536295372953829539295402954129542295432954429545295462954729548295492955029551295522955329554295552955629557295582955929560295612956229563295642956529566295672956829569295702957129572295732957429575295762957729578295792958029581295822958329584295852958629587295882958929590295912959229593295942959529596295972959829599296002960129602296032960429605296062960729608296092961029611296122961329614296152961629617296182961929620296212962229623296242962529626296272962829629296302963129632296332963429635296362963729638296392964029641296422964329644296452964629647296482964929650296512965229653296542965529656296572965829659296602966129662296632966429665296662966729668296692967029671296722967329674296752967629677296782967929680296812968229683296842968529686296872968829689296902969129692296932969429695296962969729698296992970029701297022970329704297052970629707297082970929710297112971229713297142971529716297172971829719297202972129722297232972429725297262972729728297292973029731297322973329734297352973629737297382973929740297412974229743297442974529746297472974829749297502975129752297532975429755297562975729758297592976029761297622976329764297652976629767297682976929770297712977229773297742977529776297772977829779297802978129782297832978429785297862978729788297892979029791297922979329794297952979629797297982979929800298012980229803298042980529806298072980829809298102981129812298132981429815298162981729818298192982029821298222982329824298252982629827298282982929830298312983229833298342983529836298372983829839298402984129842
  1. /**
  2. * Copyright (c) 2008
  3. * Willi Tscheschner
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a
  6. * copy of this software and associated documentation files (the "Software"),
  7. * to deal in the Software without restriction, including without limitation
  8. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. * and/or sell copies of the Software, and to permit persons to whom the
  10. * Software is furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21. * DEALINGS IN THE SOFTWARE.
  22. **/
  23. /**
  24. * @namespace Oryx name space for different utility methods
  25. * @name ORYX.Utils
  26. */
  27. ORYX.Utils = {
  28. /**
  29. * General helper method for parsing a param out of current location url
  30. * @example
  31. * // Current url in Browser => "http://oryx.org?param=value"
  32. * ORYX.Utils.getParamFromUrl("param") // => "value"
  33. * @param {Object} name
  34. */
  35. getParamFromUrl: function(name){
  36. name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  37. var regexS = "[\\?&]" + name + "=([^&#]*)";
  38. var regex = new RegExp(regexS);
  39. var results = regex.exec(window.location.href);
  40. if (results == null) {
  41. return null;
  42. }
  43. else {
  44. return results[1];
  45. }
  46. },
  47. adjustLightness: function(){
  48. return arguments[0];
  49. },
  50. adjustGradient: function(gradient, reference){
  51. if (ORYX.CONFIG.DISABLE_GRADIENT && gradient){
  52. var col = reference.getAttributeNS(null, "stop-color") || "#ffffff";
  53. $A(gradient.getElementsByTagName("stop")).each(function(stop){
  54. if (stop == reference){ return; }
  55. stop.setAttributeNS(null, "stop-color", col);
  56. })
  57. }
  58. }
  59. }
  60. /**
  61. * Copyright (c) 2006
  62. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  63. *
  64. * Permission is hereby granted, free of charge, to any person obtaining a
  65. * copy of this software and associated documentation files (the "Software"),
  66. * to deal in the Software without restriction, including without limitation
  67. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  68. * and/or sell copies of the Software, and to permit persons to whom the
  69. * Software is furnished to do so, subject to the following conditions:
  70. *
  71. * The above copyright notice and this permission notice shall be included in
  72. * all copies or substantial portions of the Software.
  73. *
  74. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  75. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  76. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  77. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  78. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  79. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  80. * DEALINGS IN THE SOFTWARE.
  81. **/
  82. XMLNS = {
  83. ATOM: "http://www.w3.org/2005/Atom",
  84. XHTML: "http://www.w3.org/1999/xhtml",
  85. ERDF: "http://purl.org/NET/erdf/profile",
  86. RDFS: "http://www.w3.org/2000/01/rdf-schema#",
  87. RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
  88. RAZIEL: "http://b3mn.org/Raziel",
  89. SCHEMA: ""
  90. };
  91. //TODO kann kickstart sich vielleicht auch um die erzeugung von paketen/
  92. // namespaces k�mmern? z.b. requireNamespace("ORYX.Core.SVG");
  93. var Kickstart = {
  94. started: false,
  95. callbacks: [],
  96. alreadyLoaded: [],
  97. PATH: '',
  98. load: function() { Kickstart.kick(); },
  99. kick: function() {
  100. //console.profile("loading");
  101. if(!Kickstart.started) {
  102. Kickstart.started = true;
  103. Kickstart.callbacks.each(function(callback){
  104. // call the registered callback asynchronously.
  105. window.setTimeout(callback, 1);
  106. });
  107. }
  108. },
  109. register: function(callback) {
  110. //TODO Add some mutual exclusion between kick and register calls.
  111. with(Kickstart) {
  112. if(started) window.setTimeout(callback, 1);
  113. else Kickstart.callbacks.push(callback)
  114. }
  115. },
  116. /**
  117. * Loads a js, assuring that it has only been downloaded once.
  118. * @param {String} url the script to load.
  119. */
  120. require: function(url) {
  121. // if not already loaded, include it.
  122. if(Kickstart.alreadyLoaded.member(url))
  123. return false;
  124. return Kickstart.include(url);
  125. },
  126. /**
  127. * Loads a js, regardless of whether it has only been already downloaded.
  128. * @param {String} url the script to load.
  129. */
  130. include: function(url) {
  131. // prepare a script tag and place it in html head.
  132. var head = document.getElementsByTagNameNS(XMLNS.XHTML, 'head')[0];
  133. var s = document.createElementNS(XMLNS.XHTML, "script");
  134. s.setAttributeNS(XMLNS.XHTML, 'type', 'text/javascript');
  135. s.src = Kickstart.PATH + url;
  136. //TODO macht es sinn, dass neue skript als letztes kind in den head
  137. // einzubinden (stichwort reihenfolge der skript tags)?
  138. head.appendChild(s);
  139. // remember this url.
  140. Kickstart.alreadyLoaded.push(url);
  141. return true;
  142. }
  143. }
  144. // register kickstart as the new onload event listener on current window.
  145. // previous listener(s) are triggered to launch with kickstart.
  146. Event.observe(window, 'load', Kickstart.load);/**
  147. * Copyright (c) 2006
  148. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  149. *
  150. * Permission is hereby granted, free of charge, to any person obtaining a
  151. * copy of this software and associated documentation files (the "Software"),
  152. * to deal in the Software without restriction, including without limitation
  153. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  154. * and/or sell copies of the Software, and to permit persons to whom the
  155. * Software is furnished to do so, subject to the following conditions:
  156. *
  157. * The above copyright notice and this permission notice shall be included in
  158. * all copies or substantial portions of the Software.
  159. *
  160. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  161. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  162. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  163. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  164. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  165. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  166. * DEALINGS IN THE SOFTWARE.
  167. **/
  168. var ERDF = {
  169. LITERAL: 0x01,
  170. RESOURCE: 0x02,
  171. DELIMITERS: ['.', '-'],
  172. HASH: '#',
  173. HYPHEN: "-",
  174. schemas: [],
  175. callback: undefined,
  176. log: undefined,
  177. init: function(callback) {
  178. // init logging.
  179. //ERDF.log = Log4js.getLogger("oryx");
  180. //ERDF.log.setLevel(Log4js.Level.ALL);
  181. //ERDF.log.addAppender(new ConsoleAppender(ERDF.log, false));
  182. //if(ERDF.log.isTraceEnabled())
  183. // ERDF.log.trace("ERDF Parser is initialized.");
  184. // register callbacks and default schemas.
  185. ERDF.callback = callback;
  186. ERDF.registerSchema('schema', XMLNS.SCHEMA);
  187. ERDF.registerSchema('rdfs', XMLNS.RDFS);
  188. },
  189. run: function() {
  190. //if(ERDF.log.isTraceEnabled())
  191. // ERDF.log.trace("ERDF Parser is running.");
  192. // do the work.
  193. return ERDF._checkProfile() && ERDF.parse();
  194. },
  195. parse: function() {
  196. //(ERDF.log.isDebugEnabled())
  197. // ERDF.log.debug("Begin parsing document metadata.");
  198. // time measuring
  199. ERDF.__startTime = new Date();
  200. var bodies = document.getElementsByTagNameNS(XMLNS.XHTML, 'body');
  201. var subject = {type: ERDF.RESOURCE, value: ''};
  202. var result = ERDF._parseDocumentMetadata() &&
  203. ERDF._parseFromTag(bodies[0], subject);
  204. // time measuring
  205. ERDF.__stopTime = new Date();
  206. var duration = (ERDF.__stopTime - ERDF.__startTime)/1000.;
  207. //alert('ERDF parsing took ' + duration + ' s.');
  208. return result;
  209. },
  210. _parseDocumentMetadata: function() {
  211. // get links from head element.
  212. var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head');
  213. var links = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'link');
  214. var metas = heads[0].getElementsByTagNameNS(XMLNS.XHTML, 'meta');
  215. // process links first, since they could contain schema definitions.
  216. $A(links).each(function(link) {
  217. var properties = link.getAttribute('rel');
  218. var reversedProperties = link.getAttribute('rev');
  219. var value = link.getAttribute('href');
  220. ERDF._parseTriplesFrom(
  221. ERDF.RESOURCE, '',
  222. properties,
  223. ERDF.RESOURCE, value);
  224. ERDF._parseTriplesFrom(
  225. ERDF.RESOURCE, value,
  226. reversedProperties,
  227. ERDF.RESOURCE, '');
  228. });
  229. // continue with metas.
  230. $A(metas).each(function(meta) {
  231. var property = meta.getAttribute('name');
  232. var value = meta.getAttribute('content');
  233. ERDF._parseTriplesFrom(
  234. ERDF.RESOURCE, '',
  235. property,
  236. ERDF.LITERAL, value);
  237. });
  238. return true;
  239. },
  240. _parseFromTag: function(node, subject, depth) {
  241. // avoid parsing non-xhtml content.
  242. if(node.namespaceURI != XMLNS.XHTML) { return; }
  243. // housekeeping.
  244. if(!depth) depth=0;
  245. var id = node.getAttribute('id');
  246. // some logging.
  247. //if(ERDF.log.isTraceEnabled())
  248. // ERDF.log.trace(">".times(depth) + " Parsing " + node.nodeName + " ("+node.nodeType+") for data on " +
  249. // ((subject.type == ERDF.RESOURCE) ? ('<' + subject.value + '>') : '') +
  250. // ((subject.type == ERDF.LITERAL) ? '"' + subject.value + '"' : ''));
  251. /* triple finding! */
  252. // in a-tags...
  253. if(node.nodeName.endsWith(':a') || node.nodeName == 'a') {
  254. var properties = node.getAttribute('rel');
  255. var reversedProperties = node.getAttribute('rev');
  256. var value = node.getAttribute('href');
  257. var title = node.getAttribute('title');
  258. var content = node.textContent;
  259. // rel triples
  260. ERDF._parseTriplesFrom(
  261. subject.type, subject.value,
  262. properties,
  263. ERDF.RESOURCE, value,
  264. function(triple) {
  265. var label = title? title : content;
  266. // label triples
  267. ERDF._parseTriplesFrom(
  268. triple.object.type, triple.object.value,
  269. 'rdfs.label',
  270. ERDF.LITERAL, label);
  271. });
  272. // rev triples
  273. ERDF._parseTriplesFrom(
  274. subject.type, subject.value,
  275. reversedProperties,
  276. ERDF.RESOURCE, '');
  277. // type triples
  278. ERDF._parseTypeTriplesFrom(
  279. subject.type, subject.value,
  280. properties);
  281. // in img-tags...
  282. } else if(node.nodeName.endsWith(':img') || node.nodeName == 'img') {
  283. var properties = node.getAttribute('class');
  284. var value = node.getAttribute('src');
  285. var alt = node.getAttribute('alt');
  286. ERDF._parseTriplesFrom(
  287. subject.type, subject.value,
  288. properties,
  289. ERDF.RESOURCE, value,
  290. function(triple) {
  291. var label = alt;
  292. // label triples
  293. ERDF._parseTriplesFrom(
  294. triple.object.type, triple.object.value,
  295. 'rdfs.label',
  296. ERDF.LITERAL, label);
  297. });
  298. }
  299. // in every tag
  300. var properties = node.getAttribute('class');
  301. var title = node.getAttribute('title');
  302. var content = node.textContent;
  303. var label = title ? title : content;
  304. // regular triples
  305. ERDF._parseTriplesFrom(
  306. subject.type, subject.value,
  307. properties,
  308. ERDF.LITERAL, label);
  309. if(id) subject = {type: ERDF.RESOURCE, value: ERDF.HASH+id};
  310. // type triples
  311. ERDF._parseTypeTriplesFrom(
  312. subject.type, subject.value,
  313. properties);
  314. // parse all children that are element nodes.
  315. var children = node.childNodes;
  316. if(children) $A(children).each(function(_node) {
  317. if(_node.nodeType == _node.ELEMENT_NODE)
  318. ERDF._parseFromTag(_node, subject, depth+1); });
  319. },
  320. _parseTriplesFrom: function(subjectType, subject, properties,
  321. objectType, object, callback) {
  322. if(!properties) return;
  323. properties.toLowerCase().split(' ').each( function(property) {
  324. //if(ERDF.log.isTraceEnabled())
  325. // ERDF.log.trace("Going for property " + property);
  326. var schema = ERDF.schemas.find( function(schema) {
  327. return false || ERDF.DELIMITERS.find( function(delimiter) {
  328. return property.startsWith(schema.prefix + delimiter);
  329. });
  330. });
  331. if(schema && object) {
  332. property = property.substring(
  333. schema.prefix.length+1, property.length);
  334. var triple = ERDF.registerTriple(
  335. new ERDF.Resource(subject),
  336. {prefix: schema.prefix, name: property},
  337. (objectType == ERDF.RESOURCE) ?
  338. new ERDF.Resource(object) :
  339. new ERDF.Literal(object));
  340. if(callback) callback(triple);
  341. }
  342. });
  343. },
  344. _parseTypeTriplesFrom: function(subjectType, subject, properties, callback) {
  345. if(!properties) return;
  346. properties.toLowerCase().split(' ').each( function(property) {
  347. //if(ERDF.log.isTraceEnabled())
  348. // ERDF.log.trace("Going for property " + property);
  349. var schema = ERDF.schemas.find( function(schema) {
  350. return false || ERDF.DELIMITERS.find( function(delimiter) {
  351. return property.startsWith(ERDF.HYPHEN + schema.prefix + delimiter);
  352. });
  353. });
  354. if(schema && subject) {
  355. property = property.substring(schema.prefix.length+2, property.length);
  356. var triple = ERDF.registerTriple(
  357. (subjectType == ERDF.RESOURCE) ?
  358. new ERDF.Resource(subject) :
  359. new ERDF.Literal(subject),
  360. {prefix: 'rdf', name: 'type'},
  361. new ERDF.Resource(schema.namespace+property));
  362. if(callback) callback(triple);
  363. }
  364. });
  365. },
  366. /**
  367. * Checks for ERDF profile declaration in head of document.
  368. */
  369. _checkProfile: function() {
  370. // get profiles from head element.
  371. var heads = document.getElementsByTagNameNS(XMLNS.XHTML, 'head');
  372. var profiles = heads[0].getAttribute("profile");
  373. var found = false;
  374. // if erdf profile is contained.
  375. if(profiles && profiles.split(" ").member(XMLNS.ERDF)) {
  376. // pass check.
  377. //if(ERDF.log.isTraceEnabled())
  378. // ERDF.log.trace("Found ERDF profile " + XMLNS.ERDF);
  379. return true;
  380. } else {
  381. // otherwise fail check.
  382. //if(ERDF.log.isFatalEnabled())
  383. // ERDF.log.fatal("No ERDF profile found.");
  384. return false;
  385. }
  386. },
  387. __stripHashes: function(s) {
  388. return (s && s.substring(0, 1)=='#') ? s.substring(1, s.length) : s;
  389. },
  390. registerSchema: function(prefix, namespace) {
  391. // TODO check whether already registered, if so, complain.
  392. ERDF.schemas.push({
  393. prefix: prefix,
  394. namespace: namespace
  395. });
  396. //if(ERDF.log.isDebugEnabled())
  397. // ERDF.log.debug("Prefix '"+prefix+"' for '"+namespace+"' registered.");
  398. },
  399. registerTriple: function(subject, predicate, object) {
  400. // if prefix is schema, this is a schema definition.
  401. if(predicate.prefix.toLowerCase() == 'schema')
  402. this.registerSchema(predicate.name, object.value);
  403. var triple = new ERDF.Triple(subject, predicate, object);
  404. ERDF.callback(triple);
  405. //if(ERDF.log.isInfoEnabled())
  406. // ERDF.log.info(triple)
  407. // return the registered triple.
  408. return triple;
  409. },
  410. __enhanceObject: function() {
  411. /* Resource state querying methods */
  412. this.isResource = function() {
  413. return this.type == ERDF.RESOURCE };
  414. this.isLocal = function() {
  415. return this.isResource() && this.value.startsWith('#') };
  416. this.isCurrentDocument = function() {
  417. return this.isResource() && (this.value == '') };
  418. /* Resource getter methods.*/
  419. this.getId = function() {
  420. return this.isLocal() ? ERDF.__stripHashes(this.value) : false; };
  421. /* Liiteral state querying methods */
  422. this.isLiteral = function() {
  423. return this.type == ERDF.LIITERAL };
  424. },
  425. serialize: function(literal) {
  426. if(!literal){
  427. return "";
  428. }else if(literal.constructor == String) {
  429. return literal;
  430. } else if(literal.constructor == Boolean) {
  431. return literal? 'true':'false';
  432. } else {
  433. return literal.toString();
  434. }
  435. }
  436. };
  437. ERDF.Triple = function(subject, predicate, object) {
  438. this.subject = subject;
  439. this.predicate = predicate;
  440. this.object = object;
  441. this.toString = function() {
  442. return "[ERDF.Triple] " +
  443. this.subject.toString() + ' ' +
  444. this.predicate.prefix + ':' + this.predicate.name + ' ' +
  445. this.object.toString();
  446. };
  447. };
  448. ERDF.Resource = function(uri) {
  449. this.type = ERDF.RESOURCE;
  450. this.value = uri;
  451. ERDF.__enhanceObject.apply(this);
  452. this.toString = function() {
  453. return '<' + this.value + '>';
  454. }
  455. };
  456. ERDF.Literal = function(literal) {
  457. this.type = ERDF.LITERAL;
  458. this.value = ERDF.serialize(literal);
  459. ERDF.__enhanceObject.apply(this);
  460. this.toString = function() {
  461. return '"' + this.value + '"';
  462. }
  463. };/**
  464. * Copyright (c) 2006
  465. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  466. *
  467. * Permission is hereby granted, free of charge, to any person obtaining a
  468. * copy of this software and associated documentation files (the "Software"),
  469. * to deal in the Software without restriction, including without limitation
  470. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  471. * and/or sell copies of the Software, and to permit persons to whom the
  472. * Software is furnished to do so, subject to the following conditions:
  473. *
  474. * The above copyright notice and this permission notice shall be included in
  475. * all copies or substantial portions of the Software.
  476. *
  477. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  478. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  479. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  480. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  481. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  482. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  483. * DEALINGS IN THE SOFTWARE.
  484. **/
  485. /*
  486. * Save and triple generation behaviour. Use this area to configure
  487. * data management to your needs.
  488. */
  489. var USE_ASYNCHRONOUS_REQUESTS = true;
  490. var DISCARD_UNUSED_TRIPLES = true;
  491. var PREFER_SPANS_OVER_DIVS = true;
  492. var PREFER_TITLE_OVER_TEXTNODE = false;
  493. var RESOURCE_ID_PREFIX = 'resource';
  494. var SHOW_DEBUG_ALERTS_WHEN_SAVING = false;
  495. var SHOW_EXTENDED_DEBUG_INFORMATION = false;
  496. /*
  497. * Back end specific workarounds.
  498. */
  499. var USE_ARESS_WORKAROUNDS = true;
  500. /*
  501. * Data management constants. Do not change these, as they are used
  502. * both internally and externally to communicate on events and to identify
  503. * command object actions in triple production and embedding rules.
  504. */
  505. // Resource constants
  506. var RESOURCE_CREATED = 0x01;
  507. var RESOURCE_REMOVED = 0x02;
  508. var RESOURCE_SAVED = 0x04;
  509. var RESOURCE_RELOADED = 0x08;
  510. var RESOURCE_SYNCHRONIZED = 0x10;
  511. // Triple constants
  512. var TRIPLE_REMOVE = 0x01;
  513. var TRIPLE_ADD = 0x02;
  514. var TRIPLE_RELOAD = 0x04;
  515. var TRIPLE_SAVE = 0x08;
  516. var PROCESSDATA_REF = 'processdata';
  517. // HTTP status code constants
  518. //
  519. //// 2xx
  520. //const 200_OK = 'Ok';
  521. //const 201_CREATED = 'Created';
  522. //const 202_ACCEPTED = 'Accepted';
  523. //const 204_NO_CONTENT = 'No Content';
  524. //
  525. //// 3xx
  526. //const 301_MOVED_PERMANENTLY = 'Moved Permanently';
  527. //const 302_MOVED_TEMPORARILY = 'Moved Temporarily';
  528. //const 304_NOT_MODIFIED = 'Not Modified';
  529. //
  530. //// 4xx
  531. //const 400_BAD_REQUEST = 'Bad Request';
  532. //const 401_UNAUTHORIZED = 'Unauthorized';
  533. //const 403_FORBIDDEN = 'Forbidden';
  534. //const 404_NOT_FOUND = 'Not Found';
  535. //const 409_CONFLICT = 'Conflict';
  536. //
  537. //// 5xx
  538. //const 500_INTERNAL_SERVER_ERROR = 'Internal Server Error';
  539. //const 501_NOT_IMPLEMENTED = 'Not Implemented';
  540. //const 502_BAD_GATEWAY = 'Bad Gateway';
  541. //const 503_SERVICE_UNAVAILABLE = 'Service Unavailable';
  542. //
  543. /**
  544. * The Data Management object. Use this one when interacting with page internal
  545. * data. Initialize data management by DataManager.init();
  546. * @class DataManager
  547. */
  548. var DataManager = {
  549. /**
  550. * The init method should be called once in the DataManagers lifetime.
  551. * It causes the DataManager to initialize itself, the erdf parser, do all
  552. * neccessary registrations and configurations, to run the parser and
  553. * from then on deliver all resulting triples.
  554. * No parameters needed are needed in a call to this method.
  555. */
  556. init: function() {
  557. ERDF.init(DataManager._registerTriple);
  558. DataManager.__synclocal();
  559. },
  560. /**
  561. * This triple array is meant to be the whole knowledge of the DataManager.
  562. */
  563. _triples: [],
  564. /**
  565. * This method is meant for callback from erdf parsing. It is not to be
  566. * used in another way than to add triples to the triple store.
  567. * @param {Object} triple the triple to add to the triple store.
  568. */
  569. _registerTriple: function(triple) {
  570. DataManager._triples.push(triple)
  571. },
  572. /**
  573. * The __synclocal method is for internal usage only.
  574. * It performs synchronization with the local document, that is, the triple
  575. * store is adjustet to the content of the document, which could have been
  576. * changed by any other applications running on the same page.
  577. */
  578. __synclocal: function() {
  579. DataManager._triples = [];
  580. ERDF.run();
  581. },
  582. /**
  583. * Makes the shape passed into this method synchronize itself with the DOM.
  584. * This method returns the shapes resource object for further manipulation.
  585. * @param {Object} shape
  586. */
  587. __synchronizeShape: function(shape) {
  588. var r = ResourceManager.getResource(shape.resourceId);
  589. var serialize = shape.serialize();
  590. // store all serialize values
  591. serialize.each( function(ser) {
  592. var resource = (ser.type == 'resource');
  593. var _triple = new ERDF.Triple(
  594. new ERDF.Resource(shape.resourceId),
  595. {prefix: ser.prefix, name: ser.name},
  596. resource ?
  597. new ERDF.Resource(ser.value) :
  598. new ERDF.Literal(ser.value)
  599. );
  600. DataManager.setObject(_triple);
  601. });
  602. return r;
  603. },
  604. __storeShape: function(shape) {
  605. // first synchronize the shape,
  606. var resource = DataManager.__synchronizeShape(shape);
  607. // then save the synchronized dom.
  608. resource.save();
  609. },
  610. __forceExistance: function(shape) {
  611. if(!$(shape.resourceId)) {
  612. if(!$$('.' + PROCESSDATA_REF)[0])
  613. DataManager.graft(XMLNS.XHTML,
  614. document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]);
  615. // object is literal
  616. DataManager.graft(XMLNS.XHTML,
  617. $$('.' + PROCESSDATA_REF)[0], [
  618. 'div', {
  619. 'id': shape.resourceId,
  620. //This should be done in a more dynamic way!!!!!
  621. 'class': (shape instanceof ORYX.Core.Canvas) ? "-oryx-canvas" : undefined
  622. }
  623. ]);
  624. } else {
  625. var resource = $(shape.resourceId)
  626. var children = $A(resource.childNodes)
  627. children.each( function(child) {
  628. resource.removeChild(child);
  629. });
  630. };
  631. },
  632. __persistShape: function(shape) {
  633. // a shape serialization.
  634. var shapeData = shape.serialize();
  635. // initialize a triple array and construct a shape resource
  636. // to be used in triple generation.
  637. var triplesArray = [];
  638. var shapeResource = new ERDF.Resource(shape.resourceId);
  639. // remove all triples for this particular shape's resource
  640. DataManager.removeTriples( DataManager.query(
  641. shapeResource, undefined, undefined));
  642. // for each data set in the shape's serialization
  643. shapeData.each( function(data) {
  644. // construct a triple's value
  645. var value = (data.type == 'resource') ?
  646. new ERDF.Resource(data.value) :
  647. new ERDF.Literal(data.value);
  648. // construct triple and add it to the DOM.
  649. DataManager.addTriple( new ERDF.Triple(
  650. shapeResource,
  651. {prefix: data.prefix, name: data.name},
  652. value
  653. ));
  654. });
  655. },
  656. __persistDOM: function(facade) {
  657. // getChildShapes gets all shapes (nodes AND edges), deep flag
  658. // makes it return a flattened child hierarchy.
  659. var canvas = facade.getCanvas();
  660. var shapes = canvas.getChildShapes(true);
  661. var result = '';
  662. // persist all shapes.
  663. shapes.each( function(shape) {
  664. DataManager.__forceExistance(shape);
  665. });
  666. //DataManager.__synclocal();
  667. DataManager.__renderCanvas(facade);
  668. result += DataManager.serialize(
  669. $(ERDF.__stripHashes(facade.getCanvas().resourceId)), true);
  670. shapes.each( function(shape) {
  671. DataManager.__persistShape(shape);
  672. result += DataManager.serialize(
  673. $(ERDF.__stripHashes(shape.resourceId)), true);
  674. });
  675. //result += DataManager.__renderCanvas(facade);
  676. return result;
  677. },
  678. __renderCanvas: function(facade) {
  679. var canvas = facade.getCanvas();
  680. var stencilSets = facade.getStencilSets();
  681. var shapes = canvas.getChildShapes(true);
  682. DataManager.__forceExistance(canvas);
  683. DataManager.__persistShape(canvas);
  684. var shapeResource = new ERDF.Resource(canvas.resourceId);
  685. // remove all triples for this particular shape's resource
  686. DataManager.removeTriples( DataManager.query(
  687. shapeResource, undefined, undefined));
  688. DataManager.addTriple( new ERDF.Triple(
  689. shapeResource,
  690. {prefix: "oryx", name: "mode"},
  691. new ERDF.Literal("writable")
  692. ));
  693. DataManager.addTriple( new ERDF.Triple(
  694. shapeResource,
  695. {prefix: "oryx", name: "mode"},
  696. new ERDF.Literal("fullscreen")
  697. ));
  698. stencilSets.values().each(function(stencilset) {
  699. DataManager.addTriple( new ERDF.Triple(
  700. shapeResource,
  701. {prefix: "oryx", name: "stencilset"},
  702. new ERDF.Resource(stencilset.source().replace(/&/g, "%26"))
  703. ));
  704. DataManager.addTriple( new ERDF.Triple(
  705. shapeResource,
  706. {prefix: "oryx", name: "ssnamespace"},
  707. new ERDF.Resource(stencilset.namespace())
  708. ));
  709. stencilset.extensions().keys().each(function(extension) {
  710. DataManager.addTriple( new ERDF.Triple(
  711. shapeResource,
  712. {prefix: "oryx", name: "ssextension"},
  713. new ERDF.Literal(extension)
  714. ));
  715. });
  716. });
  717. shapes.each(function(shape) {
  718. DataManager.addTriple( new ERDF.Triple(
  719. shapeResource,
  720. {prefix: "oryx", name: "render"},
  721. new ERDF.Resource("#" + shape.resourceId)
  722. ));
  723. });
  724. },
  725. __counter: 0,
  726. __provideId: function() {
  727. while($(RESOURCE_ID_PREFIX+DataManager.__counter))
  728. DataManager.__counter++;
  729. return RESOURCE_ID_PREFIX+DataManager.__counter;
  730. },
  731. serializeDOM: function(facade) {
  732. return DataManager.__persistDOM(facade);
  733. },
  734. syncGlobal: function(facade) {
  735. return DataManager.__syncglobal(facade);
  736. },
  737. /**
  738. * This method is used to synchronize local DOM with remote resources.
  739. * Local changes are commited to the server, and remote changes are
  740. * performed to the local document.
  741. * @param {Object} facade The facade of the editor that holds certain
  742. * resource representations as shapes.
  743. */
  744. __syncglobal: function(facade) {
  745. // getChildShapes gets all shapes (nodes AND edges), deep flag
  746. // makes it return a flattened child hierarchy.
  747. var canvas = facade.getCanvas();
  748. var shapes = canvas.getChildShapes(true);
  749. // create dummy resource representations in the dom
  750. // for all shapes that were newly created.
  751. shapes.select( function(shape) {
  752. // select shapes without resource id.
  753. return !($(shape.resourceId));
  754. }).each( function(shape) {
  755. // create new resources for them.
  756. if(USE_ARESS_WORKAROUNDS) {
  757. /*
  758. * This is a workaround due to a bug in aress. Resources are
  759. * ignoring changes to raziel:type property once they are
  760. * created. As long as this is not fixed, the resource is now
  761. * being created using a randomly guessed id, this temporary id
  762. * is then used in references and the appropriate div is being
  763. * populated with properties.
  764. *
  765. * AFTER THIS PHASE THE DATA IS INCONSISTENT AS REFERENCES POINT
  766. * TO IDS THAT ARE UNKNOWN TO THE BACK END.
  767. *
  768. * After the resource is actually created in aress, it gets an id
  769. * that is persistent. All shapes are then being populated with the
  770. * correct id references and stored on the server.
  771. *
  772. * AFTER THE SAVE PROCESS HAS RETURNED, THE DATA IS CONSISTENT
  773. * REGARDING THE ID REFERENCES AGAIN.
  774. */
  775. var razielType = shape.properties['raziel-type'];
  776. var div = '<div xmlns="http://www.w3.org/1999/xhtml">' +
  777. '<span class="raziel-type">'+razielType+'</span></div>';
  778. var r = ResourceManager.__createResource(div);
  779. shape.resourceId = r.id();
  780. } else {
  781. var r = ResourceManager.__createResource();
  782. shape.resourceId = r.id();
  783. }
  784. });
  785. shapes.each( function(shape) {
  786. // store all shapes.
  787. DataManager.__storeShape(shape);
  788. });
  789. },
  790. /**
  791. * This method serializes a single div into a string that satisfies the
  792. * client/server communication protocol. It ingnores all elements that have
  793. * an attribute named class that includes 'transient'.
  794. * @param {Object} node the element to serialize.
  795. * @param {Object} preserveNamespace whether to preserve the parent's
  796. * namespace. If you are not sure about namespaces, provide
  797. * just the element to be serialized.
  798. */
  799. serialize: function(node, preserveNamespace) {
  800. if (node.nodeType == node.ELEMENT_NODE) {
  801. // serialize an element node.
  802. var children = $A(node.childNodes);
  803. var attributes = $A(node.attributes);
  804. var clazz = new String(node.getAttribute('class'));
  805. var ignore = clazz.split(' ').member('transient');
  806. // ignore transients.
  807. if(ignore)
  808. return '';
  809. // start serialization.
  810. var result = '<' + node.nodeName;
  811. // preserve namespace?
  812. if(!preserveNamespace)
  813. result += ' xmlns="' + (node.namespaceURI ? node.namespaceURI : XMLNS.XHTML) + '" xmlns:oryx="http://oryx-editor.org"';
  814. // add all attributes.
  815. attributes.each(function(attribute) {
  816. result += ' ' + attribute.nodeName + '="' +
  817. attribute.nodeValue + '"';});
  818. // close if no children.
  819. if(children.length == 0)
  820. result += '/>';
  821. else {
  822. // serialize all children.
  823. result += '>';
  824. children.each(function(_node) {
  825. result += DataManager.serialize(_node, true)});
  826. result += '</' + node.nodeName + '>'
  827. }
  828. return result;
  829. } else if (node.nodeType == node.TEXT_NODE) {
  830. // serialize a text node.
  831. return node.nodeValue;
  832. }
  833. //TODO serialize cdata areas also.
  834. //TODO work on namespace awareness.
  835. },
  836. addTriple: function(triple) {
  837. // assert the subject is a resource
  838. if(!triple.subject.type == ERDF.LITERAL)
  839. throw 'Cannot add the triple ' + triple.toString() +
  840. ' because the subject is not a resource.'
  841. // get the element which represents this triple's subject.
  842. var elementId = ERDF.__stripHashes(triple.subject.value);
  843. var element = $(elementId);
  844. // assert the subject is inside this document.
  845. if(!element)
  846. throw 'Cannot add the triple ' + triple.toString() +
  847. ' because the subject "'+elementId+'" is not in the document.';
  848. if(triple.object.type == ERDF.LITERAL)
  849. // object is literal
  850. DataManager.graft(XMLNS.XHTML, element, [
  851. 'span', {'class': (triple.predicate.prefix + "-" +
  852. triple.predicate.name)}, triple.object.value.escapeHTML()
  853. ]);
  854. else {
  855. // object is resource
  856. DataManager.graft(XMLNS.XHTML, element, [
  857. 'a', {'rel': (triple.predicate.prefix + "-" +
  858. triple.predicate.name), 'href': triple.object.value}
  859. ]);
  860. }
  861. return true;
  862. },
  863. removeTriples: function(triples) {
  864. // alert('Removing ' +triples.length+' triples.');
  865. // from all the triples select those ...
  866. var removed = triples.select(
  867. function(triple) {
  868. // TODO remove also from triple store.
  869. // ... that were actually removed.
  870. return DataManager.__removeTriple(triple);
  871. });
  872. // sync and return removed triples.
  873. // DataManager.__synclocal();
  874. return removed;
  875. },
  876. removeTriple: function(triple) {
  877. // remember whether the triple was actually removed.
  878. var result = DataManager.__removeTriple(triple);
  879. // sync and return removed triples.
  880. // DataManager.__synclocal();
  881. return result;
  882. },
  883. __removeTriple: function(triple) {
  884. // assert the subject is a resource
  885. if(!triple.subject.type == ERDF.LITERAL)
  886. throw 'Cannot remove the triple ' + triple.toString() +
  887. ' because the subject is not a resource.';
  888. // get the element which represents this triple's subject.
  889. var elementId = ERDF.__stripHashes(triple.subject.value);
  890. var element = $(elementId);
  891. // assert the subject is inside this document.
  892. if(!element)
  893. throw 'Cannot remove the triple ' + triple.toString() +
  894. ' because the subject is not in the document.';
  895. if(triple.object.type == ERDF.LITERAL) {
  896. // continue searching actively for the triple.
  897. var result = DataManager.__removeTripleRecursively(triple, element);
  898. return result;
  899. }
  900. },
  901. __removeTripleRecursively: function(triple, continueFrom) {
  902. // return when this node is not an element node.
  903. if(continueFrom.nodeType != continueFrom.ELEMENT_NODE)
  904. return false;
  905. var classes = new String(continueFrom.getAttribute('class'));
  906. var children = $A(continueFrom.childNodes);
  907. if(classes.include(triple.predicate.prefix + '-' + triple.predicate.name)) {
  908. var content = continueFrom.textContent;
  909. if( (triple.object.type == ERDF.LITERAL) &&
  910. (triple.object.value == content))
  911. continueFrom.parentNode.removeChild(continueFrom);
  912. return true;
  913. } else {
  914. children.each(function(_node) {
  915. DataManager.__removeTripleRecursively(triple, _node)});
  916. return false;
  917. }
  918. },
  919. /**
  920. * graft() function
  921. * Originally by Sean M. Burke from interglacial.com, altered for usage with
  922. * SVG and namespace (xmlns) support. Be sure you understand xmlns before
  923. * using this funtion, as it creates all grafted elements in the xmlns
  924. * provided by you and all element's attribures in default xmlns. If you
  925. * need to graft elements in a certain xmlns and wish to assign attributes
  926. * in both that and another xmlns, you will need to do stepwise grafting,
  927. * adding non-default attributes yourself or you'll have to enhance this
  928. * function. Latter, I would appreciate: martin�apfelfabrik.de
  929. * @param {Object} namespace The namespace in which
  930. * elements should be grafted.
  931. * @param {Object} parent The element that should contain the grafted
  932. * structure after the function returned.
  933. * @param {Object} t the crafting structure.
  934. * @param {Object} doc the document in which grafting is performed.
  935. */
  936. graft: function(namespace, parent, t, doc) {
  937. doc = (doc || (parent && parent.ownerDocument) || document);
  938. var e;
  939. if(t === undefined) {
  940. echo( "Can't graft an undefined value");
  941. } else if(t.constructor == String) {
  942. e = doc.createTextNode( t );
  943. } else {
  944. for(var i = 0; i < t.length; i++) {
  945. if( i === 0 && t[i].constructor == String ) {
  946. var snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i );
  947. if( snared ) {
  948. e = doc.createElementNS(namespace, snared[1]);
  949. e.setAttributeNS(null, 'class', snared[2] );
  950. continue;
  951. }
  952. snared = t[i].match( /^([a-z][a-z0-9]*)$/i );
  953. if( snared ) {
  954. e = doc.createElementNS(namespace, snared[1]); // but no class
  955. continue;
  956. }
  957. // Otherwise:
  958. e = doc.createElementNS(namespace, "span");
  959. e.setAttribute(null, "class", "namelessFromLOL" );
  960. }
  961. if( t[i] === undefined ) {
  962. echo("Can't graft an undefined value in a list!");
  963. } else if( t[i].constructor == String || t[i].constructor == Array) {
  964. this.graft(namespace, e, t[i], doc );
  965. } else if( t[i].constructor == Number ) {
  966. this.graft(namespace, e, t[i].toString(), doc );
  967. } else if( t[i].constructor == Object ) {
  968. // hash's properties => element's attributes
  969. for(var k in t[i]) { e.setAttributeNS(null, k, t[i][k] ); }
  970. } else if( t[i].constructor == Boolean ) {
  971. this.graft(namespace, e, t[i] ? 'true' : 'false', doc );
  972. } else
  973. throw "Object " + t[i] + " is inscrutable as an graft arglet.";
  974. }
  975. }
  976. if(parent) parent.appendChild(e);
  977. return Element.extend(e); // return the topmost created node
  978. },
  979. setObject: function(triple) {
  980. /**
  981. * Erwartungen von Arvid an diese Funktion:
  982. * - Es existiert genau ein triple mit dem Subjekt und Praedikat,
  983. * das uebergeben wurde, und dieses haelt uebergebenes Objekt.
  984. */
  985. var triples = DataManager.query(
  986. triple.subject,
  987. triple.predicate,
  988. undefined
  989. );
  990. DataManager.removeTriples(triples);
  991. DataManager.addTriple(triple);
  992. return true;
  993. },
  994. query: function(subject, predicate, object) {
  995. /*
  996. * Typical triple.
  997. * {value: subject, type: subjectType},
  998. * {prefix: schema.prefix, name: property},
  999. * {value: object, type: objectType});
  1000. */
  1001. return DataManager._triples.select(function(triple) {
  1002. var select = ((subject) ?
  1003. (triple.subject.type == subject.type) &&
  1004. (triple.subject.value == subject.value) : true);
  1005. if(predicate) {
  1006. select = select && ((predicate.prefix) ?
  1007. (triple.predicate.prefix == predicate.prefix) : true);
  1008. select = select && ((predicate.name) ?
  1009. (triple.predicate.name == predicate.name) : true);
  1010. }
  1011. select = select && ((object) ?
  1012. (triple.object.type == object.type) &&
  1013. (triple.object.value == object.value) : true);
  1014. return select;
  1015. });
  1016. }
  1017. }
  1018. Kickstart.register(DataManager.init);
  1019. function assert(expr, m) { if(!expr) throw m; };
  1020. function DMCommand(action, triple) {
  1021. // store action and triple.
  1022. this.action = action;
  1023. this.triple = triple;
  1024. this.toString = function() {
  1025. return 'Command('+action+', '+triple+')';
  1026. };
  1027. }
  1028. function DMCommandHandler(nextHandler) {
  1029. /**
  1030. * Private method to set the next handler in the Chain of Responsibility
  1031. * (see http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern for
  1032. * details).
  1033. * @param {DMCommandHandler} handler The handler that is next in the chain.
  1034. */
  1035. this.__setNext = function(handler) {
  1036. var _next = this.__next;
  1037. this.__next = nextHandler;
  1038. return _next ? _next : true;
  1039. };
  1040. this.__setNext(nextHandler);
  1041. /**
  1042. * Invokes the next handler. If there is no next handler, this method
  1043. * returns false, otherwise it forwards the result of the handling.
  1044. * @param {Object} command The command object to be processed.
  1045. */
  1046. this.__invokeNext = function(command) {
  1047. return this.__next ? this.__next.handle(command) : false;
  1048. };
  1049. /**
  1050. * Handles a command. The abstract method process() is called with the
  1051. * command object that has been passed. If the process method catches the
  1052. * command (returns true on completion), the handle() method returns true.
  1053. * If the process() method doesn't catch the command, the next handler will
  1054. * be invoked.
  1055. * @param {Object} command The command object to be processed.
  1056. */
  1057. this.handle = function(command) {
  1058. return this.process(command) ? true : this.__invokeNext(command);
  1059. }
  1060. /**
  1061. * Empty process() method returning false. If javascript knew abstract
  1062. * class members, this would be one.
  1063. * @param {Object} command The command object to process.
  1064. */
  1065. this.process = function(command) { return false; };
  1066. };
  1067. /**
  1068. * This Handler manages the addition and the removal of meta elements in the
  1069. * head of the document.
  1070. * @param {DMCommandHandler} next The handler that is next in the chain.
  1071. */
  1072. function MetaTagHandler(next) {
  1073. DMCommandHandler.apply(this, [next]);
  1074. this.process = function(command) {
  1075. with(command.triple) {
  1076. /* assert prerequisites */
  1077. if( !(
  1078. (subject instanceof ERDF.Resource) &&
  1079. (subject.isCurrentDocument()) &&
  1080. (object instanceof ERDF.Literal)
  1081. )) return false;
  1082. }
  1083. };
  1084. };
  1085. var chain = new MetaTagHandler();
  1086. var command = new DMCommand(TRIPLE_ADD, new ERDF.Triple(
  1087. new ERDF.Resource(''),
  1088. 'rdf:tool',
  1089. new ERDF.Literal('')
  1090. ));
  1091. /*
  1092. if(chain.handle(command))
  1093. alert('Handled!');
  1094. */
  1095. ResourceManager = {
  1096. __corrupt: false,
  1097. __latelyCreatedResource: undefined,
  1098. __listeners: $H(),
  1099. __token: 1,
  1100. addListener: function(listener, mask) {
  1101. if(!(listener instanceof Function))
  1102. throw 'Resource event listener is not a function!';
  1103. if(!(mask))
  1104. throw 'Invalid mask for resource event listener registration.';
  1105. // construct controller and token.
  1106. var controller = {listener: listener, mask: mask};
  1107. var token = ResourceManager.__token++;
  1108. // add new listener.
  1109. ResourceManager.__listeners[token] = controller;
  1110. // return the token generated.
  1111. return token;
  1112. },
  1113. removeListener: function(token) {
  1114. // remove the listener with the token and return it.
  1115. return ResourceManager.__listners.remove(token);
  1116. },
  1117. __Event: function(action, resourceId) {
  1118. this.action = action;
  1119. this.resourceId = resourceId;
  1120. },
  1121. __dispatchEvent: function(event) {
  1122. // get all listeners. for each listener, ...
  1123. ResourceManager.__listeners.values().each(function(controller) {
  1124. // .. if listener subscribed to this type of event ...
  1125. if(event.action & controller.mask)
  1126. return controller.listener(event);
  1127. });
  1128. },
  1129. getResource: function(id) {
  1130. // get all possible resources for this.
  1131. id = ERDF.__stripHashes(id);
  1132. var resources = DataManager.query(
  1133. new ERDF.Resource('#'+id),
  1134. {prefix: 'raziel', name: 'entry'},
  1135. undefined
  1136. );
  1137. // check for consistency.
  1138. if((resources.length == 1) && (resources[0].object.isResource())) {
  1139. var entryUrl = resources[0].object.value;
  1140. return new ResourceManager.__Resource(id, entryUrl);
  1141. }
  1142. // else throw an error message.
  1143. throw ('Resource with id ' +id+ ' not recognized as such. ' +
  1144. ((resources.length > 1) ?
  1145. ' There is more than one raziel:entry URL.' :
  1146. ' There is no raziel:entry URL.'));
  1147. return false;
  1148. },
  1149. __createResource: function(alternativeDiv) {
  1150. var collectionUrls = DataManager.query(
  1151. new ERDF.Resource(''),
  1152. // TODO This will become raziel:collection in near future.
  1153. {prefix: 'raziel', name: 'collection'},
  1154. undefined
  1155. );
  1156. // check for consistency.
  1157. if( (collectionUrls.length == 1) &&
  1158. (collectionUrls[0].object.isResource())) {
  1159. // get the collection url.
  1160. var collectionUrl = collectionUrls[0].object.value;
  1161. var resource = undefined;
  1162. // if there is an old id, serialize the dummy div from there,
  1163. // otherwise create a dummy div on the fly.
  1164. var serialization = alternativeDiv? alternativeDiv :
  1165. '<div xmlns="http://www.w3.org/1999/xhtml"></div>';
  1166. ResourceManager.__request(
  1167. 'POST', collectionUrl, serialization,
  1168. // on success
  1169. function() {
  1170. // get div and id that have been generated by the server.
  1171. var response = (this.responseXML);
  1172. var div = response.childNodes[0];
  1173. var id = div.getAttribute('id');
  1174. // store div in DOM
  1175. if(!$$('.' + PROCESSDATA_REF)[0])
  1176. DataManager.graft(XMLNS.XHTML,
  1177. document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]);
  1178. $$('.' + PROCESSDATA_REF)[0].appendChild(div.cloneNode(true));
  1179. // parse local erdf data once more.
  1180. DataManager.__synclocal();
  1181. // get new resource object.
  1182. resource = new ResourceManager.getResource(id);
  1183. // set up an action informing of the creation.
  1184. ResourceManager.__resourceActionSucceeded(
  1185. this, RESOURCE_CREATED, undefined);
  1186. },
  1187. function() { ResourceManager.__resourceActionFailed(
  1188. this, RESOURCE_CREATED, undefined);},
  1189. false
  1190. );
  1191. return resource;
  1192. }
  1193. // else
  1194. throw 'Could not create resource! raziel:collection URL is missing!';
  1195. return false;
  1196. },
  1197. __Resource: function(id, url) {
  1198. this.__id = id;
  1199. this.__url = url;
  1200. /*
  1201. * Process URL is no longer needed to refer to the shape element on the
  1202. * canvas. AReSS uses the id's to gather information on fireing
  1203. * behaviour now.
  1204. */
  1205. // // find the process url.
  1206. // var processUrl = undefined;
  1207. //
  1208. // var urls = DataManager.query(
  1209. // new ERDF.Resource('#'+this.__id),
  1210. // {prefix: 'raziel', name: 'process'},
  1211. // undefined
  1212. // );
  1213. //
  1214. // if(urls.length == 0) { throw 'The resource with the id ' +id+ ' has no process url.'};
  1215. //
  1216. // urls.each( function(triple) {
  1217. //
  1218. // // if there are more urls, use the last one.
  1219. // processUrl = triple.object.value;
  1220. // });
  1221. //
  1222. // this.__processUrl = processUrl;
  1223. //
  1224. // // convenience function for getting the process url.
  1225. // this.processUrl = function() {
  1226. // return this.__processUrl;
  1227. // }
  1228. // convenience finction for getting the id.
  1229. this.id = function() {
  1230. return this.__id;
  1231. }
  1232. // convenience finction for getting the entry url.
  1233. this.url = function() {
  1234. return this.__url;
  1235. }
  1236. this.reload = function() {
  1237. var _url = this.__url;
  1238. var _id = this.__id;
  1239. ResourceManager.__request(
  1240. 'GET', _url, null,
  1241. function() { ResourceManager.__resourceActionSucceeded(
  1242. this, RESOURCE_RELOADED, _id); },
  1243. function() { ResourceManager.__resourceActionFailed(
  1244. this, RESURCE_RELOADED, _id); },
  1245. USE_ASYNCHRONOUS_REQUESTS
  1246. );
  1247. };
  1248. this.save = function(synchronize) {
  1249. var _url = this.__url;
  1250. var _id = this.__id;
  1251. data = DataManager.serialize($(_id));
  1252. ResourceManager.__request(
  1253. 'PUT', _url, data,
  1254. function() { ResourceManager.__resourceActionSucceeded(
  1255. this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE_SAVED, _id); },
  1256. function() { ResourceManager.__resourceActionFailed(
  1257. this, synchronize ? RESOURCE_SAVED | RESOURCE_SYNCHRONIZED : RESOURCE.SAVED, _id); },
  1258. USE_ASYNCHRONOUS_REQUESTS
  1259. );
  1260. };
  1261. this.remove = function() {
  1262. var _url = this.__url;
  1263. var _id = this.__id;
  1264. ResourceManager.__request(
  1265. 'DELETE', _url, null,
  1266. function() { ResourceManager.__resourceActionSucceeded(
  1267. this, RESOURCE_REMOVED, _id); },
  1268. function() { ResourceManager.__resourceActionFailed(
  1269. this, RESOURCE_REMOVED, _id);},
  1270. USE_ASYNCHRONOUS_REQUESTS
  1271. );
  1272. };
  1273. },
  1274. request: function(url, requestOptions) {
  1275. var options = {
  1276. method: 'get',
  1277. asynchronous: true,
  1278. parameters: {}
  1279. };
  1280. Object.extend(options, requestOptions || {});
  1281. var params = Hash.toQueryString(options.parameters);
  1282. if (params)
  1283. url += (url.include('?') ? '&' : '?') + params;
  1284. return ResourceManager.__request(
  1285. options.method,
  1286. url,
  1287. options.data,
  1288. (options.onSuccess instanceof Function ? function() { options.onSuccess(this); } : undefined ),
  1289. (options.onFailure instanceof Function ? function() { options.onFailure(this); } : undefined ),
  1290. options.asynchronous && USE_ASYNCHRONOUS_REQUESTS,
  1291. options.headers);
  1292. },
  1293. __request: function(method, url, data, success, error, async, headers) {
  1294. // get a request object
  1295. var httpRequest = Try.these(
  1296. /* do the Mozilla/Safari/Opera stuff */
  1297. function() { return new XMLHttpRequest(); },
  1298. /* do the IE stuff */
  1299. function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
  1300. function() { return new ActiveXObject("Microsoft.XMLHTTP") }
  1301. );
  1302. // if there is no request object ...
  1303. if (!httpRequest) {
  1304. if(!this.__corrupt)
  1305. throw 'This browser does not provide any AJAX functionality. You will not be able to use the software provided with the page you are viewing. Please consider installing appropriate extensions.';
  1306. this.__corrupt = true;
  1307. return false;
  1308. }
  1309. if(success instanceof Function)
  1310. httpRequest.onload = success;
  1311. if(error instanceof Function) {
  1312. httpRequest.onerror = error;
  1313. }
  1314. var h = $H(headers)
  1315. h.keys().each(function(key) {
  1316. httpRequest.setRequestHeader(key, h[key]);
  1317. });
  1318. try {
  1319. if(SHOW_DEBUG_ALERTS_WHEN_SAVING)
  1320. alert(method + ' ' + url + '\n' +
  1321. SHOW_EXTENDED_DEBUG_INFORMATION ? data : '');
  1322. // TODO Remove synchronous calls to the server as soon as xenodot
  1323. // handles asynchronous requests without failure.
  1324. httpRequest.open(method, url, !async?false:true);
  1325. httpRequest.send(data);
  1326. } catch(e) {
  1327. return false;
  1328. }
  1329. return true;
  1330. },
  1331. __resourceActionSucceeded: function(transport, action, id) {
  1332. var status = transport.status;
  1333. var response = transport.responseText;
  1334. if(SHOW_DEBUG_ALERTS_WHEN_SAVING)
  1335. alert(status + ' ' + url + '\n' +
  1336. SHOW_EXTENDED_DEBUG_INFORMATION ? data : '');
  1337. // if the status code is not in 2xx, throw an error.
  1338. if(status >= 300)
  1339. throw 'The server responded with an error: ' + status + '\n' + (SHOW_EXTENDED_DEBUG_INFORMATION ? + data : 'If you need additional information here, including the data sent by the server, consider setting SHOW_EXTENDED_DEBUG_INFORMATION to true.');
  1340. switch(action) {
  1341. case RESOURCE_REMOVED:
  1342. // get div and id
  1343. var response = (transport.responseXML);
  1344. var div = response.childNodes[0];
  1345. var id = div.getAttribute('id');
  1346. // remove the resource from DOM
  1347. var localDiv = document.getElementById(id);
  1348. localDiv.parentNode.removeChild(localDiv);
  1349. break;
  1350. case RESOURCE_CREATED:
  1351. // nothing remains to be done.
  1352. break;
  1353. case RESOURCE_SAVED | RESOURCE_SYNCHRONIZED:
  1354. DataManager.__synclocal();
  1355. case RESOURCE_SAVED:
  1356. // nothing remains to be done.
  1357. break;
  1358. case RESOURCE_RELOADED:
  1359. // get div and id
  1360. var response = (transport.responseXML);
  1361. var div = response.childNodes[0];
  1362. var id = div.getAttribute('id');
  1363. // remove the local resource representation from DOM
  1364. var localDiv = document.getElementById(id)
  1365. localDiv.parentNode.removeChild(localDiv);
  1366. // store div in DOM
  1367. if(!$$(PROCESSDATA_REF)[0])
  1368. DataManager.graft(XMLNS.XHTML,
  1369. document.getElementsByTagNameNS(XMLNS.XHTML, 'body').item(0), ['div', {'class': PROCESSDATA_REF, 'style':'display:none;'}]);
  1370. $$(PROCESSDATA_REF)[0].appendChild(div.cloneNode(true));
  1371. DataManager.__synclocal();
  1372. break;
  1373. default:
  1374. DataManager.__synclocal();
  1375. }
  1376. // dispatch to all listeners ...
  1377. ResourceManager.__dispatchEvent(
  1378. // ... an event describing the change that happened here.
  1379. new ResourceManager.__Event(action, id)
  1380. );
  1381. },
  1382. __resourceActionFailed: function(transport, action, id) {
  1383. throw "Fatal: Resource action failed. There is something horribly " +
  1384. "wrong with either the server, the transport protocol or your " +
  1385. "online status. Sure you're online?";
  1386. }
  1387. }/**
  1388. * Copyright (c) 2006
  1389. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  1390. *
  1391. * Permission is hereby granted, free of charge, to any person obtaining a
  1392. * copy of this software and associated documentation files (the "Software"),
  1393. * to deal in the Software without restriction, including without limitation
  1394. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  1395. * and/or sell copies of the Software, and to permit persons to whom the
  1396. * Software is furnished to do so, subject to the following conditions:
  1397. *
  1398. * The above copyright notice and this permission notice shall be included in
  1399. * all copies or substantial portions of the Software.
  1400. *
  1401. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1402. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1403. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1404. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1405. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1406. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  1407. * DEALINGS IN THE SOFTWARE.
  1408. **/
  1409. /**
  1410. * The super class for all classes in ORYX. Adds some OOP feeling to javascript.
  1411. * See article "Object Oriented Super Class Method Calling with JavaScript" on
  1412. * http://truecode.blogspot.com/2006/08/object-oriented-super-class-method.html
  1413. * for a documentation on this. Fairly good article that points out errors in
  1414. * Douglas Crockford's inheritance and super method calling approach.
  1415. * Worth reading.
  1416. * @class Clazz
  1417. */
  1418. var Clazz = function() {};
  1419. /**
  1420. * Empty constructor.
  1421. * @methodOf Clazz.prototype
  1422. */
  1423. Clazz.prototype.construct = function() {};
  1424. /**
  1425. * Can be used to build up inheritances of classes.
  1426. * @example
  1427. * var MyClass = Clazz.extend({
  1428. * construct: function(myParam){
  1429. * // Do sth.
  1430. * }
  1431. * });
  1432. * var MySubClass = MyClass.extend({
  1433. * construct: function(myParam){
  1434. * // Use this to call constructor of super class
  1435. * arguments.callee.$.construct.apply(this, arguments);
  1436. * // Do sth.
  1437. * }
  1438. * });
  1439. * @param {Object} def The definition of the new class.
  1440. */
  1441. Clazz.extend = function(def) {
  1442. var classDef = function() {
  1443. if (arguments[0] !== Clazz) { this.construct.apply(this, arguments); }
  1444. };
  1445. var proto = new this(Clazz);
  1446. var superClass = this.prototype;
  1447. for (var n in def) {
  1448. var item = def[n];
  1449. if (item instanceof Function) item.$ = superClass;
  1450. proto[n] = item;
  1451. }
  1452. classDef.prototype = proto;
  1453. //Give this new class the same static extend method
  1454. classDef.extend = this.extend;
  1455. return classDef;
  1456. };/**
  1457. * Copyright (c) 2010
  1458. * Signavio GmbH
  1459. *
  1460. * Permission is hereby granted, free of charge, to any person obtaining a
  1461. * copy of this software and associated documentation files (the "Software"),
  1462. * to deal in the Software without restriction, including without limitation
  1463. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  1464. * and/or sell copies of the Software, and to permit persons to whom the
  1465. * Software is furnished to do so, subject to the following conditions:
  1466. *
  1467. * The above copyright notice and this permission notice shall be included in
  1468. * all copies or substantial portions of the Software.
  1469. *
  1470. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1471. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1472. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1473. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1474. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1475. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  1476. * DEALINGS IN THE SOFTWARE.
  1477. **/
  1478. if(!ORYX) var ORYX = {};
  1479. if(!ORYX.CONFIG) ORYX.CONFIG = {};
  1480. /**
  1481. * This file contains URI constants that may be used for XMLHTTPRequests.
  1482. */
  1483. ORYX.CONFIG.ROOT_PATH = "../editor/"; //TODO: Remove last slash!!
  1484. ORYX.CONFIG.EXPLORER_PATH = "../explorer";
  1485. ORYX.CONFIG.LIBS_PATH = "../libs";
  1486. /**
  1487. * Regular Config
  1488. */
  1489. ORYX.CONFIG.SERVER_HANDLER_ROOT = "../service";
  1490. ORYX.CONFIG.SERVER_EDITOR_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor";
  1491. ORYX.CONFIG.SERVER_MODEL_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model";
  1492. ORYX.CONFIG.STENCILSET_HANDLER = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset?embedsvg=true&url=true&namespace=";
  1493. ORYX.CONFIG.STENCIL_SETS_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_stencilset";
  1494. ORYX.CONFIG.PLUGINS_CONFIG = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor/plugins";
  1495. ORYX.CONFIG.SYNTAXCHECKER_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/syntaxchecker";
  1496. ORYX.CONFIG.DEPLOY_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/model/deploy";
  1497. ORYX.CONFIG.MODEL_LIST_URL = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/models";
  1498. ORYX.CONFIG.SS_EXTENSIONS_FOLDER = ORYX.CONFIG.ROOT_PATH + "stencilsets/extensions/";
  1499. ORYX.CONFIG.SS_EXTENSIONS_CONFIG = ORYX.CONFIG.SERVER_HANDLER_ROOT + "/editor_ssextensions";
  1500. ORYX.CONFIG.ORYX_NEW_URL = "/new";
  1501. ORYX.CONFIG.BPMN_LAYOUTER = ORYX.CONFIG.ROOT_PATH + "bpmnlayouter";/**
  1502. * Copyright (c) 2006
  1503. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  1504. *
  1505. * Permission is hereby granted, free of charge, to any person obtaining a
  1506. * copy of this software and associated documentation files (the "Software"),
  1507. * to deal in the Software without restriction, including without limitation
  1508. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  1509. * and/or sell copies of the Software, and to permit persons to whom the
  1510. * Software is furnished to do so, subject to the following conditions:
  1511. *
  1512. * The above copyright notice and this permission notice shall be included in
  1513. * all copies or substantial portions of the Software.
  1514. *
  1515. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1516. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1517. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1518. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1519. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1520. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  1521. * DEALINGS IN THE SOFTWARE.
  1522. **/
  1523. if(!ORYX) var ORYX = {};
  1524. if(!ORYX.CONFIG) ORYX.CONFIG = {};
  1525. /**
  1526. * Signavio specific variables
  1527. */
  1528. ORYX.CONFIG.BACKEND_SWITCH = true;
  1529. ORYX.CONFIG.PANEL_LEFT_WIDTH = 250;
  1530. ORYX.CONFIG.PANEL_RIGHT_COLLAPSED = true;
  1531. ORYX.CONFIG.PANEL_RIGHT_WIDTH = 300;
  1532. ORYX.CONFIG.APPNAME = 'Activiti BPM suite';
  1533. ORYX.CONFIG.WEB_URL = "../";
  1534. ORYX.CONFIG.BLANK_IMAGE = ORYX.CONFIG.LIBS_PATH + '/ext-2.0.2/resources/images/default/s.gif';
  1535. /* Show grid line while dragging */
  1536. ORYX.CONFIG.SHOW_GRIDLINE = true;
  1537. /* Editor-Mode */
  1538. ORYX.CONFIG.MODE_READONLY = "readonly";
  1539. ORYX.CONFIG.MODE_FULLSCREEN = "fullscreen";
  1540. ORYX.CONFIG.WINDOW_HEIGHT = 400;
  1541. ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY = false;
  1542. /* Plugins */
  1543. ORYX.CONFIG.PLUGINS_ENABLED = true;
  1544. ORYX.CONFIG.PLUGINS_FOLDER = "Plugins/";
  1545. ORYX.CONFIG.BPMN20_SCHEMA_VALIDATION_ON = true;
  1546. /* Namespaces */
  1547. ORYX.CONFIG.NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
  1548. ORYX.CONFIG.NAMESPACE_SVG = "http://www.w3.org/2000/svg";
  1549. /* UI */
  1550. ORYX.CONFIG.CANVAS_WIDTH = 1485;
  1551. ORYX.CONFIG.CANVAS_HEIGHT = 1050;
  1552. ORYX.CONFIG.CANVAS_RESIZE_INTERVAL = 300;
  1553. ORYX.CONFIG.SELECTED_AREA_PADDING = 4;
  1554. ORYX.CONFIG.CANVAS_BACKGROUND_COLOR = "none";
  1555. ORYX.CONFIG.GRID_DISTANCE = 30;
  1556. ORYX.CONFIG.GRID_ENABLED = true;
  1557. ORYX.CONFIG.ZOOM_OFFSET = 0.1;
  1558. ORYX.CONFIG.DEFAULT_SHAPE_MARGIN = 60;
  1559. ORYX.CONFIG.SCALERS_SIZE = 7;
  1560. ORYX.CONFIG.MINIMUM_SIZE = 20;
  1561. ORYX.CONFIG.MAXIMUM_SIZE = 10000;
  1562. ORYX.CONFIG.OFFSET_MAGNET = 15;
  1563. ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP = 8;
  1564. ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM = 8;
  1565. ORYX.CONFIG.OFFSET_EDGE_BOUNDS = 5;
  1566. ORYX.CONFIG.COPY_MOVE_OFFSET = 30;
  1567. ORYX.CONFIG.BORDER_OFFSET = 14;
  1568. ORYX.CONFIG.MAX_NUM_SHAPES_NO_GROUP = 12;
  1569. ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER = 30;
  1570. ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET = 45;
  1571. /* Shape-Menu Align */
  1572. ORYX.CONFIG.SHAPEMENU_RIGHT = "Oryx_Right";
  1573. ORYX.CONFIG.SHAPEMENU_BOTTOM = "Oryx_Bottom";
  1574. ORYX.CONFIG.SHAPEMENU_LEFT = "Oryx_Left";
  1575. ORYX.CONFIG.SHAPEMENU_TOP = "Oryx_Top";
  1576. /* Morph-Menu Item */
  1577. ORYX.CONFIG.MORPHITEM_DISABLED = "Oryx_MorphItem_disabled";
  1578. /* Property type names */
  1579. ORYX.CONFIG.TYPE_STRING = "string";
  1580. ORYX.CONFIG.TYPE_BOOLEAN = "boolean";
  1581. ORYX.CONFIG.TYPE_INTEGER = "integer";
  1582. ORYX.CONFIG.TYPE_FLOAT = "float";
  1583. ORYX.CONFIG.TYPE_COLOR = "color";
  1584. ORYX.CONFIG.TYPE_DATE = "date";
  1585. ORYX.CONFIG.TYPE_CHOICE = "choice";
  1586. ORYX.CONFIG.TYPE_URL = "url";
  1587. ORYX.CONFIG.TYPE_DIAGRAM_LINK = "diagramlink";
  1588. ORYX.CONFIG.TYPE_COMPLEX = "complex";
  1589. ORYX.CONFIG.TYPE_MULTIPLECOMPLEX = "multiplecomplex";
  1590. ORYX.CONFIG.TYPE_TEXT = "text";
  1591. ORYX.CONFIG.TYPE_MODEL_LINK = "modellink";
  1592. ORYX.CONFIG.TYPE_LISTENER = "listener";
  1593. ORYX.CONFIG.TYPE_EPC_FREQ = "epcfrequency";
  1594. ORYX.CONFIG.TYPE_GLOSSARY_LINK = "glossarylink";
  1595. /* Vertical line distance of multiline labels */
  1596. ORYX.CONFIG.LABEL_LINE_DISTANCE = 2;
  1597. ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT = 12;
  1598. /* Open Morph Menu with Hover */
  1599. ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER = false;
  1600. /* Editor constants come here */
  1601. ORYX.CONFIG.EDITOR_ALIGN_BOTTOM = 0x01;
  1602. ORYX.CONFIG.EDITOR_ALIGN_MIDDLE = 0x02;
  1603. ORYX.CONFIG.EDITOR_ALIGN_TOP = 0x04;
  1604. ORYX.CONFIG.EDITOR_ALIGN_LEFT = 0x08;
  1605. ORYX.CONFIG.EDITOR_ALIGN_CENTER = 0x10;
  1606. ORYX.CONFIG.EDITOR_ALIGN_RIGHT = 0x20;
  1607. ORYX.CONFIG.EDITOR_ALIGN_SIZE = 0x30;
  1608. /* Event types */
  1609. ORYX.CONFIG.EVENT_MOUSEDOWN = "mousedown";
  1610. ORYX.CONFIG.EVENT_MOUSEUP = "mouseup";
  1611. ORYX.CONFIG.EVENT_MOUSEOVER = "mouseover";
  1612. ORYX.CONFIG.EVENT_MOUSEOUT = "mouseout";
  1613. ORYX.CONFIG.EVENT_MOUSEMOVE = "mousemove";
  1614. ORYX.CONFIG.EVENT_DBLCLICK = "dblclick";
  1615. ORYX.CONFIG.EVENT_KEYDOWN = "keydown";
  1616. ORYX.CONFIG.EVENT_KEYUP = "keyup";
  1617. ORYX.CONFIG.EVENT_LOADED = "editorloaded";
  1618. ORYX.CONFIG.EVENT_EXECUTE_COMMANDS = "executeCommands";
  1619. ORYX.CONFIG.EVENT_STENCIL_SET_LOADED = "stencilSetLoaded";
  1620. ORYX.CONFIG.EVENT_SELECTION_CHANGED = "selectionchanged";
  1621. ORYX.CONFIG.EVENT_SHAPEADDED = "shapeadded";
  1622. ORYX.CONFIG.EVENT_SHAPEREMOVED = "shaperemoved";
  1623. ORYX.CONFIG.EVENT_PROPERTY_CHANGED = "propertyChanged";
  1624. ORYX.CONFIG.EVENT_DRAGDROP_START = "dragdrop.start";
  1625. ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE = "shape.menu.close";
  1626. ORYX.CONFIG.EVENT_DRAGDROP_END = "dragdrop.end";
  1627. ORYX.CONFIG.EVENT_RESIZE_START = "resize.start";
  1628. ORYX.CONFIG.EVENT_RESIZE_END = "resize.end";
  1629. ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED = "dragDocker.docked";
  1630. ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW = "highlight.showHighlight";
  1631. ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE = "highlight.hideHighlight";
  1632. ORYX.CONFIG.EVENT_LOADING_ENABLE = "loading.enable";
  1633. ORYX.CONFIG.EVENT_LOADING_DISABLE = "loading.disable";
  1634. ORYX.CONFIG.EVENT_LOADING_STATUS = "loading.status";
  1635. ORYX.CONFIG.EVENT_OVERLAY_SHOW = "overlay.show";
  1636. ORYX.CONFIG.EVENT_OVERLAY_HIDE = "overlay.hide";
  1637. ORYX.CONFIG.EVENT_ARRANGEMENT_TOP = "arrangement.setToTop";
  1638. ORYX.CONFIG.EVENT_ARRANGEMENT_BACK = "arrangement.setToBack";
  1639. ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD = "arrangement.setForward";
  1640. ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD = "arrangement.setBackward";
  1641. ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED = "propertyWindow.propertyChanged";
  1642. ORYX.CONFIG.EVENT_LAYOUT_ROWS = "layout.rows";
  1643. ORYX.CONFIG.EVENT_LAYOUT_BPEL = "layout.BPEL";
  1644. ORYX.CONFIG.EVENT_LAYOUT_BPEL_VERTICAL = "layout.BPEL.vertical";
  1645. ORYX.CONFIG.EVENT_LAYOUT_BPEL_HORIZONTAL = "layout.BPEL.horizontal";
  1646. ORYX.CONFIG.EVENT_LAYOUT_BPEL_SINGLECHILD = "layout.BPEL.singlechild";
  1647. ORYX.CONFIG.EVENT_LAYOUT_BPEL_AUTORESIZE = "layout.BPEL.autoresize";
  1648. ORYX.CONFIG.EVENT_AUTOLAYOUT_LAYOUT = "autolayout.layout";
  1649. ORYX.CONFIG.EVENT_UNDO_EXECUTE = "undo.execute";
  1650. ORYX.CONFIG.EVENT_UNDO_ROLLBACK = "undo.rollback";
  1651. ORYX.CONFIG.EVENT_BUTTON_UPDATE = "toolbar.button.update";
  1652. ORYX.CONFIG.EVENT_LAYOUT = "layout.dolayout";
  1653. ORYX.CONFIG.EVENT_GLOSSARY_LINK_EDIT = "glossary.link.edit";
  1654. ORYX.CONFIG.EVENT_GLOSSARY_SHOW = "glossary.show.info";
  1655. ORYX.CONFIG.EVENT_GLOSSARY_NEW = "glossary.show.new";
  1656. ORYX.CONFIG.EVENT_DOCKERDRAG = "dragTheDocker";
  1657. ORYX.CONFIG.EVENT_SHOW_PROPERTYWINDOW = "propertywindow.show";
  1658. ORYX.CONFIG.EVENT_ABOUT_TO_SAVE = "file.aboutToSave";
  1659. /* Selection Shapes Highlights */
  1660. ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE = 5;
  1661. ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR = "#4444FF";
  1662. ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR2 = "#9999FF";
  1663. ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_CORNER = "corner";
  1664. ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE = "rectangle";
  1665. ORYX.CONFIG.SELECTION_VALID_COLOR = "#00FF00";
  1666. ORYX.CONFIG.SELECTION_INVALID_COLOR = "#FF0000";
  1667. ORYX.CONFIG.DOCKER_DOCKED_COLOR = "#00FF00";
  1668. ORYX.CONFIG.DOCKER_UNDOCKED_COLOR = "#FF0000";
  1669. ORYX.CONFIG.DOCKER_SNAP_OFFSET = 10;
  1670. /* Copy & Paste */
  1671. ORYX.CONFIG.EDIT_OFFSET_PASTE = 10;
  1672. /* Key-Codes */
  1673. ORYX.CONFIG.KEY_CODE_X = 88;
  1674. ORYX.CONFIG.KEY_CODE_C = 67;
  1675. ORYX.CONFIG.KEY_CODE_V = 86;
  1676. ORYX.CONFIG.KEY_CODE_DELETE = 46;
  1677. ORYX.CONFIG.KEY_CODE_META = 224;
  1678. ORYX.CONFIG.KEY_CODE_BACKSPACE = 8;
  1679. ORYX.CONFIG.KEY_CODE_LEFT = 37;
  1680. ORYX.CONFIG.KEY_CODE_RIGHT = 39;
  1681. ORYX.CONFIG.KEY_CODE_UP = 38;
  1682. ORYX.CONFIG.KEY_CODE_DOWN = 40;
  1683. // TODO Determine where the lowercase constants are still used and remove them from here.
  1684. ORYX.CONFIG.KEY_Code_enter = 12;
  1685. ORYX.CONFIG.KEY_Code_left = 37;
  1686. ORYX.CONFIG.KEY_Code_right = 39;
  1687. ORYX.CONFIG.KEY_Code_top = 38;
  1688. ORYX.CONFIG.KEY_Code_bottom = 40;
  1689. /* Supported Meta Keys */
  1690. ORYX.CONFIG.META_KEY_META_CTRL = "metactrl";
  1691. ORYX.CONFIG.META_KEY_ALT = "alt";
  1692. ORYX.CONFIG.META_KEY_SHIFT = "shift";
  1693. /* Key Actions */
  1694. ORYX.CONFIG.KEY_ACTION_DOWN = "down";
  1695. ORYX.CONFIG.KEY_ACTION_UP = "up";
  1696. /**
  1697. * Copyright (c) 2006
  1698. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  1699. *
  1700. * Permission is hereby granted, free of charge, to any person obtaining a
  1701. * copy of this software and associated documentation files (the "Software"),
  1702. * to deal in the Software without restriction, including without limitation
  1703. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  1704. * and/or sell copies of the Software, and to permit persons to whom the
  1705. * Software is furnished to do so, subject to the following conditions:
  1706. *
  1707. * The above copyright notice and this permission notice shall be included in
  1708. * all copies or substantial portions of the Software.
  1709. *
  1710. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1711. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1712. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  1713. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  1714. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  1715. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  1716. * DEALINGS IN THE SOFTWARE.
  1717. **/
  1718. function printf() {
  1719. var result = arguments[0];
  1720. for (var i=1; i<arguments.length; i++)
  1721. result = result.replace('%' + (i-1), arguments[i]);
  1722. return result;
  1723. }
  1724. // oryx constants.
  1725. var ORYX_LOGLEVEL_TRACE = 5;
  1726. var ORYX_LOGLEVEL_DEBUG = 4;
  1727. var ORYX_LOGLEVEL_INFO = 3;
  1728. var ORYX_LOGLEVEL_WARN = 2;
  1729. var ORYX_LOGLEVEL_ERROR = 1;
  1730. var ORYX_LOGLEVEL_FATAL = 0;
  1731. var ORYX_LOGLEVEL = 3;
  1732. var ORYX_CONFIGURATION_DELAY = 100;
  1733. var ORYX_CONFIGURATION_WAIT_ATTEMPTS = 10;
  1734. if(!ORYX) var ORYX = {};
  1735. ORYX = Object.extend(ORYX, {
  1736. //set the path in the config.js file!!!!
  1737. PATH: ORYX.CONFIG.ROOT_PATH,
  1738. //CONFIGURATION: "config.js",
  1739. URLS: [
  1740. /*
  1741. * No longer needed, since compiled into one source file that
  1742. * contains all of this files concatenated in the exact order
  1743. * as defined in build.xml.
  1744. */
  1745. /*
  1746. "scripts/Core/SVG/editpathhandler.js",
  1747. "scripts/Core/SVG/minmaxpathhandler.js",
  1748. "scripts/Core/SVG/pointspathhandler.js",
  1749. "scripts/Core/SVG/svgmarker.js",
  1750. "scripts/Core/SVG/svgshape.js",
  1751. "scripts/Core/SVG/label.js",
  1752. "scripts/Core/Math/math.js",
  1753. "scripts/Core/StencilSet/stencil.js",
  1754. "scripts/Core/StencilSet/property.js",
  1755. "scripts/Core/StencilSet/propertyitem.js",
  1756. "scripts/Core/StencilSet/rules.js",
  1757. "scripts/Core/StencilSet/stencilset.js",
  1758. "scripts/Core/StencilSet/stencilsets.js",
  1759. "scripts/Core/bounds.js",
  1760. "scripts/Core/uiobject.js",
  1761. "scripts/Core/abstractshape.js",
  1762. "scripts/Core/canvas.js",
  1763. "scripts/Core/main.js",
  1764. "scripts/Core/svgDrag.js",
  1765. "scripts/Core/shape.js",
  1766. "scripts/Core/Controls/control.js",
  1767. "scripts/Core/Controls/docker.js",
  1768. "scripts/Core/Controls/magnet.js",
  1769. "scripts/Core/node.js",
  1770. "scripts/Core/edge.js"
  1771. */ ],
  1772. alreadyLoaded: [],
  1773. configrationRetries: 0,
  1774. Version: '0.1.1',
  1775. availablePlugins: [],
  1776. /**
  1777. * The ORYX.Log logger.
  1778. */
  1779. Log: {
  1780. __appenders: [
  1781. { append: function(message) {
  1782. console.log(message); }}
  1783. ],
  1784. trace: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_TRACE)
  1785. ORYX.Log.__log('TRACE', arguments); },
  1786. debug: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_DEBUG)
  1787. ORYX.Log.__log('DEBUG', arguments); },
  1788. info: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_INFO)
  1789. ORYX.Log.__log('INFO', arguments); },
  1790. warn: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_WARN)
  1791. ORYX.Log.__log('WARN', arguments); },
  1792. error: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_ERROR)
  1793. ORYX.Log.__log('ERROR', arguments); },
  1794. fatal: function() { if(ORYX_LOGLEVEL >= ORYX_LOGLEVEL_FATAL)
  1795. ORYX.Log.__log('FATAL', arguments); },
  1796. __log: function(prefix, messageParts) {
  1797. messageParts[0] = (new Date()).getTime() + " "
  1798. + prefix + " " + messageParts[0];
  1799. var message = printf.apply(null, messageParts);
  1800. ORYX.Log.__appenders.each(function(appender) {
  1801. appender.append(message);
  1802. });
  1803. },
  1804. addAppender: function(appender) {
  1805. ORYX.Log.__appenders.push(appender);
  1806. }
  1807. },
  1808. /**
  1809. * First bootstrapping layer. The Oryx loading procedure begins. In this
  1810. * step, all preliminaries that are not in the responsibility of Oryx to be
  1811. * met have to be checked here, such as the existance of the prototpe
  1812. * library in the current execution environment. After that, the second
  1813. * bootstrapping layer is being invoked. Failing to ensure that any
  1814. * preliminary condition is not met has to fail with an error.
  1815. */
  1816. load: function() {
  1817. if (ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY !== true) {
  1818. var waitingpanel = new Ext.Window({renderTo:Ext.getBody(),id:'oryx-loading-panel',bodyStyle:'padding: 8px;background:white',title:ORYX.I18N.Oryx.title,width:'auto',height:'auto',modal:true,resizable:false,closable:false,html:'<span style="font-size:11px;">' + ORYX.I18N.Oryx.pleaseWait + '</span>'})
  1819. waitingpanel.show()
  1820. }
  1821. ORYX.Log.debug("Oryx begins loading procedure.");
  1822. // check for prototype
  1823. if( (typeof Prototype=='undefined') ||
  1824. (typeof Element == 'undefined') ||
  1825. (typeof Element.Methods=='undefined') ||
  1826. parseFloat(Prototype.Version.split(".")[0] + "." +
  1827. Prototype.Version.split(".")[1]) < 1.5)
  1828. throw("Application requires the Prototype JavaScript framework >= 1.5.3");
  1829. ORYX.Log.debug("Prototype > 1.5 found.");
  1830. // continue loading.
  1831. ORYX._load();
  1832. },
  1833. /**
  1834. * Second bootstrapping layer. The oryx configuration is checked. When not
  1835. * yet loaded, config.js is being requested from the server. A repeated
  1836. * error in retrieving the configuration will result in an error to be
  1837. * thrown after a certain time of retries. Once the configuration is there,
  1838. * all urls that are registered with oryx loading are being requested from
  1839. * the server. Once everything is loaded, the third layer is being invoked.
  1840. */
  1841. _load: function() {
  1842. /*
  1843. // if configuration not there already,
  1844. if(!(ORYX.CONFIG)) {
  1845. // if this is the first attempt...
  1846. if(ORYX.configrationRetries == 0) {
  1847. // get the path and filename.
  1848. var configuration = ORYX.PATH + ORYX.CONFIGURATION;
  1849. ORYX.Log.debug("Configuration not found, loading from '%0'.",
  1850. configuration);
  1851. // require configuration file.
  1852. Kickstart.require(configuration);
  1853. // else if attempts exceeded ...
  1854. } else if(ORYX.configrationRetries >= ORYX_CONFIGURATION_WAIT_ATTEMPTS) {
  1855. throw "Tried to get configuration" +
  1856. ORYX_CONFIGURATION_WAIT_ATTEMPTS +
  1857. " times from '" + configuration + "'. Giving up."
  1858. } else if(ORYX.configrationRetries > 0){
  1859. // point out how many attempts are left...
  1860. ORYX.Log.debug("Waiting once more (%0 attempts left)",
  1861. (ORYX_CONFIGURATION_WAIT_ATTEMPTS -
  1862. ORYX.configrationRetries));
  1863. }
  1864. // any case: continue in a moment with increased retry count.
  1865. ORYX.configrationRetries++;
  1866. window.setTimeout(ORYX._load, ORYX_CONFIGURATION_DELAY);
  1867. return;
  1868. }
  1869. ORYX.Log.info("Configuration loaded.");
  1870. // load necessary scripts.
  1871. ORYX.URLS.each(function(url) {
  1872. ORYX.Log.debug("Requireing '%0'", url);
  1873. Kickstart.require(ORYX.PATH + url) });
  1874. */
  1875. // configurate logging and load plugins.
  1876. ORYX.loadPlugins();
  1877. },
  1878. /**
  1879. * Third bootstrapping layer. This is where first the plugin coniguration
  1880. * file is loaded into oryx, analyzed, and where all plugins are being
  1881. * requested by the server. Afterwards, all editor instances will be
  1882. * initialized.
  1883. */
  1884. loadPlugins: function() {
  1885. // load plugins if enabled.
  1886. if(ORYX.CONFIG.PLUGINS_ENABLED)
  1887. ORYX._loadPlugins()
  1888. else
  1889. ORYX.Log.warn("Ignoring plugins, loading Core only.");
  1890. // init the editor instances.
  1891. init();
  1892. },
  1893. _loadPlugins: function() {
  1894. // load plugin configuration file.
  1895. var source = ORYX.CONFIG.PLUGINS_CONFIG;
  1896. ORYX.Log.debug("Loading plugin configuration from '%0'.", source);
  1897. new Ajax.Request(source, {
  1898. asynchronous: false,
  1899. method: 'get',
  1900. onSuccess: function(result) {
  1901. /*
  1902. * This is the method that is being called when the plugin
  1903. * configuration was successfully loaded from the server. The
  1904. * file has to be processed and the contents need to be
  1905. * considered for further plugin requireation.
  1906. */
  1907. ORYX.Log.info("Plugin configuration file loaded.");
  1908. // get plugins.xml content
  1909. var resultXml = result.responseXML;
  1910. // TODO: Describe how properties are handled.
  1911. // Get the globale Properties
  1912. var globalProperties = [];
  1913. var preferences = $A(resultXml.getElementsByTagName("properties"));
  1914. preferences.each( function(p) {
  1915. var props = $A(p.childNodes);
  1916. props.each( function(prop) {
  1917. var property = new Hash();
  1918. // get all attributes from the node and set to global properties
  1919. var attributes = $A(prop.attributes)
  1920. attributes.each(function(attr){property[attr.nodeName] = attr.nodeValue});
  1921. if(attributes.length > 0) { globalProperties.push(property) };
  1922. });
  1923. });
  1924. // TODO Why are we using XML if we don't respect structure anyway?
  1925. // for each plugin element in the configuration..
  1926. var plugin = resultXml.getElementsByTagName("plugin");
  1927. $A(plugin).each( function(node) {
  1928. // get all element's attributes.
  1929. // TODO: What about: var pluginData = $H(node.attributes) !?
  1930. var pluginData = new Hash();
  1931. $A(node.attributes).each( function(attr){
  1932. pluginData[attr.nodeName] = attr.nodeValue});
  1933. // ensure there's a name attribute.
  1934. if(!pluginData['name']) {
  1935. ORYX.Log.error("A plugin is not providing a name. Ingnoring this plugin.");
  1936. return;
  1937. }
  1938. // ensure there's a source attribute.
  1939. if(!pluginData['source']) {
  1940. ORYX.Log.error("Plugin with name '%0' doesn't provide a source attribute.", pluginData['name']);
  1941. return;
  1942. }
  1943. // Get all private Properties
  1944. var propertyNodes = node.getElementsByTagName("property");
  1945. var properties = [];
  1946. $A(propertyNodes).each(function(prop) {
  1947. var property = new Hash();
  1948. // Get all Attributes from the Node
  1949. var attributes = $A(prop.attributes)
  1950. attributes.each(function(attr){property[attr.nodeName] = attr.nodeValue});
  1951. if(attributes.length > 0) { properties.push(property) };
  1952. });
  1953. // Set all Global-Properties to the Properties
  1954. properties = properties.concat(globalProperties);
  1955. // Set Properties to Plugin-Data
  1956. pluginData['properties'] = properties;
  1957. // Get the RequieredNodes
  1958. var requireNodes = node.getElementsByTagName("requires");
  1959. var requires;
  1960. $A(requireNodes).each(function(req) {
  1961. var namespace = $A(req.attributes).find(function(attr){ return attr.name == "namespace"})
  1962. if( namespace && namespace.nodeValue ){
  1963. if( !requires ){
  1964. requires = {namespaces:[]}
  1965. }
  1966. requires.namespaces.push(namespace.nodeValue)
  1967. }
  1968. });
  1969. // Set Requires to the Plugin-Data, if there is one
  1970. if( requires ){
  1971. pluginData['requires'] = requires;
  1972. }
  1973. // Get the RequieredNodes
  1974. var notUsesInNodes = node.getElementsByTagName("notUsesIn");
  1975. var notUsesIn;
  1976. $A(notUsesInNodes).each(function(not) {
  1977. var namespace = $A(not.attributes).find(function(attr){ return attr.name == "namespace"})
  1978. if( namespace && namespace.nodeValue ){
  1979. if( !notUsesIn ){
  1980. notUsesIn = {namespaces:[]}
  1981. }
  1982. notUsesIn.namespaces.push(namespace.nodeValue)
  1983. }
  1984. });
  1985. // Set Requires to the Plugin-Data, if there is one
  1986. if( notUsesIn ){
  1987. pluginData['notUsesIn'] = notUsesIn;
  1988. }
  1989. var url = ORYX.PATH + ORYX.CONFIG.PLUGINS_FOLDER + pluginData['source'];
  1990. ORYX.Log.debug("Requireing '%0'", url);
  1991. // Add the Script-Tag to the Site
  1992. //Kickstart.require(url);
  1993. ORYX.Log.info("Plugin '%0' successfully loaded.", pluginData['name']);
  1994. // Add the Plugin-Data to all available Plugins
  1995. ORYX.availablePlugins.push(pluginData);
  1996. });
  1997. },
  1998. onFailure:this._loadPluginsOnFails
  1999. });
  2000. },
  2001. _loadPluginsOnFails: function(result) {
  2002. ORYX.Log.error("Plugin configuration file not available.");
  2003. }
  2004. });
  2005. ORYX.Log.debug('Registering Oryx with Kickstart');
  2006. Kickstart.register(ORYX.load);
  2007. /**
  2008. * Copyright (c) 2006
  2009. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  2010. *
  2011. * Permission is hereby granted, free of charge, to any person obtaining a
  2012. * copy of this software and associated documentation files (the "Software"),
  2013. * to deal in the Software without restriction, including without limitation
  2014. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  2015. * and/or sell copies of the Software, and to permit persons to whom the
  2016. * Software is furnished to do so, subject to the following conditions:
  2017. *
  2018. * The above copyright notice and this permission notice shall be included in
  2019. * all copies or substantial portions of the Software.
  2020. *
  2021. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2022. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2023. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2024. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2025. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2026. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  2027. * DEALINGS IN THE SOFTWARE.
  2028. **/
  2029. /**
  2030. * Init namespaces
  2031. */
  2032. if(!ORYX) {var ORYX = {};}
  2033. if(!ORYX.Core) {ORYX.Core = {};}
  2034. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  2035. /**
  2036. * EditPathHandler
  2037. *
  2038. * Edit SVG paths' coordinates according to specified from-to movement and
  2039. * horizontal and vertical scaling factors.
  2040. * The resulting path's d attribute is stored in instance variable d.
  2041. *
  2042. * @constructor
  2043. */
  2044. ORYX.Core.SVG.EditPathHandler = Clazz.extend({
  2045. construct: function() {
  2046. arguments.callee.$.construct.apply(this, arguments);
  2047. this.x = 0;
  2048. this.y = 0;
  2049. this.oldX = 0;
  2050. this.oldY = 0;
  2051. this.deltaWidth = 1;
  2052. this.deltaHeight = 1;
  2053. this.d = "";
  2054. },
  2055. /**
  2056. * init
  2057. *
  2058. * @param {float} x Target point's x-coordinate
  2059. * @param {float} y Target point's y-coordinate
  2060. * @param {float} oldX Reference point's x-coordinate
  2061. * @param {float} oldY Reference point's y-coordinate
  2062. * @param {float} deltaWidth Horizontal scaling factor
  2063. * @param {float} deltaHeight Vertical scaling factor
  2064. */
  2065. init: function(x, y, oldX, oldY, deltaWidth, deltaHeight) {
  2066. this.x = x;
  2067. this.y = y;
  2068. this.oldX = oldX;
  2069. this.oldY = oldY;
  2070. this.deltaWidth = deltaWidth;
  2071. this.deltaHeight = deltaHeight;
  2072. this.d = "";
  2073. },
  2074. /**
  2075. * editPointsAbs
  2076. *
  2077. * @param {Array} points Array of absolutePoints
  2078. */
  2079. editPointsAbs: function(points) {
  2080. if(points instanceof Array) {
  2081. var newPoints = [];
  2082. var x, y;
  2083. for(var i = 0; i < points.length; i++) {
  2084. x = (parseFloat(points[i]) - this.oldX)*this.deltaWidth + this.x;
  2085. i++;
  2086. y = (parseFloat(points[i]) - this.oldY)*this.deltaHeight + this.y;
  2087. newPoints.push(x);
  2088. newPoints.push(y);
  2089. }
  2090. return newPoints;
  2091. } else {
  2092. //TODO error
  2093. }
  2094. },
  2095. /**
  2096. * editPointsRel
  2097. *
  2098. * @param {Array} points Array of absolutePoints
  2099. */
  2100. editPointsRel: function(points) {
  2101. if(points instanceof Array) {
  2102. var newPoints = [];
  2103. var x, y;
  2104. for(var i = 0; i < points.length; i++) {
  2105. x = parseFloat(points[i])*this.deltaWidth;
  2106. i++;
  2107. y = parseFloat(points[i])*this.deltaHeight;
  2108. newPoints.push(x);
  2109. newPoints.push(y);
  2110. }
  2111. return newPoints;
  2112. } else {
  2113. //TODO error
  2114. }
  2115. },
  2116. /**
  2117. * arcAbs - A
  2118. *
  2119. * @param {Number} rx
  2120. * @param {Number} ry
  2121. * @param {Number} xAxisRotation
  2122. * @param {Boolean} largeArcFlag
  2123. * @param {Boolean} sweepFlag
  2124. * @param {Number} x
  2125. * @param {Number} y
  2126. */
  2127. arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2128. var pointsAbs = this.editPointsAbs([x, y]);
  2129. var pointsRel = this.editPointsRel([rx, ry]);
  2130. this.d = this.d.concat(" A" + pointsRel[0] + " " + pointsRel[1] +
  2131. " " + xAxisRotation + " " + largeArcFlag +
  2132. " " + sweepFlag + " " + pointsAbs[0] + " " +
  2133. pointsAbs[1] + " ");
  2134. },
  2135. /**
  2136. * arcRel - a
  2137. *
  2138. * @param {Number} rx
  2139. * @param {Number} ry
  2140. * @param {Number} xAxisRotation
  2141. * @param {Boolean} largeArcFlag
  2142. * @param {Boolean} sweepFlag
  2143. * @param {Number} x
  2144. * @param {Number} y
  2145. */
  2146. arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2147. var pointsRel = this.editPointsRel([rx, ry, x, y]);
  2148. this.d = this.d.concat(" a" + pointsRel[0] + " " + pointsRel[1] +
  2149. " " + xAxisRotation + " " + largeArcFlag +
  2150. " " + sweepFlag + " " + pointsRel[2] + " " +
  2151. pointsRel[3] + " ");
  2152. },
  2153. /**
  2154. * curvetoCubicAbs - C
  2155. *
  2156. * @param {Number} x1
  2157. * @param {Number} y1
  2158. * @param {Number} x2
  2159. * @param {Number} y2
  2160. * @param {Number} x
  2161. * @param {Number} y
  2162. */
  2163. curvetoCubicAbs: function(x1, y1, x2, y2, x, y) {
  2164. var pointsAbs = this.editPointsAbs([x1, y1, x2, y2, x, y]);
  2165. this.d = this.d.concat(" C" + pointsAbs[0] + " " + pointsAbs[1] +
  2166. " " + pointsAbs[2] + " " + pointsAbs[3] +
  2167. " " + pointsAbs[4] + " " + pointsAbs[5] + " ");
  2168. },
  2169. /**
  2170. * curvetoCubicRel - c
  2171. *
  2172. * @param {Number} x1
  2173. * @param {Number} y1
  2174. * @param {Number} x2
  2175. * @param {Number} y2
  2176. * @param {Number} x
  2177. * @param {Number} y
  2178. */
  2179. curvetoCubicRel: function(x1, y1, x2, y2, x, y) {
  2180. var pointsRel = this.editPointsRel([x1, y1, x2, y2, x, y]);
  2181. this.d = this.d.concat(" c" + pointsRel[0] + " " + pointsRel[1] +
  2182. " " + pointsRel[2] + " " + pointsRel[3] +
  2183. " " + pointsRel[4] + " " + pointsRel[5] + " ");
  2184. },
  2185. /**
  2186. * linetoHorizontalAbs - H
  2187. *
  2188. * @param {Number} x
  2189. */
  2190. linetoHorizontalAbs: function(x) {
  2191. var pointsAbs = this.editPointsAbs([x, 0]);
  2192. this.d = this.d.concat(" H" + pointsAbs[0] + " ");
  2193. },
  2194. /**
  2195. * linetoHorizontalRel - h
  2196. *
  2197. * @param {Number} x
  2198. */
  2199. linetoHorizontalRel: function(x) {
  2200. var pointsRel = this.editPointsRel([x, 0]);
  2201. this.d = this.d.concat(" h" + pointsRel[0] + " ");
  2202. },
  2203. /**
  2204. * linetoAbs - L
  2205. *
  2206. * @param {Number} x
  2207. * @param {Number} y
  2208. */
  2209. linetoAbs: function(x, y) {
  2210. var pointsAbs = this.editPointsAbs([x, y]);
  2211. this.d = this.d.concat(" L" + pointsAbs[0] + " " + pointsAbs[1] + " ");
  2212. },
  2213. /**
  2214. * linetoRel - l
  2215. *
  2216. * @param {Number} x
  2217. * @param {Number} y
  2218. */
  2219. linetoRel: function(x, y) {
  2220. var pointsRel = this.editPointsRel([x, y]);
  2221. this.d = this.d.concat(" l" + pointsRel[0] + " " + pointsRel[1] + " ");
  2222. },
  2223. /**
  2224. * movetoAbs - M
  2225. *
  2226. * @param {Number} x
  2227. * @param {Number} y
  2228. */
  2229. movetoAbs: function(x, y) {
  2230. var pointsAbs = this.editPointsAbs([x, y]);
  2231. this.d = this.d.concat(" M" + pointsAbs[0] + " " + pointsAbs[1] + " ");
  2232. },
  2233. /**
  2234. * movetoRel - m
  2235. *
  2236. * @param {Number} x
  2237. * @param {Number} y
  2238. */
  2239. movetoRel: function(x, y) {
  2240. var pointsRel;
  2241. if(this.d === "") {
  2242. pointsRel = this.editPointsAbs([x, y]);
  2243. } else {
  2244. pointsRel = this.editPointsRel([x, y]);
  2245. }
  2246. this.d = this.d.concat(" m" + pointsRel[0] + " " + pointsRel[1] + " ");
  2247. },
  2248. /**
  2249. * curvetoQuadraticAbs - Q
  2250. *
  2251. * @param {Number} x1
  2252. * @param {Number} y1
  2253. * @param {Number} x
  2254. * @param {Number} y
  2255. */
  2256. curvetoQuadraticAbs: function(x1, y1, x, y) {
  2257. var pointsAbs = this.editPointsAbs([x1, y1, x, y]);
  2258. this.d = this.d.concat(" Q" + pointsAbs[0] + " " + pointsAbs[1] + " " +
  2259. pointsAbs[2] + " " + pointsAbs[3] + " ");
  2260. },
  2261. /**
  2262. * curvetoQuadraticRel - q
  2263. *
  2264. * @param {Number} x1
  2265. * @param {Number} y1
  2266. * @param {Number} x
  2267. * @param {Number} y
  2268. */
  2269. curvetoQuadraticRel: function(x1, y1, x, y) {
  2270. var pointsRel = this.editPointsRel([x1, y1, x, y]);
  2271. this.d = this.d.concat(" q" + pointsRel[0] + " " + pointsRel[1] + " " +
  2272. pointsRel[2] + " " + pointsRel[3] + " ");
  2273. },
  2274. /**
  2275. * curvetoCubicSmoothAbs - S
  2276. *
  2277. * @param {Number} x2
  2278. * @param {Number} y2
  2279. * @param {Number} x
  2280. * @param {Number} y
  2281. */
  2282. curvetoCubicSmoothAbs: function(x2, y2, x, y) {
  2283. var pointsAbs = this.editPointsAbs([x2, y2, x, y]);
  2284. this.d = this.d.concat(" S" + pointsAbs[0] + " " + pointsAbs[1] + " " +
  2285. pointsAbs[2] + " " + pointsAbs[3] + " ");
  2286. },
  2287. /**
  2288. * curvetoCubicSmoothRel - s
  2289. *
  2290. * @param {Number} x2
  2291. * @param {Number} y2
  2292. * @param {Number} x
  2293. * @param {Number} y
  2294. */
  2295. curvetoCubicSmoothRel: function(x2, y2, x, y) {
  2296. var pointsRel = this.editPointsRel([x2, y2, x, y]);
  2297. this.d = this.d.concat(" s" + pointsRel[0] + " " + pointsRel[1] + " " +
  2298. pointsRel[2] + " " + pointsRel[3] + " ");
  2299. },
  2300. /**
  2301. * curvetoQuadraticSmoothAbs - T
  2302. *
  2303. * @param {Number} x
  2304. * @param {Number} y
  2305. */
  2306. curvetoQuadraticSmoothAbs: function(x, y) {
  2307. var pointsAbs = this.editPointsAbs([x, y]);
  2308. this.d = this.d.concat(" T" + pointsAbs[0] + " " + pointsAbs[1] + " ");
  2309. },
  2310. /**
  2311. * curvetoQuadraticSmoothRel - t
  2312. *
  2313. * @param {Number} x
  2314. * @param {Number} y
  2315. */
  2316. curvetoQuadraticSmoothRel: function(x, y) {
  2317. var pointsRel = this.editPointsRel([x, y]);
  2318. this.d = this.d.concat(" t" + pointsRel[0] + " " + pointsRel[1] + " ");
  2319. },
  2320. /**
  2321. * linetoVerticalAbs - V
  2322. *
  2323. * @param {Number} y
  2324. */
  2325. linetoVerticalAbs: function(y) {
  2326. var pointsAbs = this.editPointsAbs([0, y]);
  2327. this.d = this.d.concat(" V" + pointsAbs[1] + " ");
  2328. },
  2329. /**
  2330. * linetoVerticalRel - v
  2331. *
  2332. * @param {Number} y
  2333. */
  2334. linetoVerticalRel: function(y) {
  2335. var pointsRel = this.editPointsRel([0, y]);
  2336. this.d = this.d.concat(" v" + pointsRel[1] + " ");
  2337. },
  2338. /**
  2339. * closePath - z or Z
  2340. */
  2341. closePath: function() {
  2342. this.d = this.d.concat(" z");
  2343. }
  2344. });/**
  2345. * Copyright (c) 2006
  2346. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  2347. *
  2348. * Permission is hereby granted, free of charge, to any person obtaining a
  2349. * copy of this software and associated documentation files (the "Software"),
  2350. * to deal in the Software without restriction, including without limitation
  2351. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  2352. * and/or sell copies of the Software, and to permit persons to whom the
  2353. * Software is furnished to do so, subject to the following conditions:
  2354. *
  2355. * The above copyright notice and this permission notice shall be included in
  2356. * all copies or substantial portions of the Software.
  2357. *
  2358. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2359. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2360. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2361. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2362. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2363. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  2364. * DEALINGS IN THE SOFTWARE.
  2365. **/
  2366. /**
  2367. * Init namespaces
  2368. */
  2369. if(!ORYX) {var ORYX = {};}
  2370. if(!ORYX.Core) {ORYX.Core = {};}
  2371. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  2372. /**
  2373. * MinMaxPathHandler
  2374. *
  2375. * Determine the minimum and maximum of a SVG path's absolute coordinates.
  2376. * For relative coordinates the absolute value is computed for consideration.
  2377. * The values are stored in attributes minX, minY, maxX, and maxY.
  2378. *
  2379. * @constructor
  2380. */
  2381. ORYX.Core.SVG.MinMaxPathHandler = Clazz.extend({
  2382. construct: function() {
  2383. arguments.callee.$.construct.apply(this, arguments);
  2384. this.minX = undefined;
  2385. this.minY = undefined;
  2386. this.maxX = undefined;
  2387. this.maxY = undefined;
  2388. this._lastAbsX = undefined;
  2389. this._lastAbsY = undefined;
  2390. },
  2391. /**
  2392. * Store minimal and maximal coordinates of passed points to attributes minX, maxX, minY, maxY
  2393. *
  2394. * @param {Array} points Array of absolutePoints
  2395. */
  2396. calculateMinMax: function(points) {
  2397. if(points instanceof Array) {
  2398. var x, y;
  2399. for(var i = 0; i < points.length; i++) {
  2400. x = parseFloat(points[i]);
  2401. i++;
  2402. y = parseFloat(points[i]);
  2403. this.minX = (this.minX !== undefined) ? Math.min(this.minX, x) : x;
  2404. this.maxX = (this.maxX !== undefined) ? Math.max(this.maxX, x) : x;
  2405. this.minY = (this.minY !== undefined) ? Math.min(this.minY, y) : y;
  2406. this.maxY = (this.maxY !== undefined) ? Math.max(this.maxY, y) : y;
  2407. this._lastAbsX = x;
  2408. this._lastAbsY = y;
  2409. }
  2410. } else {
  2411. //TODO error
  2412. }
  2413. },
  2414. /**
  2415. * arcAbs - A
  2416. *
  2417. * @param {Number} rx
  2418. * @param {Number} ry
  2419. * @param {Number} xAxisRotation
  2420. * @param {Boolean} largeArcFlag
  2421. * @param {Boolean} sweepFlag
  2422. * @param {Number} x
  2423. * @param {Number} y
  2424. */
  2425. arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2426. this.calculateMinMax([x, y]);
  2427. },
  2428. /**
  2429. * arcRel - a
  2430. *
  2431. * @param {Number} rx
  2432. * @param {Number} ry
  2433. * @param {Number} xAxisRotation
  2434. * @param {Boolean} largeArcFlag
  2435. * @param {Boolean} sweepFlag
  2436. * @param {Number} x
  2437. * @param {Number} y
  2438. */
  2439. arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2440. this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
  2441. },
  2442. /**
  2443. * curvetoCubicAbs - C
  2444. *
  2445. * @param {Number} x1
  2446. * @param {Number} y1
  2447. * @param {Number} x2
  2448. * @param {Number} y2
  2449. * @param {Number} x
  2450. * @param {Number} y
  2451. */
  2452. curvetoCubicAbs: function(x1, y1, x2, y2, x, y) {
  2453. this.calculateMinMax([x1, y1, x2, y2, x, y]);
  2454. },
  2455. /**
  2456. * curvetoCubicRel - c
  2457. *
  2458. * @param {Number} x1
  2459. * @param {Number} y1
  2460. * @param {Number} x2
  2461. * @param {Number} y2
  2462. * @param {Number} x
  2463. * @param {Number} y
  2464. */
  2465. curvetoCubicRel: function(x1, y1, x2, y2, x, y) {
  2466. this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1,
  2467. this._lastAbsX + x2, this._lastAbsY + y2,
  2468. this._lastAbsX + x, this._lastAbsY + y]);
  2469. },
  2470. /**
  2471. * linetoHorizontalAbs - H
  2472. *
  2473. * @param {Number} x
  2474. */
  2475. linetoHorizontalAbs: function(x) {
  2476. this.calculateMinMax([x, this._lastAbsY]);
  2477. },
  2478. /**
  2479. * linetoHorizontalRel - h
  2480. *
  2481. * @param {Number} x
  2482. */
  2483. linetoHorizontalRel: function(x) {
  2484. this.calculateMinMax([this._lastAbsX + x, this._lastAbsY]);
  2485. },
  2486. /**
  2487. * linetoAbs - L
  2488. *
  2489. * @param {Number} x
  2490. * @param {Number} y
  2491. */
  2492. linetoAbs: function(x, y) {
  2493. this.calculateMinMax([x, y]);
  2494. },
  2495. /**
  2496. * linetoRel - l
  2497. *
  2498. * @param {Number} x
  2499. * @param {Number} y
  2500. */
  2501. linetoRel: function(x, y) {
  2502. this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
  2503. },
  2504. /**
  2505. * movetoAbs - M
  2506. *
  2507. * @param {Number} x
  2508. * @param {Number} y
  2509. */
  2510. movetoAbs: function(x, y) {
  2511. this.calculateMinMax([x, y]);
  2512. },
  2513. /**
  2514. * movetoRel - m
  2515. *
  2516. * @param {Number} x
  2517. * @param {Number} y
  2518. */
  2519. movetoRel: function(x, y) {
  2520. if(this._lastAbsX && this._lastAbsY) {
  2521. this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
  2522. } else {
  2523. this.calculateMinMax([x, y]);
  2524. }
  2525. },
  2526. /**
  2527. * curvetoQuadraticAbs - Q
  2528. *
  2529. * @param {Number} x1
  2530. * @param {Number} y1
  2531. * @param {Number} x
  2532. * @param {Number} y
  2533. */
  2534. curvetoQuadraticAbs: function(x1, y1, x, y) {
  2535. this.calculateMinMax([x1, y1, x, y]);
  2536. },
  2537. /**
  2538. * curvetoQuadraticRel - q
  2539. *
  2540. * @param {Number} x1
  2541. * @param {Number} y1
  2542. * @param {Number} x
  2543. * @param {Number} y
  2544. */
  2545. curvetoQuadraticRel: function(x1, y1, x, y) {
  2546. this.calculateMinMax([this._lastAbsX + x1, this._lastAbsY + y1, this._lastAbsX + x, this._lastAbsY + y]);
  2547. },
  2548. /**
  2549. * curvetoCubicSmoothAbs - S
  2550. *
  2551. * @param {Number} x2
  2552. * @param {Number} y2
  2553. * @param {Number} x
  2554. * @param {Number} y
  2555. */
  2556. curvetoCubicSmoothAbs: function(x2, y2, x, y) {
  2557. this.calculateMinMax([x2, y2, x, y]);
  2558. },
  2559. /**
  2560. * curvetoCubicSmoothRel - s
  2561. *
  2562. * @param {Number} x2
  2563. * @param {Number} y2
  2564. * @param {Number} x
  2565. * @param {Number} y
  2566. */
  2567. curvetoCubicSmoothRel: function(x2, y2, x, y) {
  2568. this.calculateMinMax([this._lastAbsX + x2, this._lastAbsY + y2, this._lastAbsX + x, this._lastAbsY + y]);
  2569. },
  2570. /**
  2571. * curvetoQuadraticSmoothAbs - T
  2572. *
  2573. * @param {Number} x
  2574. * @param {Number} y
  2575. */
  2576. curvetoQuadraticSmoothAbs: function(x, y) {
  2577. this.calculateMinMax([x, y]);
  2578. },
  2579. /**
  2580. * curvetoQuadraticSmoothRel - t
  2581. *
  2582. * @param {Number} x
  2583. * @param {Number} y
  2584. */
  2585. curvetoQuadraticSmoothRel: function(x, y) {
  2586. this.calculateMinMax([this._lastAbsX + x, this._lastAbsY + y]);
  2587. },
  2588. /**
  2589. * linetoVerticalAbs - V
  2590. *
  2591. * @param {Number} y
  2592. */
  2593. linetoVerticalAbs: function(y) {
  2594. this.calculateMinMax([this._lastAbsX, y]);
  2595. },
  2596. /**
  2597. * linetoVerticalRel - v
  2598. *
  2599. * @param {Number} y
  2600. */
  2601. linetoVerticalRel: function(y) {
  2602. this.calculateMinMax([this._lastAbsX, this._lastAbsY + y]);
  2603. },
  2604. /**
  2605. * closePath - z or Z
  2606. */
  2607. closePath: function() {
  2608. return;// do nothing
  2609. }
  2610. });/**
  2611. * Copyright (c) 2006
  2612. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  2613. *
  2614. * Permission is hereby granted, free of charge, to any person obtaining a
  2615. * copy of this software and associated documentation files (the "Software"),
  2616. * to deal in the Software without restriction, including without limitation
  2617. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  2618. * and/or sell copies of the Software, and to permit persons to whom the
  2619. * Software is furnished to do so, subject to the following conditions:
  2620. *
  2621. * The above copyright notice and this permission notice shall be included in
  2622. * all copies or substantial portions of the Software.
  2623. *
  2624. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2625. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2626. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2627. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2628. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2629. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  2630. * DEALINGS IN THE SOFTWARE.
  2631. **/
  2632. /**
  2633. * Init namespaces
  2634. */
  2635. if(!ORYX) {var ORYX = {};}
  2636. if(!ORYX.Core) {ORYX.Core = {};}
  2637. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  2638. /**
  2639. * PathHandler
  2640. *
  2641. * Determine absolute points of a SVG path. The coordinates are stored
  2642. * sequentially in the attribute points (x-coordinates at even indices,
  2643. * y-coordinates at odd indices).
  2644. *
  2645. * @constructor
  2646. */
  2647. ORYX.Core.SVG.PointsPathHandler = Clazz.extend({
  2648. construct: function() {
  2649. arguments.callee.$.construct.apply(this, arguments);
  2650. this.points = [];
  2651. this._lastAbsX = undefined;
  2652. this._lastAbsY = undefined;
  2653. },
  2654. /**
  2655. * addPoints
  2656. *
  2657. * @param {Array} points Array of absolutePoints
  2658. */
  2659. addPoints: function(points) {
  2660. if(points instanceof Array) {
  2661. var x, y;
  2662. for(var i = 0; i < points.length; i++) {
  2663. x = parseFloat(points[i]);
  2664. i++;
  2665. y = parseFloat(points[i]);
  2666. this.points.push(x);
  2667. this.points.push(y);
  2668. //this.points.push({x:x, y:y});
  2669. this._lastAbsX = x;
  2670. this._lastAbsY = y;
  2671. }
  2672. } else {
  2673. //TODO error
  2674. }
  2675. },
  2676. /**
  2677. * arcAbs - A
  2678. *
  2679. * @param {Number} rx
  2680. * @param {Number} ry
  2681. * @param {Number} xAxisRotation
  2682. * @param {Boolean} largeArcFlag
  2683. * @param {Boolean} sweepFlag
  2684. * @param {Number} x
  2685. * @param {Number} y
  2686. */
  2687. arcAbs: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2688. this.addPoints([x, y]);
  2689. },
  2690. /**
  2691. * arcRel - a
  2692. *
  2693. * @param {Number} rx
  2694. * @param {Number} ry
  2695. * @param {Number} xAxisRotation
  2696. * @param {Boolean} largeArcFlag
  2697. * @param {Boolean} sweepFlag
  2698. * @param {Number} x
  2699. * @param {Number} y
  2700. */
  2701. arcRel: function(rx, ry, xAxisRotation, largeArcFlag, sweepFlag, x, y) {
  2702. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2703. },
  2704. /**
  2705. * curvetoCubicAbs - C
  2706. *
  2707. * @param {Number} x1
  2708. * @param {Number} y1
  2709. * @param {Number} x2
  2710. * @param {Number} y2
  2711. * @param {Number} x
  2712. * @param {Number} y
  2713. */
  2714. curvetoCubicAbs: function(x1, y1, x2, y2, x, y) {
  2715. this.addPoints([x, y]);
  2716. },
  2717. /**
  2718. * curvetoCubicRel - c
  2719. *
  2720. * @param {Number} x1
  2721. * @param {Number} y1
  2722. * @param {Number} x2
  2723. * @param {Number} y2
  2724. * @param {Number} x
  2725. * @param {Number} y
  2726. */
  2727. curvetoCubicRel: function(x1, y1, x2, y2, x, y) {
  2728. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2729. },
  2730. /**
  2731. * linetoHorizontalAbs - H
  2732. *
  2733. * @param {Number} x
  2734. */
  2735. linetoHorizontalAbs: function(x) {
  2736. this.addPoints([x, this._lastAbsY]);
  2737. },
  2738. /**
  2739. * linetoHorizontalRel - h
  2740. *
  2741. * @param {Number} x
  2742. */
  2743. linetoHorizontalRel: function(x) {
  2744. this.addPoints([this._lastAbsX + x, this._lastAbsY]);
  2745. },
  2746. /**
  2747. * linetoAbs - L
  2748. *
  2749. * @param {Number} x
  2750. * @param {Number} y
  2751. */
  2752. linetoAbs: function(x, y) {
  2753. this.addPoints([x, y]);
  2754. },
  2755. /**
  2756. * linetoRel - l
  2757. *
  2758. * @param {Number} x
  2759. * @param {Number} y
  2760. */
  2761. linetoRel: function(x, y) {
  2762. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2763. },
  2764. /**
  2765. * movetoAbs - M
  2766. *
  2767. * @param {Number} x
  2768. * @param {Number} y
  2769. */
  2770. movetoAbs: function(x, y) {
  2771. this.addPoints([x, y]);
  2772. },
  2773. /**
  2774. * movetoRel - m
  2775. *
  2776. * @param {Number} x
  2777. * @param {Number} y
  2778. */
  2779. movetoRel: function(x, y) {
  2780. if(this._lastAbsX && this._lastAbsY) {
  2781. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2782. } else {
  2783. this.addPoints([x, y]);
  2784. }
  2785. },
  2786. /**
  2787. * curvetoQuadraticAbs - Q
  2788. *
  2789. * @param {Number} x1
  2790. * @param {Number} y1
  2791. * @param {Number} x
  2792. * @param {Number} y
  2793. */
  2794. curvetoQuadraticAbs: function(x1, y1, x, y) {
  2795. this.addPoints([x, y]);
  2796. },
  2797. /**
  2798. * curvetoQuadraticRel - q
  2799. *
  2800. * @param {Number} x1
  2801. * @param {Number} y1
  2802. * @param {Number} x
  2803. * @param {Number} y
  2804. */
  2805. curvetoQuadraticRel: function(x1, y1, x, y) {
  2806. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2807. },
  2808. /**
  2809. * curvetoCubicSmoothAbs - S
  2810. *
  2811. * @param {Number} x2
  2812. * @param {Number} y2
  2813. * @param {Number} x
  2814. * @param {Number} y
  2815. */
  2816. curvetoCubicSmoothAbs: function(x2, y2, x, y) {
  2817. this.addPoints([x, y]);
  2818. },
  2819. /**
  2820. * curvetoCubicSmoothRel - s
  2821. *
  2822. * @param {Number} x2
  2823. * @param {Number} y2
  2824. * @param {Number} x
  2825. * @param {Number} y
  2826. */
  2827. curvetoCubicSmoothRel: function(x2, y2, x, y) {
  2828. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2829. },
  2830. /**
  2831. * curvetoQuadraticSmoothAbs - T
  2832. *
  2833. * @param {Number} x
  2834. * @param {Number} y
  2835. */
  2836. curvetoQuadraticSmoothAbs: function(x, y) {
  2837. this.addPoints([x, y]);
  2838. },
  2839. /**
  2840. * curvetoQuadraticSmoothRel - t
  2841. *
  2842. * @param {Number} x
  2843. * @param {Number} y
  2844. */
  2845. curvetoQuadraticSmoothRel: function(x, y) {
  2846. this.addPoints([this._lastAbsX + x, this._lastAbsY + y]);
  2847. },
  2848. /**
  2849. * linetoVerticalAbs - V
  2850. *
  2851. * @param {Number} y
  2852. */
  2853. linetoVerticalAbs: function(y) {
  2854. this.addPoints([this._lastAbsX, y]);
  2855. },
  2856. /**
  2857. * linetoVerticalRel - v
  2858. *
  2859. * @param {Number} y
  2860. */
  2861. linetoVerticalRel: function(y) {
  2862. this.addPoints([this._lastAbsX, this._lastAbsY + y]);
  2863. },
  2864. /**
  2865. * closePath - z or Z
  2866. */
  2867. closePath: function() {
  2868. return;// do nothing
  2869. }
  2870. });/**
  2871. * Copyright (c) 2006
  2872. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  2873. *
  2874. * Permission is hereby granted, free of charge, to any person obtaining a
  2875. * copy of this software and associated documentation files (the "Software"),
  2876. * to deal in the Software without restriction, including without limitation
  2877. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  2878. * and/or sell copies of the Software, and to permit persons to whom the
  2879. * Software is furnished to do so, subject to the following conditions:
  2880. *
  2881. * The above copyright notice and this permission notice shall be included in
  2882. * all copies or substantial portions of the Software.
  2883. *
  2884. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  2885. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  2886. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  2887. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  2888. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  2889. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  2890. * DEALINGS IN THE SOFTWARE.
  2891. **/
  2892. /**
  2893. *
  2894. * Config variables
  2895. */
  2896. NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
  2897. NAMESPACE_SVG = "http://www.w3.org/2000/svg/";
  2898. /**
  2899. * @classDescription This class wraps the manipulation of a SVG marker.
  2900. * @namespace ORYX.Core.SVG
  2901. * uses Inheritance (Clazz)
  2902. * uses Prototype 1.5.0
  2903. *
  2904. */
  2905. /**
  2906. * Init package
  2907. */
  2908. if(!ORYX) {var ORYX = {};}
  2909. if(!ORYX.Core) {ORYX.Core = {};}
  2910. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  2911. ORYX.Core.SVG.SVGMarker = Clazz.extend({
  2912. /**
  2913. * Constructor
  2914. * @param markerElement {SVGMarkerElement}
  2915. */
  2916. construct: function(markerElement) {
  2917. arguments.callee.$.construct.apply(this, arguments);
  2918. this.id = undefined;
  2919. this.element = markerElement;
  2920. this.refX = undefined;
  2921. this.refY = undefined;
  2922. this.markerWidth = undefined;
  2923. this.markerHeight = undefined;
  2924. this.oldRefX = undefined;
  2925. this.oldRefY = undefined;
  2926. this.oldMarkerWidth = undefined;
  2927. this.oldMarkerHeight = undefined;
  2928. this.optional = false;
  2929. this.enabled = true;
  2930. this.minimumLength = undefined;
  2931. this.resize = false;
  2932. this.svgShapes = [];
  2933. this._init(); //initialisation of all the properties declared above.
  2934. },
  2935. /**
  2936. * Initializes the values that are defined in the constructor.
  2937. */
  2938. _init: function() {
  2939. //check if this.element is a SVGMarkerElement
  2940. if(!( this.element == "[object SVGMarkerElement]")) {
  2941. throw "SVGMarker: Argument is not an instance of SVGMarkerElement.";
  2942. }
  2943. this.id = this.element.getAttributeNS(null, "id");
  2944. //init svg marker attributes
  2945. var refXValue = this.element.getAttributeNS(null, "refX");
  2946. if(refXValue) {
  2947. this.refX = parseFloat(refXValue);
  2948. } else {
  2949. this.refX = 0;
  2950. }
  2951. var refYValue = this.element.getAttributeNS(null, "refY");
  2952. if(refYValue) {
  2953. this.refY = parseFloat(refYValue);
  2954. } else {
  2955. this.refY = 0;
  2956. }
  2957. var markerWidthValue = this.element.getAttributeNS(null, "markerWidth");
  2958. if(markerWidthValue) {
  2959. this.markerWidth = parseFloat(markerWidthValue);
  2960. } else {
  2961. this.markerWidth = 3;
  2962. }
  2963. var markerHeightValue = this.element.getAttributeNS(null, "markerHeight");
  2964. if(markerHeightValue) {
  2965. this.markerHeight = parseFloat(markerHeightValue);
  2966. } else {
  2967. this.markerHeight = 3;
  2968. }
  2969. this.oldRefX = this.refX;
  2970. this.oldRefY = this.refY;
  2971. this.oldMarkerWidth = this.markerWidth;
  2972. this.oldMarkerHeight = this.markerHeight;
  2973. //init oryx attributes
  2974. var optionalAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "optional");
  2975. if(optionalAttr) {
  2976. optionalAttr = optionalAttr.strip();
  2977. this.optional = (optionalAttr.toLowerCase() === "yes");
  2978. } else {
  2979. this.optional = false;
  2980. }
  2981. var enabledAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "enabled");
  2982. if(enabledAttr) {
  2983. enabledAttr = enabledAttr.strip();
  2984. this.enabled = !(enabledAttr.toLowerCase() === "no");
  2985. } else {
  2986. this.enabled = true;
  2987. }
  2988. var minLengthAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "minimumLength");
  2989. if(minLengthAttr) {
  2990. this.minimumLength = parseFloat(minLengthAttr);
  2991. }
  2992. var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize");
  2993. if(resizeAttr) {
  2994. resizeAttr = resizeAttr.strip();
  2995. this.resize = (resizeAttr.toLowerCase() === "yes");
  2996. } else {
  2997. this.resize = false;
  2998. }
  2999. //init SVGShape objects
  3000. //this.svgShapes = this._getSVGShapes(this.element);
  3001. },
  3002. /**
  3003. *
  3004. */
  3005. _getSVGShapes: function(svgElement) {
  3006. if(svgElement.hasChildNodes) {
  3007. var svgShapes = [];
  3008. var me = this;
  3009. $A(svgElement.childNodes).each(function(svgChild) {
  3010. try {
  3011. var svgShape = new ORYX.Core.SVG.SVGShape(svgChild);
  3012. svgShapes.push(svgShape);
  3013. } catch (e) {
  3014. svgShapes = svgShapes.concat(me._getSVGShapes(svgChild));
  3015. }
  3016. });
  3017. return svgShapes;
  3018. }
  3019. },
  3020. /**
  3021. * Writes the changed values into the SVG marker.
  3022. */
  3023. update: function() {
  3024. //TODO mache marker resizebar!!! aber erst wenn der rest der connectingshape funzt!
  3025. // //update marker attributes
  3026. // if(this.refX != this.oldRefX) {
  3027. // this.element.setAttributeNS(null, "refX", this.refX);
  3028. // }
  3029. // if(this.refY != this.oldRefY) {
  3030. // this.element.setAttributeNS(null, "refY", this.refY);
  3031. // }
  3032. // if(this.markerWidth != this.oldMarkerWidth) {
  3033. // this.element.setAttributeNS(null, "markerWidth", this.markerWidth);
  3034. // }
  3035. // if(this.markerHeight != this.oldMarkerHeight) {
  3036. // this.element.setAttributeNS(null, "markerHeight", this.markerHeight);
  3037. // }
  3038. //
  3039. // //update SVGShape objects
  3040. // var widthDelta = this.markerWidth / this.oldMarkerWidth;
  3041. // var heightDelta = this.markerHeight / this.oldMarkerHeight;
  3042. // if(widthDelta != 1 && heightDelta != 1) {
  3043. // this.svgShapes.each(function(svgShape) {
  3044. //
  3045. // });
  3046. // }
  3047. //update old values to prepare the next update
  3048. this.oldRefX = this.refX;
  3049. this.oldRefY = this.refY;
  3050. this.oldMarkerWidth = this.markerWidth;
  3051. this.oldMarkerHeight = this.markerHeight;
  3052. },
  3053. toString: function() { return (this.element) ? "SVGMarker " + this.element.id : "SVGMarker " + this.element;}
  3054. });/**
  3055. * Copyright (c) 2006
  3056. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  3057. *
  3058. * Permission is hereby granted, free of charge, to any person obtaining a
  3059. * copy of this software and associated documentation files (the "Software"),
  3060. * to deal in the Software without restriction, including without limitation
  3061. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  3062. * and/or sell copies of the Software, and to permit persons to whom the
  3063. * Software is furnished to do so, subject to the following conditions:
  3064. *
  3065. * The above copyright notice and this permission notice shall be included in
  3066. * all copies or substantial portions of the Software.
  3067. *
  3068. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  3069. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  3070. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  3071. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  3072. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  3073. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  3074. * DEALINGS IN THE SOFTWARE.
  3075. **/
  3076. /**
  3077. *
  3078. * Config variables
  3079. */
  3080. NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
  3081. NAMESPACE_SVG = "http://www.w3.org/2000/svg/";
  3082. /**
  3083. * @classDescription This class wraps the manipulation of a SVG basic shape or a path.
  3084. * @namespace ORYX.Core.SVG
  3085. * uses Inheritance (Clazz)
  3086. * uses Prototype 1.5.0
  3087. * uses PathParser by Kevin Lindsey (http://kevlindev.com/)
  3088. * uses MinMaxPathHandler
  3089. * uses EditPathHandler
  3090. *
  3091. */
  3092. //init package
  3093. if(!ORYX) {var ORYX = {};}
  3094. if(!ORYX.Core) {ORYX.Core = {};}
  3095. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  3096. ORYX.Core.SVG.SVGShape = Clazz.extend({
  3097. /**
  3098. * Constructor
  3099. * @param svgElem {SVGElement} An SVGElement that is a basic shape or a path.
  3100. */
  3101. construct: function(svgElem) {
  3102. arguments.callee.$.construct.apply(this, arguments);
  3103. this.type;
  3104. this.element = svgElem;
  3105. this.x = undefined;
  3106. this.y = undefined;
  3107. this.width = undefined;
  3108. this.height = undefined;
  3109. this.oldX = undefined;
  3110. this.oldY = undefined;
  3111. this.oldWidth = undefined;
  3112. this.oldHeight = undefined;
  3113. this.radiusX = undefined;
  3114. this.radiusY = undefined;
  3115. this.isHorizontallyResizable = false;
  3116. this.isVerticallyResizable = false;
  3117. //this.anchors = [];
  3118. this.anchorLeft = false;
  3119. this.anchorRight = false;
  3120. this.anchorTop = false;
  3121. this.anchorBottom = false;
  3122. //attributes of path elements of edge objects
  3123. this.allowDockers = true;
  3124. this.resizeMarkerMid = false;
  3125. this.editPathParser;
  3126. this.editPathHandler;
  3127. this.init(); //initialisation of all the properties declared above.
  3128. },
  3129. /**
  3130. * Initializes the values that are defined in the constructor.
  3131. */
  3132. init: function() {
  3133. /**initialize position and size*/
  3134. if(ORYX.Editor.checkClassType(this.element, SVGRectElement) || ORYX.Editor.checkClassType(this.element, SVGImageElement)) {
  3135. this.type = "Rect";
  3136. var xAttr = this.element.getAttributeNS(null, "x");
  3137. if(xAttr) {
  3138. this.oldX = parseFloat(xAttr);
  3139. } else {
  3140. throw "Missing attribute in element " + this.element;
  3141. }
  3142. var yAttr = this.element.getAttributeNS(null, "y");
  3143. if(yAttr) {
  3144. this.oldY = parseFloat(yAttr);
  3145. } else {
  3146. throw "Missing attribute in element " + this.element;
  3147. }
  3148. var widthAttr = this.element.getAttributeNS(null, "width");
  3149. if(widthAttr) {
  3150. this.oldWidth = parseFloat(widthAttr);
  3151. } else {
  3152. throw "Missing attribute in element " + this.element;
  3153. }
  3154. var heightAttr = this.element.getAttributeNS(null, "height");
  3155. if(heightAttr) {
  3156. this.oldHeight = parseFloat(heightAttr);
  3157. } else {
  3158. throw "Missing attribute in element " + this.element;
  3159. }
  3160. } else if(ORYX.Editor.checkClassType(this.element, SVGCircleElement)) {
  3161. this.type = "Circle";
  3162. var cx = undefined;
  3163. var cy = undefined;
  3164. //var r = undefined;
  3165. var cxAttr = this.element.getAttributeNS(null, "cx");
  3166. if(cxAttr) {
  3167. cx = parseFloat(cxAttr);
  3168. } else {
  3169. throw "Missing attribute in element " + this.element;
  3170. }
  3171. var cyAttr = this.element.getAttributeNS(null, "cy");
  3172. if(cyAttr) {
  3173. cy = parseFloat(cyAttr);
  3174. } else {
  3175. throw "Missing attribute in element " + this.element;
  3176. }
  3177. var rAttr = this.element.getAttributeNS(null, "r");
  3178. if(rAttr) {
  3179. //r = parseFloat(rAttr);
  3180. this.radiusX = parseFloat(rAttr);
  3181. } else {
  3182. throw "Missing attribute in element " + this.element;
  3183. }
  3184. this.oldX = cx - this.radiusX;
  3185. this.oldY = cy - this.radiusX;
  3186. this.oldWidth = 2*this.radiusX;
  3187. this.oldHeight = 2*this.radiusX;
  3188. } else if(ORYX.Editor.checkClassType(this.element, SVGEllipseElement)) {
  3189. this.type = "Ellipse";
  3190. var cx = undefined;
  3191. var cy = undefined;
  3192. //var rx = undefined;
  3193. //var ry = undefined;
  3194. var cxAttr = this.element.getAttributeNS(null, "cx");
  3195. if(cxAttr) {
  3196. cx = parseFloat(cxAttr);
  3197. } else {
  3198. throw "Missing attribute in element " + this.element;
  3199. }
  3200. var cyAttr = this.element.getAttributeNS(null, "cy");
  3201. if(cyAttr) {
  3202. cy = parseFloat(cyAttr);
  3203. } else {
  3204. throw "Missing attribute in element " + this.element;
  3205. }
  3206. var rxAttr = this.element.getAttributeNS(null, "rx");
  3207. if(rxAttr) {
  3208. this.radiusX = parseFloat(rxAttr);
  3209. } else {
  3210. throw "Missing attribute in element " + this.element;
  3211. }
  3212. var ryAttr = this.element.getAttributeNS(null, "ry");
  3213. if(ryAttr) {
  3214. this.radiusY = parseFloat(ryAttr);
  3215. } else {
  3216. throw "Missing attribute in element " + this.element;
  3217. }
  3218. this.oldX = cx - this.radiusX;
  3219. this.oldY = cy - this.radiusY;
  3220. this.oldWidth = 2*this.radiusX;
  3221. this.oldHeight = 2*this.radiusY;
  3222. } else if(ORYX.Editor.checkClassType(this.element, SVGLineElement)) {
  3223. this.type = "Line";
  3224. var x1 = undefined;
  3225. var y1 = undefined;
  3226. var x2 = undefined;
  3227. var y2 = undefined;
  3228. var x1Attr = this.element.getAttributeNS(null, "x1");
  3229. if(x1Attr) {
  3230. x1 = parseFloat(x1Attr);
  3231. } else {
  3232. throw "Missing attribute in element " + this.element;
  3233. }
  3234. var y1Attr = this.element.getAttributeNS(null, "y1");
  3235. if(y1Attr) {
  3236. y1 = parseFloat(y1Attr);
  3237. } else {
  3238. throw "Missing attribute in element " + this.element;
  3239. }
  3240. var x2Attr = this.element.getAttributeNS(null, "x2");
  3241. if(x2Attr) {
  3242. x2 = parseFloat(x2Attr);
  3243. } else {
  3244. throw "Missing attribute in element " + this.element;
  3245. }
  3246. var y2Attr = this.element.getAttributeNS(null, "y2");
  3247. if(y2Attr) {
  3248. y2 = parseFloat(y2Attr);
  3249. } else {
  3250. throw "Missing attribute in element " + this.element;
  3251. }
  3252. this.oldX = Math.min(x1,x2);
  3253. this.oldY = Math.min(y1,y2);
  3254. this.oldWidth = Math.abs(x1-x2);
  3255. this.oldHeight = Math.abs(y1-y2);
  3256. } else if(ORYX.Editor.checkClassType(this.element, SVGPolylineElement) || ORYX.Editor.checkClassType(this.element, SVGPolygonElement)) {
  3257. this.type = "Polyline";
  3258. var pointsArray = [];
  3259. if (this.element.points&&this.element.points.numberOfItems){
  3260. for(var i=0, size=this.element.points.numberOfItems; i<size; i++){
  3261. pointsArray.push(this.element.points.getItem(i).x)
  3262. pointsArray.push(this.element.points.getItem(i).y)
  3263. }
  3264. } else {
  3265. var points = this.element.getAttributeNS(null, "points");
  3266. if(points) {
  3267. points = points.replace(/,/g , " ");
  3268. pointsArray = points.split(" ");
  3269. pointsArray = pointsArray.without("");
  3270. } else {
  3271. throw "Missing attribute in element " + this.element;
  3272. }
  3273. }
  3274. if(pointsArray && pointsArray.length && pointsArray.length > 1) {
  3275. var minX = parseFloat(pointsArray[0]);
  3276. var minY = parseFloat(pointsArray[1]);
  3277. var maxX = parseFloat(pointsArray[0]);
  3278. var maxY = parseFloat(pointsArray[1]);
  3279. for(var i = 0; i < pointsArray.length; i++) {
  3280. minX = Math.min(minX, parseFloat(pointsArray[i]));
  3281. maxX = Math.max(maxX, parseFloat(pointsArray[i]));
  3282. i++;
  3283. minY = Math.min(minY, parseFloat(pointsArray[i]));
  3284. maxY = Math.max(maxY, parseFloat(pointsArray[i]));
  3285. }
  3286. this.oldX = minX;
  3287. this.oldY = minY;
  3288. this.oldWidth = maxX-minX;
  3289. this.oldHeight = maxY-minY;
  3290. } else {
  3291. throw "Missing attribute in element " + this.element;
  3292. }
  3293. } else if(ORYX.Editor.checkClassType(this.element, SVGPathElement)) {
  3294. this.type = "Path";
  3295. this.editPathParser = new PathParser();
  3296. this.editPathHandler = new ORYX.Core.SVG.EditPathHandler();
  3297. this.editPathParser.setHandler(this.editPathHandler);
  3298. var parser = new PathParser();
  3299. var handler = new ORYX.Core.SVG.MinMaxPathHandler();
  3300. parser.setHandler(handler);
  3301. parser.parsePath(this.element);
  3302. this.oldX = handler.minX;
  3303. this.oldY = handler.minY;
  3304. this.oldWidth = handler.maxX - handler.minX;
  3305. this.oldHeight = handler.maxY - handler.minY;
  3306. delete parser;
  3307. delete handler;
  3308. } else {
  3309. throw "Element is not a shape.";
  3310. }
  3311. /** initialize attributes of oryx namespace */
  3312. //resize
  3313. var resizeAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resize");
  3314. if(resizeAttr) {
  3315. resizeAttr = resizeAttr.toLowerCase();
  3316. if(resizeAttr.match(/horizontal/)) {
  3317. this.isHorizontallyResizable = true;
  3318. } else {
  3319. this.isHorizontallyResizable = false;
  3320. }
  3321. if(resizeAttr.match(/vertical/)) {
  3322. this.isVerticallyResizable = true;
  3323. } else {
  3324. this.isVerticallyResizable = false;
  3325. }
  3326. } else {
  3327. this.isHorizontallyResizable = false;
  3328. this.isVerticallyResizable = false;
  3329. }
  3330. //anchors
  3331. var anchorAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "anchors");
  3332. if(anchorAttr) {
  3333. anchorAttr = anchorAttr.replace("/,/g", " ");
  3334. var anchors = anchorAttr.split(" ").without("");
  3335. for(var i = 0; i < anchors.length; i++) {
  3336. switch(anchors[i].toLowerCase()) {
  3337. case "left":
  3338. this.anchorLeft = true;
  3339. break;
  3340. case "right":
  3341. this.anchorRight = true;
  3342. break;
  3343. case "top":
  3344. this.anchorTop = true;
  3345. break;
  3346. case "bottom":
  3347. this.anchorBottom = true;
  3348. break;
  3349. }
  3350. }
  3351. }
  3352. //allowDockers and resizeMarkerMid
  3353. if(ORYX.Editor.checkClassType(this.element, SVGPathElement)) {
  3354. var allowDockersAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "allowDockers");
  3355. if(allowDockersAttr) {
  3356. if(allowDockersAttr.toLowerCase() === "no") {
  3357. this.allowDockers = false;
  3358. } else {
  3359. this.allowDockers = true;
  3360. }
  3361. }
  3362. var resizeMarkerMidAttr = this.element.getAttributeNS(NAMESPACE_ORYX, "resizeMarker-mid");
  3363. if(resizeMarkerMidAttr) {
  3364. if(resizeMarkerMidAttr.toLowerCase() === "yes") {
  3365. this.resizeMarkerMid = true;
  3366. } else {
  3367. this.resizeMarkerMid = false;
  3368. }
  3369. }
  3370. }
  3371. this.x = this.oldX;
  3372. this.y = this.oldY;
  3373. this.width = this.oldWidth;
  3374. this.height = this.oldHeight;
  3375. },
  3376. /**
  3377. * Writes the changed values into the SVG element.
  3378. */
  3379. update: function() {
  3380. if(this.x !== this.oldX || this.y !== this.oldY || this.width !== this.oldWidth || this.height !== this.oldHeight) {
  3381. switch(this.type) {
  3382. case "Rect":
  3383. if(this.x !== this.oldX) this.element.setAttributeNS(null, "x", this.x);
  3384. if(this.y !== this.oldY) this.element.setAttributeNS(null, "y", this.y);
  3385. if(this.width !== this.oldWidth) this.element.setAttributeNS(null, "width", this.width);
  3386. if(this.height !== this.oldHeight) this.element.setAttributeNS(null, "height", this.height);
  3387. break;
  3388. case "Circle":
  3389. //calculate the radius
  3390. //var r;
  3391. // if(this.width/this.oldWidth <= this.height/this.oldHeight) {
  3392. // this.radiusX = ((this.width > this.height) ? this.width : this.height)/2.0;
  3393. // } else {
  3394. this.radiusX = ((this.width < this.height) ? this.width : this.height)/2.0;
  3395. //}
  3396. this.element.setAttributeNS(null, "cx", this.x + this.width/2.0);
  3397. this.element.setAttributeNS(null, "cy", this.y + this.height/2.0);
  3398. this.element.setAttributeNS(null, "r", this.radiusX);
  3399. break;
  3400. case "Ellipse":
  3401. this.radiusX = this.width/2;
  3402. this.radiusY = this.height/2;
  3403. this.element.setAttributeNS(null, "cx", this.x + this.radiusX);
  3404. this.element.setAttributeNS(null, "cy", this.y + this.radiusY);
  3405. this.element.setAttributeNS(null, "rx", this.radiusX);
  3406. this.element.setAttributeNS(null, "ry", this.radiusY);
  3407. break;
  3408. case "Line":
  3409. if(this.x !== this.oldX)
  3410. this.element.setAttributeNS(null, "x1", this.x);
  3411. if(this.y !== this.oldY)
  3412. this.element.setAttributeNS(null, "y1", this.y);
  3413. if(this.x !== this.oldX || this.width !== this.oldWidth)
  3414. this.element.setAttributeNS(null, "x2", this.x + this.width);
  3415. if(this.y !== this.oldY || this.height !== this.oldHeight)
  3416. this.element.setAttributeNS(null, "y2", this.y + this.height);
  3417. break;
  3418. case "Polyline":
  3419. var points = this.element.getAttributeNS(null, "points");
  3420. if(points) {
  3421. points = points.replace(/,/g, " ").split(" ").without("");
  3422. if(points && points.length && points.length > 1) {
  3423. //TODO what if oldWidth == 0?
  3424. var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth;
  3425. var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight;
  3426. var updatedPoints = "";
  3427. for(var i = 0; i < points.length; i++) {
  3428. var x = (parseFloat(points[i])-this.oldX)*widthDelta + this.x;
  3429. i++;
  3430. var y = (parseFloat(points[i])-this.oldY)*heightDelta + this.y;
  3431. updatedPoints += x + " " + y + " ";
  3432. }
  3433. this.element.setAttributeNS(null, "points", updatedPoints);
  3434. } else {
  3435. //TODO error
  3436. }
  3437. } else {
  3438. //TODO error
  3439. }
  3440. break;
  3441. case "Path":
  3442. //calculate scaling delta
  3443. //TODO what if oldWidth == 0?
  3444. var widthDelta = (this.oldWidth === 0) ? 0 : this.width / this.oldWidth;
  3445. var heightDelta = (this.oldHeight === 0) ? 0 : this.height / this.oldHeight;
  3446. //use path parser to edit each point of the path
  3447. this.editPathHandler.init(this.x, this.y, this.oldX, this.oldY, widthDelta, heightDelta);
  3448. this.editPathParser.parsePath(this.element);
  3449. //change d attribute of path
  3450. this.element.setAttributeNS(null, "d", this.editPathHandler.d);
  3451. break;
  3452. }
  3453. this.oldX = this.x;
  3454. this.oldY = this.y;
  3455. this.oldWidth = this.width;
  3456. this.oldHeight = this.height;
  3457. }
  3458. // Remove cached variables
  3459. delete this.visible;
  3460. delete this.handler;
  3461. },
  3462. isPointIncluded: function(pointX, pointY) {
  3463. // Check if there are the right arguments and if the node is visible
  3464. if(!pointX || !pointY || !this.isVisible()) {
  3465. return false;
  3466. }
  3467. switch(this.type) {
  3468. case "Rect":
  3469. return (pointX >= this.x && pointX <= this.x + this.width &&
  3470. pointY >= this.y && pointY <= this.y+this.height);
  3471. break;
  3472. case "Circle":
  3473. //calculate the radius
  3474. // var r;
  3475. // if(this.width/this.oldWidth <= this.height/this.oldHeight) {
  3476. // r = ((this.width > this.height) ? this.width : this.height)/2.0;
  3477. // } else {
  3478. // r = ((this.width < this.height) ? this.width : this.height)/2.0;
  3479. // }
  3480. return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.width/2.0, this.y + this.height/2.0, this.radiusX, this.radiusX);
  3481. break;
  3482. case "Ellipse":
  3483. return ORYX.Core.Math.isPointInEllipse(pointX, pointY, this.x + this.radiusX, this.y + this.radiusY, this.radiusX, this.radiusY);
  3484. break;
  3485. case "Line":
  3486. return ORYX.Core.Math.isPointInLine(pointX, pointY, this.x, this.y, this.x + this.width, this.y + this.height);
  3487. break;
  3488. case "Polyline":
  3489. var points = this.element.getAttributeNS(null, "points");
  3490. if(points) {
  3491. points = points.replace(/,/g , " ").split(" ").without("");
  3492. points = points.collect(function(n) {
  3493. return parseFloat(n);
  3494. });
  3495. return ORYX.Core.Math.isPointInPolygone(pointX, pointY, points);
  3496. } else {
  3497. return false;
  3498. }
  3499. break;
  3500. case "Path":
  3501. // Cache Path handler
  3502. if (!this.handler) {
  3503. var parser = new PathParser();
  3504. this.handler = new ORYX.Core.SVG.PointsPathHandler();
  3505. parser.setHandler(this.handler);
  3506. parser.parsePath(this.element);
  3507. }
  3508. return ORYX.Core.Math.isPointInPolygone(pointX, pointY, this.handler.points);
  3509. break;
  3510. default:
  3511. return false;
  3512. }
  3513. },
  3514. /**
  3515. * Returns true if the element is visible
  3516. * @param {SVGElement} elem
  3517. * @return boolean
  3518. */
  3519. isVisible: function(elem) {
  3520. if (this.visible !== undefined){
  3521. return this.visible;
  3522. }
  3523. if (!elem) {
  3524. elem = this.element;
  3525. }
  3526. var hasOwnerSVG = false;
  3527. try {
  3528. hasOwnerSVG = !!elem.ownerSVGElement;
  3529. } catch(e){}
  3530. // Is SVG context
  3531. if ( hasOwnerSVG ) {
  3532. // IF G-Element
  3533. if (ORYX.Editor.checkClassType(elem, SVGGElement)) {
  3534. if (elem.className && elem.className.baseVal == "me") {
  3535. this.visible = true;
  3536. return this.visible;
  3537. }
  3538. }
  3539. // Check if fill or stroke is set
  3540. var fill = elem.getAttributeNS(null, "fill");
  3541. var stroke = elem.getAttributeNS(null, "stroke");
  3542. if (fill && fill == "none" && stroke && stroke == "none") {
  3543. this.visible = false;
  3544. } else {
  3545. // Check if displayed
  3546. var attr = elem.getAttributeNS(null, "display");
  3547. if(!attr)
  3548. this.visible = this.isVisible(elem.parentNode);
  3549. else if (attr == "none")
  3550. this.visible = false;
  3551. else
  3552. this.visible = true;
  3553. }
  3554. } else {
  3555. this.visible = true;
  3556. }
  3557. return this.visible;
  3558. },
  3559. toString: function() { return (this.element) ? "SVGShape " + this.element.id : "SVGShape " + this.element;}
  3560. });/**
  3561. * Copyright (c) 2006
  3562. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  3563. *
  3564. * Permission is hereby granted, free of charge, to any person obtaining a
  3565. * copy of this software and associated documentation files (the "Software"),
  3566. * to deal in the Software without restriction, including without limitation
  3567. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  3568. * and/or sell copies of the Software, and to permit persons to whom the
  3569. * Software is furnished to do so, subject to the following conditions:
  3570. *
  3571. * The above copyright notice and this permission notice shall be included in
  3572. * all copies or substantial portions of the Software.
  3573. *
  3574. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  3575. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  3576. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  3577. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  3578. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  3579. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  3580. * DEALINGS IN THE SOFTWARE.
  3581. **/
  3582. /**
  3583. * Init namespaces
  3584. */
  3585. if(!ORYX) {var ORYX = {};}
  3586. if(!ORYX.Core) {ORYX.Core = {};}
  3587. if(!ORYX.Core.SVG) {ORYX.Core.SVG = {};}
  3588. /**
  3589. * @classDescription Class for adding text to a shape.
  3590. *
  3591. */
  3592. ORYX.Core.SVG.Label = Clazz.extend({
  3593. _characterSets:[
  3594. "%W",
  3595. "@",
  3596. "m",
  3597. "wDGMOQÖ#+=<>~^",
  3598. "ABCHKNRSUVXZÜÄ&",
  3599. "bdghnopquxöüETY1234567890ß_§${}*´`µ€",
  3600. "aeksvyzäFLP?°²³",
  3601. "c-",
  3602. "rtJ\"/()[]:;!|\\",
  3603. "fjI., ",
  3604. "'",
  3605. "il"
  3606. ],
  3607. _characterSetValues:[15,14,13,11,10,9,8,7,6,5,4,3],
  3608. /**
  3609. * Constructor
  3610. * @param options {Object} :
  3611. * textElement
  3612. *
  3613. */
  3614. construct: function(options) {
  3615. arguments.callee.$.construct.apply(this, arguments);
  3616. if(!options.textElement) {
  3617. throw "Label: No parameter textElement."
  3618. } else if (!ORYX.Editor.checkClassType( options.textElement, SVGTextElement ) ) {
  3619. throw "Label: Parameter textElement is not an SVGTextElement."
  3620. }
  3621. this.invisibleRenderPoint = -5000;
  3622. this.node = options.textElement;
  3623. this.node.setAttributeNS(null, 'stroke-width', '0pt');
  3624. this.node.setAttributeNS(null, 'letter-spacing', '-0.01px');
  3625. this.shapeId = options.shapeId;
  3626. this.id;
  3627. this.fitToElemId;
  3628. this.edgePosition;
  3629. this.x;
  3630. this.y;
  3631. this.oldX;
  3632. this.oldY;
  3633. this.isVisible = true;
  3634. this._text;
  3635. this._verticalAlign;
  3636. this._horizontalAlign;
  3637. this._rotate;
  3638. this._rotationPoint;
  3639. //this.anchors = [];
  3640. this.anchorLeft;
  3641. this.anchorRight;
  3642. this.anchorTop;
  3643. this.anchorBottom;
  3644. this._isChanged = true;
  3645. //if the text element already has an id, don't change it.
  3646. var _id = this.node.getAttributeNS(null, 'id');
  3647. if(_id) {
  3648. this.id = _id;
  3649. }
  3650. //initialization
  3651. //set referenced element the text is fit to
  3652. this.fitToElemId = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'fittoelem');
  3653. if(this.fitToElemId)
  3654. this.fitToElemId = this.shapeId + this.fitToElemId;
  3655. //set alignment
  3656. var alignValues = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align');
  3657. if(alignValues) {
  3658. alignValues = alignValues.replace(/,/g, " ");
  3659. alignValues = alignValues.split(" ");
  3660. alignValues = alignValues.without("");
  3661. alignValues.each((function(alignValue) {
  3662. switch (alignValue) {
  3663. case 'top':
  3664. case 'middle':
  3665. case 'bottom':
  3666. if(!this._verticalAlign){this._originVerticalAlign = this._verticalAlign = alignValue;}
  3667. break;
  3668. case 'left':
  3669. case 'center':
  3670. case 'right':
  3671. if(!this._horizontalAlign){this._originHorizontalAlign = this._horizontalAlign = alignValue;}
  3672. break;
  3673. }
  3674. }).bind(this));
  3675. }
  3676. //set edge position (only in case the label belongs to an edge)
  3677. this.edgePosition = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'edgePosition');
  3678. if(this.edgePosition) {
  3679. this.originEdgePosition = this.edgePosition = this.edgePosition.toLowerCase();
  3680. }
  3681. //get offset top
  3682. this.offsetTop = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetTop') || ORYX.CONFIG.OFFSET_EDGE_LABEL_TOP;
  3683. if(this.offsetTop) {
  3684. this.offsetTop = parseInt(this.offsetTop);
  3685. }
  3686. //get offset top
  3687. this.offsetBottom = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'offsetBottom') || ORYX.CONFIG.OFFSET_EDGE_LABEL_BOTTOM;
  3688. if(this.offsetBottom) {
  3689. this.offsetBottom = parseInt(this.offsetBottom);
  3690. }
  3691. //set rotation
  3692. var rotateValue = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'rotate');
  3693. if(rotateValue) {
  3694. try {
  3695. this._rotate = parseFloat(rotateValue);
  3696. } catch (e) {
  3697. this._rotate = 0;
  3698. }
  3699. } else {
  3700. this._rotate = 0;
  3701. }
  3702. //anchors
  3703. var anchorAttr = this.node.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors");
  3704. if(anchorAttr) {
  3705. anchorAttr = anchorAttr.replace("/,/g", " ");
  3706. var anchors = anchorAttr.split(" ").without("");
  3707. for(var i = 0; i < anchors.length; i++) {
  3708. switch(anchors[i].toLowerCase()) {
  3709. case "left":
  3710. this.originAnchorLeft = this.anchorLeft = true;
  3711. break;
  3712. case "right":
  3713. this.originAnchorRight = this.anchorRight = true;
  3714. break;
  3715. case "top":
  3716. this.originAnchorTop = this.anchorTop = true;
  3717. break;
  3718. case "bottom":
  3719. this.originAnchorBottom = this.anchorBottom = true;
  3720. break;
  3721. }
  3722. }
  3723. }
  3724. //if no alignment defined, set default alignment
  3725. if(!this._verticalAlign) { this._verticalAlign = 'bottom'; }
  3726. if(!this._horizontalAlign) { this._horizontalAlign = 'left'; }
  3727. var xValue = this.node.getAttributeNS(null, 'x');
  3728. if(xValue) {
  3729. this.oldX = this.x = parseFloat(xValue);
  3730. } else {
  3731. //TODO error
  3732. }
  3733. var yValue = this.node.getAttributeNS(null, 'y');
  3734. if(yValue) {
  3735. this.oldY = this.y = parseFloat(yValue);
  3736. } else {
  3737. //TODO error
  3738. }
  3739. //set initial text
  3740. this.text(this.node.textContent);
  3741. },
  3742. /**
  3743. * Reset the anchor position to the original value
  3744. * which was specified in the stencil set
  3745. *
  3746. */
  3747. resetAnchorPosition: function(){
  3748. this.anchorLeft = this.originAnchorLeft || false;
  3749. this.anchorRight = this.originAnchorRight || false;
  3750. this.anchorTop = this.originAnchorTop || false;
  3751. this.anchorBottom = this.originAnchorBottom || false;
  3752. },
  3753. isOriginAnchorLeft: function(){ return this.originAnchorLeft || false; },
  3754. isOriginAnchorRight: function(){ return this.originAnchorRight || false; },
  3755. isOriginAnchorTop: function(){ return this.originAnchorTop || false; },
  3756. isOriginAnchorBottom: function(){ return this.originAnchorBottom || false; },
  3757. isAnchorLeft: function(){ return this.anchorLeft || false; },
  3758. isAnchorRight: function(){ return this.anchorRight || false; },
  3759. isAnchorTop: function(){ return this.anchorTop || false; },
  3760. isAnchorBottom: function(){ return this.anchorBottom || false; },
  3761. /**
  3762. * Returns the x coordinate
  3763. * @return {number}
  3764. */
  3765. getX: function(){
  3766. try {
  3767. var x = this.node.x.baseVal.getItem(0).value;
  3768. switch(this.horizontalAlign()){
  3769. case "left": return x;
  3770. case "center": return x - (this.getWidth()/2);
  3771. case "right": return x - this.getWidth();
  3772. }
  3773. return this.node.getBBox().x;
  3774. } catch(e){
  3775. return this.x;
  3776. }
  3777. },
  3778. setX: function(x){
  3779. if (this.position)
  3780. this.position.x = x;
  3781. else
  3782. this.setOriginX(x);
  3783. },
  3784. /**
  3785. * Returns the y coordinate
  3786. * @return {number}
  3787. */
  3788. getY: function(){
  3789. try {
  3790. return this.node.getBBox().y;
  3791. } catch(e){
  3792. return this.y;
  3793. }
  3794. },
  3795. setY: function(y){
  3796. if (this.position)
  3797. this.position.y = y;
  3798. else
  3799. this.setOriginY(y);
  3800. },
  3801. setOriginX: function(x){
  3802. this.x = x;
  3803. },
  3804. setOriginY: function(y){
  3805. this.y = y;
  3806. },
  3807. /**
  3808. * Returns the width of the label
  3809. * @return {number}
  3810. */
  3811. getWidth: function(){
  3812. try {
  3813. try {
  3814. var width, cn = this.node.childNodes;
  3815. if (cn.length == 0 || !Ext.isGecko) {
  3816. width = this.node.getBBox().width;
  3817. } else {
  3818. for (var i = 0, size = cn.length; i < size; ++i) {
  3819. var w = cn[i].getComputedTextLength();
  3820. if ("undefined" == typeof width || width < w) {
  3821. width = w;
  3822. }
  3823. }
  3824. }
  3825. return width+(width%2==0?0:1);
  3826. } catch (ee) {
  3827. return this.node.getBBox().width;
  3828. }
  3829. } catch(e){
  3830. return 0;
  3831. }
  3832. },
  3833. getOriginUpperLeft: function(){
  3834. var x = this.x, y = this.y;
  3835. switch (this._horizontalAlign){
  3836. case 'center' :
  3837. x -= this.getWidth()/2;
  3838. break;
  3839. case 'right' :
  3840. x -= this.getWidth();
  3841. break;
  3842. }
  3843. switch (this._verticalAlign){
  3844. case 'middle' :
  3845. y -= this.getHeight()/2;
  3846. break;
  3847. case 'bottom' :
  3848. y -= this.getHeight();
  3849. break;
  3850. }
  3851. return {x:x, y:y};
  3852. },
  3853. /**
  3854. * Returns the height of the label
  3855. * @return {number}
  3856. */
  3857. getHeight: function(){
  3858. try {
  3859. return this.node.getBBox().height;
  3860. } catch(e){
  3861. return 0;
  3862. }
  3863. },
  3864. /**
  3865. * Returns the relative center position of the label
  3866. * to its parent shape.
  3867. * @return {Object}
  3868. */
  3869. getCenter: function(){
  3870. var up = {x: this.getX(), y: this.getY()};
  3871. up.x += this.getWidth()/2;
  3872. up.y += this.getHeight()/2;
  3873. return up;
  3874. },
  3875. /**
  3876. * Sets the position of a label relative to the parent.
  3877. * @param {Object} position
  3878. */
  3879. setPosition: function(position){
  3880. if (!position || position.x === undefined || position.y === undefined) {
  3881. delete this.position;
  3882. } else {
  3883. this.position = position;
  3884. }
  3885. if (this.position){
  3886. delete this._referencePoint;
  3887. delete this.edgePosition;
  3888. }
  3889. this._isChanged = true;
  3890. this.update();
  3891. },
  3892. /**
  3893. * Return the position
  3894. */
  3895. getPosition: function(){
  3896. return this.position;
  3897. },
  3898. setReferencePoint: function(ref){
  3899. if (ref) {
  3900. this._referencePoint = ref;
  3901. } else {
  3902. delete this._referencePoint;
  3903. }
  3904. if (this._referencePoint){
  3905. delete this.position;
  3906. }
  3907. },
  3908. getReferencePoint: function(){
  3909. return this._referencePoint || undefined;
  3910. },
  3911. changed: function() {
  3912. this._isChanged = true;
  3913. },
  3914. /**
  3915. * Register a callback which will be called if the label
  3916. * was rendered.
  3917. * @param {Object} fn
  3918. */
  3919. registerOnChange: function(fn){
  3920. if (!this.changeCallbacks){
  3921. this.changeCallbacks = [];
  3922. }
  3923. if (fn instanceof Function && !this.changeCallbacks.include(fn)){
  3924. this.changeCallbacks.push(fn);
  3925. }
  3926. },
  3927. /**
  3928. * Unregister the callback for changes.
  3929. * @param {Object} fn
  3930. */
  3931. unregisterOnChange: function(fn){
  3932. if (this.changeCallbacks && fn instanceof Function && this.changeCallbacks.include(fn)){
  3933. this.changeCallbacks = this.changeCallbacks.without(fn);
  3934. }
  3935. },
  3936. /**
  3937. * Returns TRUE if the labe is currently in
  3938. * the update mechanism.
  3939. * @return {Boolean}
  3940. */
  3941. isUpdating: function(){
  3942. return !!this._isUpdating;
  3943. },
  3944. getOriginEdgePosition: function(){
  3945. return this.originEdgePosition;
  3946. },
  3947. /**
  3948. * Returns the edgeposition.
  3949. *
  3950. * @return {String} "starttop", "startmiddle", "startbottom",
  3951. * "midtop", "midbottom", "endtop", "endbottom" or null
  3952. */
  3953. getEdgePosition: function(){
  3954. return this.edgePosition || null;
  3955. },
  3956. /**
  3957. * Set the edge position, must be one of the valid
  3958. * edge positions (see getEdgePosition).
  3959. * Removes the reference point and the absolute position as well.
  3960. *
  3961. * @param {Object} position
  3962. */
  3963. setEdgePosition: function(position){
  3964. if (["starttop", "startmiddle", "startbottom",
  3965. "midtop", "midbottom", "endtop", "endbottom"].include(position)){
  3966. this.edgePosition = position;
  3967. delete this.position;
  3968. delete this._referencePoint;
  3969. } else {
  3970. delete this.edgePosition;
  3971. }
  3972. },
  3973. /**
  3974. * Update the SVG text element.
  3975. */
  3976. update: function(force) {
  3977. var x = this.x, y = this.y;
  3978. if (this.position){
  3979. x = this.position.x;
  3980. y = this.position.y;
  3981. }
  3982. x = Math.floor(x); y = Math.floor(y);
  3983. if(this._isChanged || x !== this.oldX || y !== this.oldY || force === true) {
  3984. if (this.isVisible) {
  3985. this._isChanged = false;
  3986. this._isUpdating = true;
  3987. this.node.setAttributeNS(null, 'x', x);
  3988. this.node.setAttributeNS(null, 'y', y);
  3989. this.node.removeAttributeNS(null, "fill-opacity");
  3990. //this.node.setAttributeNS(null, 'font-size', this._fontSize);
  3991. //this.node.setAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'align', this._horizontalAlign + " " + this._verticalAlign);
  3992. this.oldX = x;
  3993. this.oldY = y;
  3994. //set rotation
  3995. if (!this.position && !this.getReferencePoint()) {
  3996. if (this._rotate !== undefined) {
  3997. if (this._rotationPoint)
  3998. this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(this._rotationPoint.x) + ' ' + Math.floor(this._rotationPoint.y) + ')');
  3999. else
  4000. this.node.setAttributeNS(null, 'transform', 'rotate(' + this._rotate + ' ' + Math.floor(x) + ' ' + Math.floor(y) + ')');
  4001. }
  4002. } else {
  4003. this.node.removeAttributeNS(null, 'transform');
  4004. }
  4005. var textLines = this._text.split("\n");
  4006. while (textLines.last() == "")
  4007. textLines.pop();
  4008. if (this.node.ownerDocument) {
  4009. // Only reset the tspans if the text
  4010. // has changed or has to be wrapped
  4011. if (this.fitToElemId || this._textHasChanged){
  4012. this.node.textContent = ""; // Remove content
  4013. textLines.each((function(textLine, index){
  4014. var tspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan');
  4015. tspan.textContent = textLine.trim();
  4016. if (this.fitToElemId) {
  4017. tspan.setAttributeNS(null, 'x', this.invisibleRenderPoint);
  4018. tspan.setAttributeNS(null, 'y', this.invisibleRenderPoint);
  4019. }
  4020. /*
  4021. * Chrome's getBBox() method fails, if a text node contains an empty tspan element.
  4022. * So, we add a whitespace to such a tspan element.
  4023. */
  4024. if(tspan.textContent === "") {
  4025. tspan.textContent = " ";
  4026. }
  4027. //append tspan to text node
  4028. this.node.appendChild(tspan);
  4029. }).bind(this));
  4030. delete this._textHasChanged;
  4031. delete this.indices;
  4032. }
  4033. //Work around for Mozilla bug 293581
  4034. if (this.isVisible && this.fitToElemId) {
  4035. this.node.setAttributeNS(null, 'visibility', 'hidden');
  4036. }
  4037. if (this.fitToElemId) {
  4038. window.setTimeout(this._checkFittingToReferencedElem.bind(this), 0);
  4039. } else {
  4040. window.setTimeout(this._positionText.bind(this), 0);
  4041. //this._positionText();
  4042. }
  4043. }
  4044. } else {
  4045. this.node.textContent = "";
  4046. //this.node.setAttributeNS(null, "fill-opacity", "0.2");
  4047. }
  4048. }
  4049. },
  4050. _checkFittingToReferencedElem: function() {
  4051. try {
  4052. var tspans = $A(this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan'));
  4053. //only do this in firefox 3. all other browsers do not support word wrapping!!!!!
  4054. //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1)>=3) {
  4055. var newtspans = [];
  4056. var refNode = this.node.ownerDocument.getElementById(this.fitToElemId);
  4057. if (refNode) {
  4058. var refbb = refNode.getBBox();
  4059. var fontSize = this.getFontSize();
  4060. for (var j = 0; j < tspans.length; j++) {
  4061. var tspan = tspans[j];
  4062. var textLength = this._getRenderedTextLength(tspan, undefined, undefined, fontSize);
  4063. var refBoxLength = (this._rotate != 0
  4064. && this._rotate % 180 != 0
  4065. && this._rotate % 90 == 0 ?
  4066. refbb.height : refbb.width);
  4067. if (textLength > refBoxLength) {
  4068. var startIndex = 0;
  4069. var lastSeperatorIndex = 0;
  4070. var numOfChars = this.getTrimmedTextLength(tspan.textContent);
  4071. for (var i = 0; i < numOfChars; i++) {
  4072. var sslength = this._getRenderedTextLength(tspan, startIndex, i-startIndex, fontSize);
  4073. if (sslength > refBoxLength - 2) {
  4074. var newtspan = this.node.ownerDocument.createElementNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan');
  4075. if (lastSeperatorIndex <= startIndex) {
  4076. lastSeperatorIndex = (i == 0) ? i : i-1;
  4077. newtspan.textContent = tspan.textContent.slice(startIndex, lastSeperatorIndex).trim();
  4078. //lastSeperatorIndex = i;
  4079. }
  4080. else {
  4081. newtspan.textContent = tspan.textContent.slice(startIndex, ++lastSeperatorIndex).trim();
  4082. }
  4083. newtspan.setAttributeNS(null, 'x', this.invisibleRenderPoint);
  4084. newtspan.setAttributeNS(null, 'y', this.invisibleRenderPoint);
  4085. //insert tspan to text node
  4086. //this.node.insertBefore(newtspan, tspan);
  4087. newtspans.push(newtspan);
  4088. startIndex = lastSeperatorIndex;
  4089. }
  4090. else {
  4091. var curChar = tspan.textContent.charAt(i);
  4092. if (curChar == ' ' ||
  4093. curChar == '-' ||
  4094. curChar == "." ||
  4095. curChar == "," ||
  4096. curChar == ";" ||
  4097. curChar == ":") {
  4098. lastSeperatorIndex = i;
  4099. }
  4100. }
  4101. }
  4102. tspan.textContent = tspan.textContent.slice(startIndex).trim();
  4103. }
  4104. newtspans.push(tspan);
  4105. }
  4106. while (this.node.hasChildNodes())
  4107. this.node.removeChild(this.node.childNodes[0]);
  4108. while (newtspans.length > 0) {
  4109. this.node.appendChild(newtspans.shift());
  4110. }
  4111. }
  4112. //}
  4113. } catch (e) {
  4114. ORYX.Log.fatal("Error " + e);
  4115. }
  4116. window.setTimeout(this._positionText.bind(this), 0);
  4117. },
  4118. /**
  4119. * This is a work around method for Mozilla bug 293581.
  4120. * Before the method getComputedTextLength works, the text has to be rendered.
  4121. */
  4122. _positionText: function() {
  4123. try {
  4124. //var tspans = this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan');
  4125. var tspans = this.node.childNodes;
  4126. var fontSize = this.getFontSize(this.node);
  4127. var invalidTSpans = [];
  4128. var x = this.x, y = this.y;
  4129. if (this.position){
  4130. x = this.position.x;
  4131. y = this.position.y;
  4132. }
  4133. x = Math.floor(x); y = Math.floor(y);
  4134. var i = 0, indic = []; // Cache indices if the _positionText is called again, before update is called
  4135. var is =(this.indices || $R(0,tspans.length-1).toArray());
  4136. var length = is.length;
  4137. is.each((function(index){
  4138. if ("undefined" == typeof index){
  4139. return;
  4140. }
  4141. var tspan = tspans[i++];
  4142. if(tspan.textContent.trim() === "") {
  4143. invalidTSpans.push(tspan);
  4144. } else {
  4145. //set vertical position
  4146. var dy = 0;
  4147. switch (this._verticalAlign) {
  4148. case 'bottom':
  4149. dy = -(length - index - 1) * (fontSize);
  4150. break;
  4151. case 'middle':
  4152. dy = -(length / 2.0 - index - 1) * (fontSize);
  4153. dy -= ORYX.CONFIG.LABEL_LINE_DISTANCE / 2;
  4154. break;
  4155. case 'top':
  4156. dy = index * (fontSize);
  4157. dy += fontSize;
  4158. break;
  4159. }
  4160. tspan.setAttributeNS(null, 'dy', Math.floor(dy));
  4161. tspan.setAttributeNS(null, 'x', x);
  4162. tspan.setAttributeNS(null, 'y', y);
  4163. indic.push(index);
  4164. }
  4165. }).bind(this));
  4166. indic.length = tspans.length;
  4167. this.indices = this.indices || indic;
  4168. invalidTSpans.each(function(tspan) {
  4169. this.node.removeChild(tspan)
  4170. }.bind(this));
  4171. //set horizontal alignment
  4172. switch (this._horizontalAlign) {
  4173. case 'left':
  4174. this.node.setAttributeNS(null, 'text-anchor', 'start');
  4175. break;
  4176. case 'center':
  4177. this.node.setAttributeNS(null, 'text-anchor', 'middle');
  4178. break;
  4179. case 'right':
  4180. this.node.setAttributeNS(null, 'text-anchor', 'end');
  4181. break;
  4182. }
  4183. } catch(e) {
  4184. //console.log(e);
  4185. this._isChanged = true;
  4186. }
  4187. if(this.isVisible) {
  4188. this.node.removeAttributeNS(null, 'visibility');
  4189. }
  4190. // Finished
  4191. delete this._isUpdating;
  4192. // Raise change event
  4193. (this.changeCallbacks||[]).each(function(fn){
  4194. fn.apply(fn);
  4195. })
  4196. },
  4197. /**
  4198. * Returns the text length of the text content of an SVG tspan element.
  4199. * For all browsers but Firefox 3 the values are estimated.
  4200. * @param {TSpanSVGElement} tspan
  4201. * @param {int} startIndex Optional, for sub strings
  4202. * @param {int} endIndex Optional, for sub strings
  4203. */
  4204. _getRenderedTextLength: function(tspan, startIndex, endIndex, fontSize) {
  4205. //if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) {
  4206. if(startIndex === undefined) {
  4207. //test string: abcdefghijklmnopqrstuvwxyzöäü,.-#+ 1234567890ßABCDEFGHIJKLMNOPQRSTUVWXYZ;:_'*ÜÄÖ!"§$%&/()=?[]{}|<>'~´`\^°µ@€²³
  4208. // for(var i = 0; i < tspan.textContent.length; i++) {
  4209. // console.log(tspan.textContent.charAt(i), tspan.getSubStringLength(i,1), this._estimateCharacterWidth(tspan.textContent.charAt(i))*(fontSize/14.0));
  4210. // }
  4211. return tspan.getComputedTextLength();
  4212. } else {
  4213. return tspan.getSubStringLength(startIndex, endIndex);
  4214. }
  4215. /*} else {
  4216. if(startIndex === undefined) {
  4217. return this._estimateTextWidth(tspan.textContent, fontSize);
  4218. } else {
  4219. return this._estimateTextWidth(tspan.textContent.substr(startIndex, endIndex).trim(), fontSize);
  4220. }
  4221. }*/
  4222. },
  4223. /**
  4224. * Estimates the text width for a string.
  4225. * Used for word wrapping in all browser but FF3.
  4226. * @param {Object} text
  4227. */
  4228. _estimateTextWidth: function(text, fontSize) {
  4229. var sum = 0.0;
  4230. for(var i = 0; i < text.length; i++) {
  4231. sum += this._estimateCharacterWidth(text.charAt(i));
  4232. }
  4233. return sum*(fontSize/14.0);
  4234. },
  4235. /**
  4236. * Estimates the width of a single character for font size 14.
  4237. * Used for word wrapping in all browser but FF3.
  4238. * @param {Object} character
  4239. */
  4240. _estimateCharacterWidth: function(character) {
  4241. for(var i = 0; i < this._characterSets.length; i++) {
  4242. if(this._characterSets[i].indexOf(character) >= 0) {
  4243. return this._characterSetValues[i];
  4244. }
  4245. }
  4246. return 9;
  4247. },
  4248. getReferencedElementWidth: function() {
  4249. var refNode = this.node.ownerDocument.getElementById(this.fitToElemId);
  4250. if(refNode) {
  4251. var refbb = refNode.getBBox();
  4252. if(refbb) {
  4253. return (this._rotate != 0
  4254. && this._rotate % 180 != 0
  4255. && this._rotate % 90 == 0 ?
  4256. refbb.height : refbb.width);
  4257. }
  4258. }
  4259. return undefined;
  4260. },
  4261. /**
  4262. * If no parameter is provided, this method returns the current text.
  4263. * @param text {String} Optional. Replaces the old text with this one.
  4264. */
  4265. text: function() {
  4266. switch (arguments.length) {
  4267. case 0:
  4268. return this._text
  4269. break;
  4270. case 1:
  4271. var oldText = this._text;
  4272. if(arguments[0]) {
  4273. this._text = arguments[0].toString();
  4274. } else {
  4275. this._text = "";
  4276. }
  4277. if(oldText !== this._text) {
  4278. this._isChanged = true;
  4279. this._textHasChanged = true;
  4280. }
  4281. break;
  4282. default:
  4283. //TODO error
  4284. break;
  4285. }
  4286. },
  4287. getOriginVerticalAlign: function(){
  4288. return this._originVerticalAlign;
  4289. },
  4290. verticalAlign: function() {
  4291. switch(arguments.length) {
  4292. case 0:
  4293. return this._verticalAlign;
  4294. case 1:
  4295. if(['top', 'middle', 'bottom'].member(arguments[0])) {
  4296. var oldValue = this._verticalAlign;
  4297. this._verticalAlign = arguments[0];
  4298. if(this._verticalAlign !== oldValue) {
  4299. this._isChanged = true;
  4300. }
  4301. }
  4302. break;
  4303. default:
  4304. //TODO error
  4305. break;
  4306. }
  4307. },
  4308. getOriginHorizontalAlign: function(){
  4309. return this._originHorizontalAlign;
  4310. },
  4311. horizontalAlign: function() {
  4312. switch(arguments.length) {
  4313. case 0:
  4314. return this._horizontalAlign;
  4315. case 1:
  4316. if(['left', 'center', 'right'].member(arguments[0])) {
  4317. var oldValue = this._horizontalAlign;
  4318. this._horizontalAlign = arguments[0];
  4319. if(this._horizontalAlign !== oldValue) {
  4320. this._isChanged = true;
  4321. }
  4322. }
  4323. break;
  4324. default:
  4325. //TODO error
  4326. break;
  4327. }
  4328. },
  4329. rotate: function() {
  4330. switch(arguments.length) {
  4331. case 0:
  4332. return this._rotate;
  4333. case 1:
  4334. if (this._rotate != arguments[0]) {
  4335. this._rotate = arguments[0];
  4336. this._rotationPoint = undefined;
  4337. this._isChanged = true;
  4338. }
  4339. case 2:
  4340. if(this._rotate != arguments[0] ||
  4341. !this._rotationPoint ||
  4342. this._rotationPoint.x != arguments[1].x ||
  4343. this._rotationPoint.y != arguments[1].y) {
  4344. this._rotate = arguments[0];
  4345. this._rotationPoint = arguments[1];
  4346. this._isChanged = true;
  4347. }
  4348. }
  4349. },
  4350. hide: function() {
  4351. if(this.isVisible) {
  4352. this.isVisible = false;
  4353. this._isChanged = true;
  4354. }
  4355. },
  4356. show: function() {
  4357. if(!this.isVisible) {
  4358. this.isVisible = true;
  4359. this._isChanged = true;
  4360. }
  4361. },
  4362. /**
  4363. * iterates parent nodes till it finds a SVG font-size
  4364. * attribute.
  4365. * @param {SVGElement} node
  4366. */
  4367. getInheritedFontSize: function(node) {
  4368. if(!node || !node.getAttributeNS)
  4369. return;
  4370. var attr = node.getAttributeNS(null, "font-size");
  4371. if(attr) {
  4372. return parseFloat(attr);
  4373. } else if(!ORYX.Editor.checkClassType(node, SVGSVGElement)) {
  4374. return this.getInheritedFontSize(node.parentNode);
  4375. }
  4376. },
  4377. getFontSize: function(node) {
  4378. var tspans = this.node.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan');
  4379. //trying to get an inherited font-size attribute
  4380. //NO CSS CONSIDERED!
  4381. var fontSize = this.getInheritedFontSize(this.node);
  4382. if (!fontSize) {
  4383. //because this only works in firefox 3, all other browser use the default line height
  4384. if (tspans[0] && /Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent) && new Number(RegExp.$1) >= 3) {
  4385. fontSize = tspans[0].getExtentOfChar(0).height;
  4386. }
  4387. else {
  4388. fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT;
  4389. }
  4390. //handling of unsupported method in webkit
  4391. if (fontSize <= 0) {
  4392. fontSize = ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT;
  4393. }
  4394. }
  4395. if(fontSize)
  4396. this.node.setAttribute("oryx:fontSize", fontSize);
  4397. return fontSize;
  4398. },
  4399. /**
  4400. * Get trimmed text length for use with
  4401. * getExtentOfChar and getSubStringLength.
  4402. * @param {String} text
  4403. */
  4404. getTrimmedTextLength: function(text) {
  4405. text = text.strip().gsub(' ', ' ');
  4406. var oldLength;
  4407. do {
  4408. oldLength = text.length;
  4409. text = text.gsub(' ', ' ');
  4410. } while (oldLength > text.length);
  4411. return text.length;
  4412. },
  4413. /**
  4414. * Returns the offset from
  4415. * edge to the label which is
  4416. * positioned under the edge
  4417. * @return {int}
  4418. */
  4419. getOffsetBottom: function(){
  4420. return this.offsetBottom;
  4421. },
  4422. /**
  4423. * Returns the offset from
  4424. * edge to the label which is
  4425. * positioned over the edge
  4426. * @return {int}
  4427. */
  4428. getOffsetTop: function(){
  4429. return this.offsetTop;
  4430. },
  4431. /**
  4432. *
  4433. * @param {Object} obj
  4434. */
  4435. deserialize: function(obj, shape){
  4436. if (obj && "undefined" != typeof obj.x && "undefined" != typeof obj.y){
  4437. this.setPosition({x:obj.x, y:obj.y});
  4438. if ("undefined" != typeof obj.distance){
  4439. var from = shape.dockers[obj.from];
  4440. var to = shape.dockers[obj.to];
  4441. if (from && to){
  4442. this.setReferencePoint({
  4443. dirty : true,
  4444. distance : obj.distance,
  4445. intersection : {x: obj.x, y: obj.y},
  4446. orientation : obj.orientation,
  4447. segment: {
  4448. from: from,
  4449. fromIndex: obj.from,
  4450. fromPosition: from.bounds.center(),
  4451. to: to,
  4452. toIndex: obj.to,
  4453. toPosition: to.bounds.center()
  4454. }
  4455. })
  4456. }
  4457. }
  4458. if (obj.left) this.anchorLeft = true;
  4459. if (obj.right) this.anchorRight = true;
  4460. if (obj.top) this.anchorTop = true;
  4461. if (obj.bottom) this.anchorBottom = true;
  4462. if (obj.valign) this.verticalAlign(obj.valign);
  4463. if (obj.align) this.horizontalAlign(obj.align);
  4464. } else if (obj && "undefined" != typeof obj.edge){
  4465. this.setEdgePosition(obj.edge);
  4466. }
  4467. },
  4468. /**
  4469. *
  4470. * @return {Object}
  4471. */
  4472. serialize: function(){
  4473. // On edge position
  4474. if (this.getEdgePosition()){
  4475. if (this.getOriginEdgePosition() !== this.getEdgePosition()){
  4476. return {edge: this.getEdgePosition()};
  4477. } else {
  4478. return null;
  4479. }
  4480. }
  4481. // On self defined position
  4482. if (this.position){
  4483. var pos = {x: this.position.x, y: this.position.y};
  4484. if (this.isAnchorLeft() && this.isAnchorLeft() !== this.isOriginAnchorLeft()){
  4485. pos.left = true;
  4486. }
  4487. if (this.isAnchorRight() && this.isAnchorRight() !== this.isOriginAnchorRight()){
  4488. pos.right = true;
  4489. }
  4490. if (this.isAnchorTop() && this.isAnchorTop() !== this.isOriginAnchorTop()){
  4491. pos.top = true;
  4492. }
  4493. if (this.isAnchorBottom() && this.isAnchorBottom() !== this.isOriginAnchorBottom()){
  4494. pos.bottom = true;
  4495. }
  4496. if (this.getOriginVerticalAlign() !== this.verticalAlign()){
  4497. pos.valign = this.verticalAlign();
  4498. }
  4499. if (this.getOriginHorizontalAlign() !== this.horizontalAlign()){
  4500. pos.align = this.horizontalAlign();
  4501. }
  4502. return pos;
  4503. }
  4504. // On reference point which is interesting for edges
  4505. if (this.getReferencePoint()){
  4506. var ref = this.getReferencePoint();
  4507. return {
  4508. distance : ref.distance,
  4509. x : ref.intersection.x,
  4510. y : ref.intersection.y,
  4511. from : ref.segment.fromIndex,
  4512. to : ref.segment.toIndex,
  4513. orientation : ref.orientation,
  4514. valign : this.verticalAlign(),
  4515. align : this.horizontalAlign()
  4516. }
  4517. }
  4518. return null;
  4519. },
  4520. toString: function() { return "Label " + this.id }
  4521. });/**
  4522. * Copyright (c) 2006
  4523. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  4524. *
  4525. * Permission is hereby granted, free of charge, to any person obtaining a
  4526. * copy of this software and associated documentation files (the "Software"),
  4527. * to deal in the Software without restriction, including without limitation
  4528. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  4529. * and/or sell copies of the Software, and to permit persons to whom the
  4530. * Software is furnished to do so, subject to the following conditions:
  4531. *
  4532. * The above copyright notice and this permission notice shall be included in
  4533. * all copies or substantial portions of the Software.
  4534. *
  4535. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  4536. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  4537. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  4538. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  4539. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  4540. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  4541. * DEALINGS IN THE SOFTWARE.
  4542. **/
  4543. /**
  4544. * Init namespaces
  4545. */
  4546. if(!ORYX) {var ORYX = {};}
  4547. if(!ORYX.Core) {ORYX.Core = {};}
  4548. if(!ORYX.Core.Math) {ORYX.Core.Math = {};}
  4549. /**
  4550. * Calculate the middle point between two given points
  4551. * @param {x:double, y:double} point1
  4552. * @param {x:double, y:double} point2
  4553. * @return the middle point
  4554. */
  4555. ORYX.Core.Math.midPoint = function(point1, point2) {
  4556. return {
  4557. x: (point1.x + point2.x) / 2.0,
  4558. y: (point1.y + point2.y) / 2.0
  4559. }
  4560. }
  4561. /**
  4562. * Returns a TRUE if the point is over a line (defined by
  4563. * point1 and point 2). In Addition a threshold can be set,
  4564. * which defines the weight of those line.
  4565. *
  4566. * @param {int} pointX - Point X
  4567. * @param {int} pointY - Point Y
  4568. * @param {int} lPoint1X - Line first Point X
  4569. * @param {int} lPoint1Y - Line first Point Y
  4570. * @param {int} lPoint2X - Line second Point X
  4571. * @param {int} lPoint2Y - Line second Point y
  4572. * @param {int} offset {optional} - maximal distance to line
  4573. * @class ORYX.Core.Math.prototype
  4574. */
  4575. ORYX.Core.Math.isPointInLine = function (pointX, pointY, lPoint1X, lPoint1Y, lPoint2X, lPoint2Y, offset) {
  4576. offset = offset ? Math.abs(offset) : 1;
  4577. // Check if the edge is vertical
  4578. if(Math.abs(lPoint1X-lPoint2X)<=offset && Math.abs(pointX-lPoint1X)<=offset && pointY-Math.max(lPoint1Y, lPoint2Y)<=offset && Math.min(lPoint1Y, lPoint2Y)-pointY<=offset) {
  4579. return true
  4580. }
  4581. // Check if the edge is horizontal
  4582. if(Math.abs(lPoint1Y-lPoint2Y)<=offset && Math.abs(pointY-lPoint1Y)<=offset && pointX-Math.max(lPoint1X, lPoint2X)<=offset && Math.min(lPoint1X, lPoint2X)-pointX<=offset) {
  4583. return true
  4584. }
  4585. if(pointX > Math.max(lPoint1X, lPoint2X) || pointX < Math.min(lPoint1X, lPoint2X)) {
  4586. return false
  4587. }
  4588. if(pointY > Math.max(lPoint1Y, lPoint2Y) || pointY < Math.min(lPoint1Y, lPoint2Y)) {
  4589. return false
  4590. }
  4591. var s = (lPoint1Y - lPoint2Y) / (lPoint1X - lPoint2X);
  4592. return Math.abs(pointY - ((s * pointX) + lPoint1Y - s * lPoint1X)) < offset
  4593. }
  4594. /**
  4595. * Get a boolean if the point is in the polygone
  4596. *
  4597. */
  4598. ORYX.Core.Math.isPointInEllipse = function (pointX, pointY, cx, cy, rx, ry) {
  4599. if(cx === undefined || cy === undefined || rx === undefined || ry === undefined) {
  4600. throw "ORYX.Core.Math.isPointInEllipse needs a ellipse with these properties: x, y, radiusX, radiusY"
  4601. }
  4602. var tx = (pointX - cx) / rx;
  4603. var ty = (pointY - cy) / ry;
  4604. return tx * tx + ty * ty < 1.0;
  4605. }
  4606. /**
  4607. * Get a boolean if the point is in the polygone
  4608. * @param {int} pointX
  4609. * @param {int} pointY
  4610. * @param {[int]} Cornerpoints of the Polygone (x,y,x,y,...)
  4611. */
  4612. ORYX.Core.Math.isPointInPolygone = function(pointX, pointY, polygone){
  4613. if (arguments.length < 3) {
  4614. throw "ORYX.Core.Math.isPointInPolygone needs two arguments"
  4615. }
  4616. var lastIndex = polygone.length-1;
  4617. if (polygone[0] !== polygone[lastIndex - 1] || polygone[1] !== polygone[lastIndex]) {
  4618. polygone.push(polygone[0]);
  4619. polygone.push(polygone[1]);
  4620. }
  4621. var crossings = 0;
  4622. var x1, y1, x2, y2, d;
  4623. for (var i = 0; i < polygone.length - 3; ) {
  4624. x1=polygone[i];
  4625. y1=polygone[++i];
  4626. x2=polygone[++i];
  4627. y2=polygone[i+1];
  4628. d=(pointY - y1) * (x2 - x1) - (pointX - x1) * (y2 - y1);
  4629. if ((y1 >= pointY) != (y2 >= pointY)) {
  4630. crossings += y2 - y1 >= 0 ? d >= 0 : d <= 0;
  4631. }
  4632. if (!d && Math.min(x1,x2) <= pointX && pointX <= Math.max(x1,x2)
  4633. && Math.min(y1,y2) <= pointY && pointY <= Math.max(y1,y2)) {
  4634. return true;
  4635. }
  4636. }
  4637. return (crossings%2)?true:false;
  4638. }
  4639. /**
  4640. * Calculates the distance between a point and a line. It is also testable, if
  4641. * the distance orthogonal to the line, matches the segment of the line.
  4642. *
  4643. * @param {float} lineP1
  4644. * The starting point of the line segment
  4645. * @param {float} lineP2
  4646. * The end point of the line segment
  4647. * @param {Point} point
  4648. * The point to calculate the distance to.
  4649. * @param {boolean} toSegmentOnly
  4650. * Flag to signal if only the segment of the line shell be evaluated.
  4651. */
  4652. ORYX.Core.Math.distancePointLinie = function(
  4653. lineP1,
  4654. lineP2,
  4655. point,
  4656. toSegmentOnly) {
  4657. var intersectionPoint =
  4658. ORYX.Core.Math.getPointOfIntersectionPointLine(lineP1,
  4659. lineP2,
  4660. point,
  4661. toSegmentOnly);
  4662. if(!intersectionPoint) {
  4663. return null;
  4664. }
  4665. return ORYX.Core.Math.getDistancePointToPoint(point, intersectionPoint);
  4666. };
  4667. /**
  4668. * Calculates the distance between two points.
  4669. *
  4670. * @param {point} point1
  4671. * @param {point} point2
  4672. */
  4673. ORYX.Core.Math.getDistancePointToPoint = function(point1, point2) {
  4674. return Math.sqrt(Math.pow(point1.x - point2.x, 2) + Math.pow(point1.y - point2.y, 2));
  4675. };
  4676. /**
  4677. * Calculates the relative distance of a point which is between two other points.
  4678. *
  4679. * @param {point} between1
  4680. * @param {point} between2
  4681. * @param {point} point
  4682. */
  4683. ORYX.Core.Math.getDistanceBetweenTwoPoints = function(between1, between2, point) {
  4684. return ORYX.Core.Math.getDistancePointToPoint(point, between1) /
  4685. ORYX.Core.Math.getDistancePointToPoint(between1, between2);
  4686. };
  4687. /**
  4688. * Returns true, if the point is of the left hand
  4689. * side of the regarding the line.
  4690. *
  4691. * @param {point} lineP1 Line first point
  4692. * @param {point} lineP2 Line second point
  4693. * @param {point} point
  4694. */
  4695. ORYX.Core.Math.pointIsLeftOfLine = function(lineP1, lineP2, point){
  4696. var vec1 = ORYX.Core.Math.getVector(lineP1, lineP2);
  4697. var vec2 = ORYX.Core.Math.getVector(lineP1, point);
  4698. // if the cross produkt is more than 0
  4699. return ((vec1.x*vec2.y) - (vec2.x*vec1.y)) > 0
  4700. };
  4701. /**
  4702. * Calculates the a point which is relatively between two other points.
  4703. *
  4704. * @param {point} point1
  4705. * @param {point} point2
  4706. * @param {number} relative Relative which is between 0 and 1
  4707. */
  4708. ORYX.Core.Math.getPointBetweenTwoPoints = function(point1, point2, relative) {
  4709. relative = Math.max(Math.min(relative || 0, 1), 0);
  4710. if (relative === 0){
  4711. return point1;
  4712. } else if (relative === 1){
  4713. return point2;
  4714. }
  4715. return {
  4716. x: point1.x + ((point2.x - point1.x) * relative),
  4717. y: point1.y + ((point2.y - point1.y) * relative)
  4718. }
  4719. };
  4720. /**
  4721. * Returns the vector of the both points
  4722. *
  4723. * @param {point} point1
  4724. * @param {point} point2
  4725. */
  4726. ORYX.Core.Math.getVector = function(point1, point2){
  4727. return {
  4728. x: point2.x - point1.x,
  4729. y: point2.y - point1.y
  4730. }
  4731. }
  4732. /**
  4733. * Returns the an identity vector of the given vector,
  4734. * which has the length ot one.
  4735. *
  4736. * @param {point} vector
  4737. * or
  4738. * @param {point} point1
  4739. * @param {point} point2
  4740. */
  4741. ORYX.Core.Math.getIdentityVector = function(vector){
  4742. if (arguments.length == 2){
  4743. vector = ORYX.Core.Math.getVector(arguments[0], arguments[1]);
  4744. }
  4745. var length = Math.sqrt((vector.x*vector.x)+(vector.y*vector.y))
  4746. return {
  4747. x: vector.x / (length || 1),
  4748. y: vector.y / (length || 1)
  4749. }
  4750. }
  4751. ORYX.Core.Math.getOrthogonalIdentityVector = function(point1, point2){
  4752. var vec = arguments.length == 1 ? point1 : ORYX.Core.Math.getIdentityVector(point1, point2);
  4753. return {
  4754. x: vec.y,
  4755. y: -vec.x
  4756. }
  4757. }
  4758. /**
  4759. * Returns the intersection point of a line and a point that defines a line
  4760. * orthogonal to the given line.
  4761. *
  4762. * @param {float} lineP1
  4763. * The starting point of the line segment
  4764. * @param {float} lineP2
  4765. * The end point of the line segment
  4766. * @param {Point} point
  4767. * The point to calculate the distance to.
  4768. * @param {boolean} onSegmentOnly
  4769. * Flag to signal if only the segment of the line shell be evaluated.
  4770. */
  4771. ORYX.Core.Math.getPointOfIntersectionPointLine = function(
  4772. lineP1,
  4773. lineP2,
  4774. point,
  4775. onSegmentOnly) {
  4776. /*
  4777. * [P3 - P1 - u(P2 - P1)] dot (P2 - P1) = 0
  4778. * u =((x3-x1)(x2-x1)+(y3-y1)(y2-y1))/(p2-p1)²
  4779. */
  4780. var denominator = Math.pow(lineP2.x - lineP1.x, 2)
  4781. + Math.pow(lineP2.y - lineP1.y, 2);
  4782. if(denominator == 0) {
  4783. return undefined;
  4784. }
  4785. var u = ((point.x - lineP1.x) * (lineP2.x - lineP1.x)
  4786. + (point.y - lineP1.y) * (lineP2.y - lineP1.y))
  4787. / denominator;
  4788. if(onSegmentOnly) {
  4789. if (!(0 <= u && u <= 1)) {
  4790. return undefined;
  4791. }
  4792. }
  4793. pointOfIntersection = new Object();
  4794. pointOfIntersection.x = lineP1.x + u * (lineP2.x - lineP1.x);
  4795. pointOfIntersection.y = lineP1.y + u * (lineP2.y - lineP1.y);
  4796. return pointOfIntersection;
  4797. };
  4798. /**
  4799. * Translated the point with the given matrix.
  4800. * @param {Point} point
  4801. * @param {Matrix} matrix
  4802. * @return {Object} Includes x, y
  4803. */
  4804. ORYX.Core.Math.getTranslatedPoint = function(point, matrix){
  4805. var x = matrix.a*point.x+matrix.c*point.y+matrix.e*1;
  4806. var y = matrix.b*point.x+matrix.d*point.y+matrix.f*1;
  4807. return {x:x, y:y}
  4808. }
  4809. /**
  4810. * Returns the inverse matrix of the given SVG transformation matrix
  4811. * @param {SVGTransformationMatrix} matrix
  4812. * @return {Matrix}
  4813. */
  4814. ORYX.Core.Math.getInverseMatrix = function(matrix){
  4815. var det = ORYX.Core.Math.getDeterminant(matrix), m = matrix;
  4816. // +- -+
  4817. // | a c e |
  4818. // | b d f |
  4819. // | 0 0 1 |
  4820. // +- -+
  4821. return {
  4822. a: det * ((m.d*1)-(m.f*0)),
  4823. b: det * ((m.f*0)-(m.b*1)),
  4824. c: det * ((m.e*0)-(m.c*1)),
  4825. d: det * ((m.a*1)-(m.e*0)),
  4826. e: det * ((m.c*m.f)-(m.e*m.d)),
  4827. f: det * ((m.e*m.b)-(m.a*m.f))
  4828. }
  4829. }
  4830. /**
  4831. * Returns the determinant of the svg transformation matrix
  4832. * @param {SVGTranformationMatrix} matrix
  4833. * @return {Number}
  4834. *
  4835. */
  4836. ORYX.Core.Math.getDeterminant = function(m){
  4837. // a11a22a33+a12a23a31+a13a21a32-a13a22a31-a12a21a33-a11a23a32
  4838. return (m.a*m.d*1)+(m.c*m.f*0)+(m.e*m.b*0)-(m.e*m.d*0)-(m.c*m.b*1)-(m.a*m.f*0);
  4839. }
  4840. /**
  4841. * Returns the bounding box of the given node. Translates the
  4842. * origin bounding box with the tranlation matrix.
  4843. * @param {SVGElement} node
  4844. * @return {Object} Includes x, y, width, height
  4845. */
  4846. ORYX.Core.Math.getTranslatedBoundingBox = function(node){
  4847. var matrix = node.getCTM();
  4848. var bb = node.getBBox();
  4849. var ul = ORYX.Core.Math.getTranslatedPoint({x:bb.x, y:bb.y}, matrix);
  4850. var ll = ORYX.Core.Math.getTranslatedPoint({x:bb.x, y:bb.y+bb.height}, matrix);
  4851. var ur = ORYX.Core.Math.getTranslatedPoint({x:bb.x+bb.width, y:bb.y}, matrix);
  4852. var lr = ORYX.Core.Math.getTranslatedPoint({x:bb.x+bb.width, y:bb.y+bb.height}, matrix);
  4853. var minPoint = {
  4854. x: Math.min(ul.x, ll.x, ur.x, lr.x),
  4855. y: Math.min(ul.y, ll.y, ur.y, lr.y)
  4856. }
  4857. var maxPoint = {
  4858. x: Math.max(ul.x, ll.x, ur.x, lr.x),
  4859. y: Math.max(ul.y, ll.y, ur.y, lr.y)
  4860. }
  4861. return {
  4862. x: minPoint.x,
  4863. y: minPoint.y,
  4864. width: maxPoint.x - minPoint.x,
  4865. height: maxPoint.y - minPoint.y
  4866. }
  4867. };
  4868. /**
  4869. * Returns the angle of the given line, which is representated by the two points
  4870. * @param {Point} p1
  4871. * @param {Point} p2
  4872. * @return {Number} 0 <= x <= 359.99999
  4873. */
  4874. ORYX.Core.Math.getAngle = function(p1, p2){
  4875. if(p1.x == p2.x && p1.y == p2.y)
  4876. return 0;
  4877. var angle = Math.asin(Math.sqrt(Math.pow(p1.y-p2.y, 2))
  4878. /(Math.sqrt(Math.pow(p2.x-p1.x, 2)+Math.pow(p1.y-p2.y, 2))))
  4879. *180/Math.PI;
  4880. if(p2.x >= p1.x && p2.y <= p1.y)
  4881. return angle;
  4882. else if(p2.x < p1.x && p2.y <= p1.y)
  4883. return 180 - angle;
  4884. else if(p2.x < p1.x && p2.y > p1.y)
  4885. return 180 + angle;
  4886. else
  4887. return 360 - angle;
  4888. };
  4889. /**
  4890. * Implementation of the cohen-sutherland algorithm
  4891. */
  4892. new function(){
  4893. var RIGHT = 2, TOP = 8, BOTTOM = 4, LEFT = 1;
  4894. function computeOutCode (x, y, xmin, ymin, xmax, ymax) {
  4895. var code = 0;
  4896. if (y > ymax)
  4897. code |= TOP;
  4898. else if (y < ymin)
  4899. code |= BOTTOM;
  4900. if (x > xmax)
  4901. code |= RIGHT;
  4902. else if (x < xmin)
  4903. code |= LEFT;
  4904. return code;
  4905. }
  4906. /**
  4907. * Returns TRUE if the rectangle is over the edge and has intersection points or includes it
  4908. * @param {Object} x1 Point A of the line
  4909. * @param {Object} y1
  4910. * @param {Object} x2 Point B of the line
  4911. * @param {Object} y2
  4912. * @param {Object} xmin Point A of the rectangle
  4913. * @param {Object} ymin
  4914. * @param {Object} xmax Point B of the rectangle
  4915. * @param {Object} ymax
  4916. */
  4917. ORYX.Core.Math.isRectOverLine = function(x1, y1, x2, y2, xmin, ymin, xmax, ymax){
  4918. return !!ORYX.Core.Math.clipLineOnRect.apply(ORYX.Core.Math, arguments);
  4919. }
  4920. /**
  4921. * Returns the clipped line on the given rectangle. If there is
  4922. * no intersection, it will return NULL.
  4923. *
  4924. * @param {Object} x1 Point A of the line
  4925. * @param {Object} y1
  4926. * @param {Object} x2 Point B of the line
  4927. * @param {Object} y2
  4928. * @param {Object} xmin Point A of the rectangle
  4929. * @param {Object} ymin
  4930. * @param {Object} xmax Point B of the rectangle
  4931. * @param {Object} ymax
  4932. */
  4933. ORYX.Core.Math.clipLineOnRect = function(x1, y1, x2, y2, xmin, ymin, xmax, ymax){
  4934. //Outcodes for P0, P1, and whatever point lies outside the clip rectangle
  4935. var outcode0, outcode1, outcodeOut, hhh = 0;
  4936. var accept = false, done = false;
  4937. //compute outcodes
  4938. outcode0 = computeOutCode(x1, y1, xmin, ymin, xmax, ymax);
  4939. outcode1 = computeOutCode(x2, y2, xmin, ymin, xmax, ymax);
  4940. do {
  4941. if ((outcode0 | outcode1) == 0 ){
  4942. accept = true;
  4943. done = true;
  4944. } else if ( (outcode0 & outcode1) > 0 ) {
  4945. done = true;
  4946. } else {
  4947. //failed both tests, so calculate the line segment to clip
  4948. //from an outside point to an intersection with clip edge
  4949. var x = 0, y = 0;
  4950. //At least one endpoint is outside the clip rectangle; pick it.
  4951. outcodeOut = outcode0 != 0 ? outcode0: outcode1;
  4952. //Now find the intersection point;
  4953. //use formulas y = y0 + slope * (x - x0), x = x0 + (1/slope)* (y - y0)
  4954. if ( (outcodeOut & TOP) > 0 ) {
  4955. x = x1 + (x2 - x1) * (ymax - y1)/(y2 - y1);
  4956. y = ymax;
  4957. } else if ((outcodeOut & BOTTOM) > 0 ) {
  4958. x = x1 + (x2 - x1) * (ymin - y1)/(y2 - y1);
  4959. y = ymin;
  4960. } else if ((outcodeOut & RIGHT)> 0) {
  4961. y = y1 + (y2 - y1) * (xmax - x1)/(x2 - x1);
  4962. x = xmax;
  4963. } else if ((outcodeOut & LEFT) > 0) {
  4964. y = y1 + (y2 - y1) * (xmin - x1)/(x2 - x1);
  4965. x = xmin;
  4966. }
  4967. //Now we move outside point to intersection point to clip
  4968. //and get ready for next pass.
  4969. if (outcodeOut == outcode0) {
  4970. x1 = x;
  4971. y1 = y;
  4972. outcode0 = computeOutCode (x1, y1, xmin, ymin, xmax, ymax);
  4973. } else {
  4974. x2 = x;
  4975. y2 = y;
  4976. outcode1 = computeOutCode (x2, y2, xmin, ymin, xmax, ymax);
  4977. }
  4978. }
  4979. hhh ++;
  4980. } while (done != true && hhh < 5000);
  4981. if(accept) {
  4982. return {a:{x:x1, y:y1}, b:{x:x2, y:y2}};
  4983. }
  4984. return null;
  4985. }
  4986. }();
  4987. /**
  4988. * Copyright (c) 2006
  4989. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  4990. *
  4991. * Permission is hereby granted, free of charge, to any person obtaining a
  4992. * copy of this software and associated documentation files (the "Software"),
  4993. * to deal in the Software without restriction, including without limitation
  4994. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  4995. * and/or sell copies of the Software, and to permit persons to whom the
  4996. * Software is furnished to do so, subject to the following conditions:
  4997. *
  4998. * The above copyright notice and this permission notice shall be included in
  4999. * all copies or substantial portions of the Software.
  5000. *
  5001. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5002. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5003. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5004. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5005. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5006. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  5007. * DEALINGS IN THE SOFTWARE.
  5008. **/
  5009. /**
  5010. * Init namespace
  5011. */
  5012. if(!ORYX) {var ORYX = {};}
  5013. if(!ORYX.Core) {ORYX.Core = {};}
  5014. if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};}
  5015. /**
  5016. * Class Stencil
  5017. * uses Prototpye 1.5.0
  5018. * uses Inheritance
  5019. *
  5020. * This class represents one stencil of a stencil set.
  5021. */
  5022. ORYX.Core.StencilSet.Stencil = {
  5023. /**
  5024. * Constructor
  5025. */
  5026. construct: function(jsonStencil, namespace, source, stencilSet, propertyPackages, defaultPosition) {
  5027. arguments.callee.$.construct.apply(this, arguments); // super();
  5028. // check arguments and set defaults.
  5029. if(!jsonStencil) throw "Stencilset seems corrupt.";
  5030. if(!namespace) throw "Stencil does not provide namespace.";
  5031. if(!source) throw "Stencil does not provide SVG source.";
  5032. if(!stencilSet) throw "Fatal internal error loading stencilset.";
  5033. //if(!propertyPackages) throw "Fatal internal error loading stencilset.";
  5034. this._source = source;
  5035. this._jsonStencil = jsonStencil;
  5036. this._stencilSet = stencilSet;
  5037. this._namespace = namespace;
  5038. this._propertyPackages = propertyPackages;
  5039. if(defaultPosition && !this._jsonStencil.position)
  5040. this._jsonStencil.position = defaultPosition;
  5041. this._view;
  5042. this._properties = new Hash();
  5043. // check stencil consistency and set defaults.
  5044. /*with(this._jsonStencil) {
  5045. if(!type) throw "Stencil does not provide type.";
  5046. if((type != "edge") && (type != "node"))
  5047. throw "Stencil type must be 'edge' or 'node'.";
  5048. if(!id || id == "") throw "Stencil does not provide valid id.";
  5049. if(!title || title == "")
  5050. throw "Stencil does not provide title";
  5051. if(!description) { description = ""; };
  5052. if(!groups) { groups = []; }
  5053. if(!roles) { roles = []; }
  5054. // add id of stencil to its roles
  5055. roles.push(id);
  5056. }*/
  5057. //init all JSON values
  5058. if(!this._jsonStencil.type || !(this._jsonStencil.type === "edge" || this._jsonStencil.type === "node")) {
  5059. throw "ORYX.Core.StencilSet.Stencil(construct): Type is not defined.";
  5060. }
  5061. if(!this._jsonStencil.id || this._jsonStencil.id === "") {
  5062. throw "ORYX.Core.StencilSet.Stencil(construct): Id is not defined.";
  5063. }
  5064. if(!this._jsonStencil.title || this._jsonStencil.title === "") {
  5065. throw "ORYX.Core.StencilSet.Stencil(construct): Title is not defined.";
  5066. }
  5067. if(!this._jsonStencil.description) { this._jsonStencil.description = ""; };
  5068. if(!this._jsonStencil.groups) { this._jsonStencil.groups = []; }
  5069. if(!this._jsonStencil.roles) { this._jsonStencil.roles = []; }
  5070. //add id of stencil to its roles
  5071. this._jsonStencil.roles.push(this._jsonStencil.id);
  5072. //prepend namespace to each role
  5073. this._jsonStencil.roles.each((function(role, index) {
  5074. this._jsonStencil.roles[index] = namespace + role;
  5075. }).bind(this));
  5076. //delete duplicate roles
  5077. this._jsonStencil.roles = this._jsonStencil.roles.uniq();
  5078. //make id unique by prepending namespace of stencil set
  5079. this._jsonStencil.id = namespace + this._jsonStencil.id;
  5080. this.postProcessProperties();
  5081. // init serialize callback
  5082. if(!this._jsonStencil.serialize) {
  5083. this._jsonStencil.serialize = {};
  5084. //this._jsonStencil.serialize = function(shape, data) { return data;};
  5085. }
  5086. // init deserialize callback
  5087. if(!this._jsonStencil.deserialize) {
  5088. this._jsonStencil.deserialize = {};
  5089. //this._jsonStencil.deserialize = function(shape, data) { return data;};
  5090. }
  5091. // init layout callback
  5092. if(!this._jsonStencil.layout) {
  5093. this._jsonStencil.layout = []
  5094. //this._jsonStencil.layout = function() {return true;}
  5095. }
  5096. //TODO does not work correctly, if the url does not exist
  5097. //How to guarantee that the view is loaded correctly before leaving the constructor???
  5098. var url = source + "view/" + jsonStencil.view;
  5099. // override content type when this is webkit.
  5100. /*
  5101. if(Prototype.Browser.WebKit) {
  5102. var req = new XMLHttpRequest;
  5103. req.open("GET", url, false);
  5104. req.overrideMimeType('text/xml');
  5105. req.send(null);
  5106. req.onload = (function() { _loadSVGOnSuccess(req.responseXML); }).bind(this);
  5107. // else just do it.
  5108. } else
  5109. */
  5110. if(this._jsonStencil.view.trim().match(/</)) {
  5111. var parser = new DOMParser();
  5112. var xml = parser.parseFromString( this._jsonStencil.view ,"text/xml");
  5113. //check if result is a SVG document
  5114. if( ORYX.Editor.checkClassType( xml.documentElement, SVGSVGElement )) {
  5115. this._view = xml.documentElement;
  5116. //updating link to images
  5117. var imageElems = this._view.getElementsByTagNameNS("http://www.w3.org/2000/svg", "image");
  5118. $A(imageElems).each((function(imageElem) {
  5119. var link = imageElem.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href");
  5120. if(link && link.value.indexOf("://") == -1) {
  5121. link.textContent = this._source + "view/" + link.value;
  5122. }
  5123. }).bind(this));
  5124. } else {
  5125. throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document."
  5126. }
  5127. } else {
  5128. new Ajax.Request(
  5129. url, {
  5130. asynchronous:false, method:'get',
  5131. onSuccess:this._loadSVGOnSuccess.bind(this),
  5132. onFailure:this._loadSVGOnFailure.bind(this)
  5133. });
  5134. }
  5135. },
  5136. postProcessProperties: function() {
  5137. // add image path to icon
  5138. if(this._jsonStencil.icon && this._jsonStencil.icon.indexOf("://") === -1) {
  5139. this._jsonStencil.icon = this._source + "icons/" + this._jsonStencil.icon;
  5140. } else {
  5141. this._jsonStencil.icon = "";
  5142. }
  5143. // init property packages
  5144. if(this._jsonStencil.propertyPackages && this._jsonStencil.propertyPackages instanceof Array) {
  5145. this._jsonStencil.propertyPackages.each((function(ppId) {
  5146. var pp = this._propertyPackages[ppId];
  5147. if(pp) {
  5148. pp.each((function(prop){
  5149. var oProp = new ORYX.Core.StencilSet.Property(prop, this._namespace, this);
  5150. this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;
  5151. }).bind(this));
  5152. }
  5153. }).bind(this));
  5154. }
  5155. // init properties
  5156. if(this._jsonStencil.properties && this._jsonStencil.properties instanceof Array) {
  5157. this._jsonStencil.properties.each((function(prop) {
  5158. var oProp = new ORYX.Core.StencilSet.Property(prop, this._namespace, this);
  5159. this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;
  5160. }).bind(this));
  5161. }
  5162. },
  5163. /**
  5164. * @param {ORYX.Core.StencilSet.Stencil} stencil
  5165. * @return {Boolean} True, if stencil has the same namespace and type.
  5166. */
  5167. equals: function(stencil) {
  5168. return (this.id() === stencil.id());
  5169. },
  5170. stencilSet: function() {
  5171. return this._stencilSet;
  5172. },
  5173. type: function() {
  5174. return this._jsonStencil.type;
  5175. },
  5176. namespace: function() {
  5177. return this._namespace;
  5178. },
  5179. id: function() {
  5180. return this._jsonStencil.id;
  5181. },
  5182. idWithoutNs: function(){
  5183. return this.id().replace(this.namespace(),"");
  5184. },
  5185. title: function() {
  5186. return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "title");
  5187. },
  5188. description: function() {
  5189. return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "description");
  5190. },
  5191. groups: function() {
  5192. return ORYX.Core.StencilSet.getTranslation(this._jsonStencil, "groups");
  5193. },
  5194. position: function() {
  5195. return (isNaN(this._jsonStencil.position) ? 0 : this._jsonStencil.position);
  5196. },
  5197. view: function() {
  5198. return this._view.cloneNode(true) || this._view;
  5199. },
  5200. icon: function() {
  5201. return this._jsonStencil.icon;
  5202. },
  5203. fixedAspectRatio: function() {
  5204. return this._jsonStencil.fixedAspectRatio === true;
  5205. },
  5206. hasMultipleRepositoryEntries: function() {
  5207. return (this.getRepositoryEntries().length > 0);
  5208. },
  5209. getRepositoryEntries: function() {
  5210. return (this._jsonStencil.repositoryEntries) ?
  5211. $A(this._jsonStencil.repositoryEntries) : $A([]);
  5212. },
  5213. properties: function() {
  5214. return this._properties.values();
  5215. },
  5216. property: function(id) {
  5217. return this._properties[id];
  5218. },
  5219. roles: function() {
  5220. return this._jsonStencil.roles;
  5221. },
  5222. defaultAlign: function() {
  5223. if(!this._jsonStencil.defaultAlign)
  5224. return "east";
  5225. return this._jsonStencil.defaultAlign;
  5226. },
  5227. serialize: function(shape, data) {
  5228. return this._jsonStencil.serialize;
  5229. //return this._jsonStencil.serialize(shape, data);
  5230. },
  5231. deserialize: function(shape, data) {
  5232. return this._jsonStencil.deserialize;
  5233. //return this._jsonStencil.deserialize(shape, data);
  5234. },
  5235. // in which case is targetShape used?
  5236. // layout: function(shape, targetShape) {
  5237. // return this._jsonStencil.layout(shape, targetShape);
  5238. // },
  5239. // layout property to store events for layouting in plugins
  5240. layout: function(shape) {
  5241. return this._jsonStencil.layout
  5242. },
  5243. addProperty: function(property, namespace) {
  5244. if(property && namespace) {
  5245. var oProp = new ORYX.Core.StencilSet.Property(property, namespace, this);
  5246. this._properties[oProp.prefix() + "-" + oProp.id()] = oProp;
  5247. }
  5248. },
  5249. removeProperty: function(propertyId) {
  5250. if(propertyId) {
  5251. var oProp = this._properties.values().find(function(prop) {
  5252. return (propertyId == prop.id());
  5253. });
  5254. if(oProp)
  5255. delete this._properties[oProp.prefix() + "-" + oProp.id()];
  5256. }
  5257. },
  5258. _loadSVGOnSuccess: function(result) {
  5259. var xml = null;
  5260. /*
  5261. * We want to get a dom object for the requested file. Unfortunately,
  5262. * safari has some issues here. this is meant as a fallback for all
  5263. * browsers that don't recognize the svg mimetype as XML but support
  5264. * data: urls on Ajax calls.
  5265. */
  5266. // responseXML != undefined.
  5267. // if(!(result.responseXML))
  5268. // get the dom by data: url.
  5269. // xml = _evenMoreEvilHack(result.responseText, 'text/xml');
  5270. // else
  5271. // get it the usual way.
  5272. xml = result.responseXML;
  5273. //check if result is a SVG document
  5274. if( ORYX.Editor.checkClassType( xml.documentElement, SVGSVGElement )) {
  5275. this._view = xml.documentElement;
  5276. //updating link to images
  5277. var imageElems = this._view.getElementsByTagNameNS("http://www.w3.org/2000/svg", "image");
  5278. $A(imageElems).each((function(imageElem) {
  5279. var link = imageElem.getAttributeNodeNS("http://www.w3.org/1999/xlink", "href");
  5280. if(link && link.value.indexOf("://") == -1) {
  5281. link.textContent = this._source + "view/" + link.value;
  5282. }
  5283. }).bind(this));
  5284. } else {
  5285. throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnSuccess): The response is not a SVG document."
  5286. }
  5287. },
  5288. _loadSVGOnFailure: function(result) {
  5289. throw "ORYX.Core.StencilSet.Stencil(_loadSVGOnFailure): Loading SVG document failed."
  5290. },
  5291. toString: function() { return "Stencil " + this.title() + " (" + this.id() + ")"; }
  5292. };
  5293. ORYX.Core.StencilSet.Stencil = Clazz.extend(ORYX.Core.StencilSet.Stencil);
  5294. /**
  5295. * Transform a string into an xml document, the Safari way, as long as
  5296. * the nightlies are broken. Even more evil version.
  5297. * @param {Object} str
  5298. * @param {Object} contentType
  5299. */
  5300. function _evenMoreEvilHack(str, contentType) {
  5301. /*
  5302. * This even more evil hack was taken from
  5303. * http://web-graphics.com/mtarchive/001606.php#chatty004999
  5304. */
  5305. if (window.ActiveXObject) {
  5306. var d = new ActiveXObject("MSXML.DomDocument");
  5307. d.loadXML(str);
  5308. return d;
  5309. } else if (window.XMLHttpRequest) {
  5310. var req = new XMLHttpRequest;
  5311. req.open("GET", "data:" + (contentType || "application/xml") +
  5312. ";charset=utf-8," + encodeURIComponent(str), false);
  5313. if (req.overrideMimeType) {
  5314. req.overrideMimeType(contentType);
  5315. }
  5316. req.send(null);
  5317. return req.responseXML;
  5318. }
  5319. }
  5320. /**
  5321. * Transform a string into an xml document, the Safari way, as long as
  5322. * the nightlies are broken.
  5323. * @param {Object} result the xml document object.
  5324. */
  5325. function _evilSafariHack(serializedXML) {
  5326. /*
  5327. * The Dave way. Taken from:
  5328. * http://web-graphics.com/mtarchive/001606.php
  5329. *
  5330. * There is another possibility to parse XML in Safari, by implementing
  5331. * the DOMParser in javascript. However, in the latest nightlies of
  5332. * WebKit, DOMParser is already available, but still buggy. So, this is
  5333. * the best compromise for the time being.
  5334. */
  5335. var xml = serializedXML;
  5336. var url = "data:text/xml;charset=utf-8," + encodeURIComponent(xml);
  5337. var dom = null;
  5338. // your standard AJAX stuff
  5339. var req = new XMLHttpRequest();
  5340. req.open("GET", url);
  5341. req.onload = function() { dom = req.responseXML; }
  5342. req.send(null);
  5343. return dom;
  5344. }
  5345. /**
  5346. * Copyright (c) 2006
  5347. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  5348. *
  5349. * Permission is hereby granted, free of charge, to any person obtaining a
  5350. * copy of this software and associated documentation files (the "Software"),
  5351. * to deal in the Software without restriction, including without limitation
  5352. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  5353. * and/or sell copies of the Software, and to permit persons to whom the
  5354. * Software is furnished to do so, subject to the following conditions:
  5355. *
  5356. * The above copyright notice and this permission notice shall be included in
  5357. * all copies or substantial portions of the Software.
  5358. *
  5359. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5360. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5361. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5362. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5363. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5364. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  5365. * DEALINGS IN THE SOFTWARE.
  5366. **/
  5367. /**
  5368. * Init namespace
  5369. */
  5370. if (!ORYX) {
  5371. var ORYX = {};
  5372. }
  5373. if (!ORYX.Core) {
  5374. ORYX.Core = {};
  5375. }
  5376. if (!ORYX.Core.StencilSet) {
  5377. ORYX.Core.StencilSet = {};
  5378. }
  5379. /**
  5380. * Class Property
  5381. * uses Prototpye 1.5.0
  5382. * uses Inheritance
  5383. */
  5384. ORYX.Core.StencilSet.Property = Clazz.extend({
  5385. /**
  5386. * Constructor
  5387. */
  5388. construct: function(jsonProp, namespace, stencil){
  5389. arguments.callee.$.construct.apply(this, arguments);
  5390. this._jsonProp = jsonProp || ORYX.Log.error("Parameter jsonProp is not defined.");
  5391. this._namespace = namespace || ORYX.Log.error("Parameter namespace is not defined.");
  5392. this._stencil = stencil || ORYX.Log.error("Parameter stencil is not defined.");
  5393. this._items = {};
  5394. this._complexItems = {};
  5395. jsonProp.id = jsonProp.id || ORYX.Log.error("ORYX.Core.StencilSet.Property(construct): Id is not defined.");
  5396. jsonProp.id = jsonProp.id.toLowerCase();
  5397. if (!jsonProp.type) {
  5398. ORYX.Log.info("Type is not defined for stencil '%0', id '%1'. Falling back to 'String'.", stencil, jsonProp.id);
  5399. jsonProp.type = "string";
  5400. }
  5401. else {
  5402. jsonProp.type = jsonProp.type.toLowerCase();
  5403. }
  5404. jsonProp.prefix = jsonProp.prefix || "oryx";
  5405. jsonProp.title = jsonProp.title || "";
  5406. jsonProp.value = jsonProp.value || "";
  5407. jsonProp.description = jsonProp.description || "";
  5408. jsonProp.readonly = jsonProp.readonly || false;
  5409. jsonProp.optional = jsonProp.optional !== false;
  5410. //init refToView
  5411. if (this._jsonProp.refToView) {
  5412. if (!(this._jsonProp.refToView instanceof Array)) {
  5413. this._jsonProp.refToView = [this._jsonProp.refToView];
  5414. }
  5415. }
  5416. else {
  5417. this._jsonProp.refToView = [];
  5418. }
  5419. var globalMin = this.getMinForType(jsonProp.type);
  5420. if (jsonProp.min === undefined || jsonProp.min === null) {
  5421. jsonProp.min =globalMin;
  5422. } else if (jsonProp.min < globalMin) {
  5423. jsonProp.min = globalMin;
  5424. }
  5425. var globalMax = this.getMaxForType(jsonProp.type);
  5426. if (jsonProp.max === undefined || jsonProp.max === null) {
  5427. jsonProp.max = globalMax;
  5428. } else if (jsonProp.max > globalMax) {
  5429. jsonProp.min = globalMax;
  5430. }
  5431. if (!jsonProp.fillOpacity) {
  5432. jsonProp.fillOpacity = false;
  5433. }
  5434. if ("number" != typeof jsonProp.lightness) {
  5435. jsonProp.lightness = 1
  5436. } else {
  5437. jsonProp.lightness = Math.max(0, Math.min(1, jsonProp.lightness))
  5438. }
  5439. if (!jsonProp.strokeOpacity) {
  5440. jsonProp.strokeOpacity = false;
  5441. }
  5442. if (jsonProp.length === undefined || jsonProp.length === null) {
  5443. jsonProp.length = Number.MAX_VALUE;
  5444. }
  5445. if (!jsonProp.wrapLines) {
  5446. jsonProp.wrapLines = false;
  5447. }
  5448. if (!jsonProp.dateFormat) {
  5449. jsonProp.dateFormat = ORYX.I18N.PropertyWindow.dateFormat || "m/d/y";
  5450. }
  5451. if (!jsonProp.fill) {
  5452. jsonProp.fill = false;
  5453. }
  5454. if (!jsonProp.stroke) {
  5455. jsonProp.stroke = false;
  5456. }
  5457. if(!jsonProp.inverseBoolean) {
  5458. jsonProp.inverseBoolean = false;
  5459. }
  5460. if(!jsonProp.directlyEditable && jsonProp.directlyEditable != false) {
  5461. jsonProp.directlyEditable = true;
  5462. }
  5463. if(jsonProp.visible !== false) {
  5464. jsonProp.visible = true;
  5465. }
  5466. if(jsonProp.isList !== true) {
  5467. jsonProp.isList = false;
  5468. if(!jsonProp.list || !(jsonProp.list instanceof Array)) {
  5469. jsonProp.list = [];
  5470. }
  5471. }
  5472. if(!jsonProp.category) {
  5473. if (jsonProp.popular) {
  5474. jsonProp.category = "popular";
  5475. } else {
  5476. jsonProp.category = "others";
  5477. }
  5478. }
  5479. if(!jsonProp.alwaysAppearInMultiselect) {
  5480. jsonProp.alwaysAppearInMultiselect = false;
  5481. }
  5482. if (jsonProp.type === ORYX.CONFIG.TYPE_CHOICE) {
  5483. if (jsonProp.items && jsonProp.items instanceof Array) {
  5484. jsonProp.items.each((function(jsonItem){
  5485. // why is the item's value used as the key???
  5486. this._items[jsonItem.value.toLowerCase()] = new ORYX.Core.StencilSet.PropertyItem(jsonItem, namespace, this);
  5487. }).bind(this));
  5488. }
  5489. else {
  5490. throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
  5491. }
  5492. // extended by Kerstin (start)
  5493. }
  5494. else
  5495. if (jsonProp.type === ORYX.CONFIG.TYPE_COMPLEX || jsonProp.type == ORYX.CONFIG.TYPE_MULTIPLECOMPLEX) {
  5496. if (jsonProp.complexItems && jsonProp.complexItems instanceof Array) {
  5497. jsonProp.complexItems.each((function(jsonComplexItem){
  5498. this._complexItems[jsonComplexItem.id.toLowerCase()] = new ORYX.Core.StencilSet.ComplexPropertyItem(jsonComplexItem, namespace, this);
  5499. }).bind(this));
  5500. }
  5501. else {
  5502. throw "ORYX.Core.StencilSet.Property(construct): No complex property items defined."
  5503. }
  5504. }
  5505. // extended by Kerstin (end)
  5506. },
  5507. getMinForType : function(type) {
  5508. if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) {
  5509. return -Math.pow(2,31)
  5510. } else {
  5511. return -Number.MAX_VALUE+1;
  5512. }
  5513. },
  5514. getMaxForType : function(type) {
  5515. if (type.toLowerCase() == ORYX.CONFIG.TYPE_INTEGER) {
  5516. return Math.pow(2,31)-1
  5517. } else {
  5518. return Number.MAX_VALUE;
  5519. }
  5520. },
  5521. /**
  5522. * @param {ORYX.Core.StencilSet.Property} property
  5523. * @return {Boolean} True, if property has the same namespace and id.
  5524. */
  5525. equals: function(property){
  5526. return (this._namespace === property.namespace() &&
  5527. this.id() === property.id()) ? true : false;
  5528. },
  5529. namespace: function(){
  5530. return this._namespace;
  5531. },
  5532. stencil: function(){
  5533. return this._stencil;
  5534. },
  5535. id: function(){
  5536. return this._jsonProp.id;
  5537. },
  5538. prefix: function(){
  5539. return this._jsonProp.prefix;
  5540. },
  5541. type: function(){
  5542. return this._jsonProp.type;
  5543. },
  5544. inverseBoolean: function() {
  5545. return this._jsonProp.inverseBoolean;
  5546. },
  5547. category: function() {
  5548. return this._jsonProp.category;
  5549. },
  5550. setCategory: function(value) {
  5551. this._jsonProp.category = value;
  5552. },
  5553. directlyEditable: function() {
  5554. return this._jsonProp.directlyEditable;
  5555. },
  5556. visible: function() {
  5557. return this._jsonProp.visible;
  5558. },
  5559. title: function(){
  5560. return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "title");
  5561. },
  5562. value: function(){
  5563. return this._jsonProp.value;
  5564. },
  5565. readonly: function(){
  5566. return this._jsonProp.readonly;
  5567. },
  5568. optional: function(){
  5569. return this._jsonProp.optional;
  5570. },
  5571. description: function(){
  5572. return ORYX.Core.StencilSet.getTranslation(this._jsonProp, "description");
  5573. },
  5574. /**
  5575. * An optional link to a SVG element so that the property affects the
  5576. * graphical representation of the stencil.
  5577. */
  5578. refToView: function(){
  5579. return this._jsonProp.refToView;
  5580. },
  5581. /**
  5582. * If type is integer or float, min is the lower bounds of value.
  5583. */
  5584. min: function(){
  5585. return this._jsonProp.min;
  5586. },
  5587. /**
  5588. * If type ist integer or float, max is the upper bounds of value.
  5589. */
  5590. max: function(){
  5591. return this._jsonProp.max;
  5592. },
  5593. /**
  5594. * If type is float, this method returns if the fill-opacity property should
  5595. * be set.
  5596. * @return {Boolean}
  5597. */
  5598. fillOpacity: function(){
  5599. return this._jsonProp.fillOpacity;
  5600. },
  5601. /**
  5602. * If type is float, this method returns if the stroke-opacity property should
  5603. * be set.
  5604. * @return {Boolean}
  5605. */
  5606. strokeOpacity: function(){
  5607. return this._jsonProp.strokeOpacity;
  5608. },
  5609. /**
  5610. * If type is string or richtext, length is the maximum length of the text.
  5611. * TODO how long can a string be.
  5612. */
  5613. length: function(){
  5614. return this._jsonProp.length ? this._jsonProp.length : Number.MAX_VALUE;
  5615. },
  5616. wrapLines: function(){
  5617. return this._jsonProp.wrapLines;
  5618. },
  5619. /**
  5620. * If type is date, dateFormat specifies the format of the date. The format
  5621. * specification of the ext library is used:
  5622. *
  5623. * Format Output Description
  5624. * ------ ---------- --------------------------------------------------------------
  5625. * d 10 Day of the month, 2 digits with leading zeros
  5626. * D Wed A textual representation of a day, three letters
  5627. * j 10 Day of the month without leading zeros
  5628. * l Wednesday A full textual representation of the day of the week
  5629. * S th English ordinal day of month suffix, 2 chars (use with j)
  5630. * w 3 Numeric representation of the day of the week
  5631. * z 9 The julian date, or day of the year (0-365)
  5632. * W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
  5633. * F January A full textual representation of the month
  5634. * m 01 Numeric representation of a month, with leading zeros
  5635. * M Jan Month name abbreviation, three letters
  5636. * n 1 Numeric representation of a month, without leading zeros
  5637. * t 31 Number of days in the given month
  5638. * L 0 Whether its a leap year (1 if it is a leap year, else 0)
  5639. * Y 2007 A full numeric representation of a year, 4 digits
  5640. * y 07 A two digit representation of a year
  5641. * a pm Lowercase Ante meridiem and Post meridiem
  5642. * A PM Uppercase Ante meridiem and Post meridiem
  5643. * g 3 12-hour format of an hour without leading zeros
  5644. * G 15 24-hour format of an hour without leading zeros
  5645. * h 03 12-hour format of an hour with leading zeros
  5646. * H 15 24-hour format of an hour with leading zeros
  5647. * i 05 Minutes with leading zeros
  5648. * s 01 Seconds, with leading zeros
  5649. * O -0600 Difference to Greenwich time (GMT) in hours
  5650. * T CST Timezone setting of the machine running the code
  5651. * Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
  5652. *
  5653. * Example:
  5654. * F j, Y, g:i a -> January 10, 2007, 3:05 pm
  5655. */
  5656. dateFormat: function(){
  5657. return this._jsonProp.dateFormat;
  5658. },
  5659. /**
  5660. * If type is color, this method returns if the fill property should
  5661. * be set.
  5662. * @return {Boolean}
  5663. */
  5664. fill: function(){
  5665. return this._jsonProp.fill;
  5666. },
  5667. /**
  5668. * Lightness defines the satiation of the color
  5669. * 0 is the pure color
  5670. * 1 is white
  5671. * @return {Integer} lightness
  5672. */
  5673. lightness: function(){
  5674. return this._jsonProp.lightness;
  5675. },
  5676. /**
  5677. * If type is color, this method returns if the stroke property should
  5678. * be set.
  5679. * @return {Boolean}
  5680. */
  5681. stroke: function(){
  5682. return this._jsonProp.stroke;
  5683. },
  5684. /**
  5685. * If type is choice, items is a hash map with all alternative values
  5686. * (PropertyItem objects) with id as keys.
  5687. */
  5688. items: function(){
  5689. return $H(this._items).values();
  5690. },
  5691. item: function(value){
  5692. if (value) {
  5693. return this._items[value.toLowerCase()];
  5694. } else {
  5695. return null;
  5696. }
  5697. },
  5698. toString: function(){
  5699. return "Property " + this.title() + " (" + this.id() + ")";
  5700. },
  5701. complexItems: function(){
  5702. return $H(this._complexItems).values();
  5703. },
  5704. complexItem: function(id){
  5705. if(id) {
  5706. return this._complexItems[id.toLowerCase()];
  5707. } else {
  5708. return null;
  5709. }
  5710. },
  5711. complexAttributeToView: function(){
  5712. return this._jsonProp.complexAttributeToView || "";
  5713. },
  5714. isList: function() {
  5715. return !!this._jsonProp.isList;
  5716. },
  5717. getListItems: function() {
  5718. return this._jsonProp.list;
  5719. },
  5720. /**
  5721. * If type is glossary link, the
  5722. * type of category can be defined where
  5723. * the link only can go to.
  5724. * @return {String} The glossary category id
  5725. */
  5726. linkableType: function(){
  5727. return this._jsonProp.linkableType || "";
  5728. },
  5729. alwaysAppearInMultiselect : function() {
  5730. return this._jsonProp.alwaysAppearInMultiselect;
  5731. },
  5732. popular: function() {
  5733. return this._jsonProp.popular || false;
  5734. },
  5735. setPopular: function() {
  5736. this._jsonProp.popular = true;
  5737. }
  5738. });
  5739. /**
  5740. * Copyright (c) 2006
  5741. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  5742. *
  5743. * Permission is hereby granted, free of charge, to any person obtaining a
  5744. * copy of this software and associated documentation files (the "Software"),
  5745. * to deal in the Software without restriction, including without limitation
  5746. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  5747. * and/or sell copies of the Software, and to permit persons to whom the
  5748. * Software is furnished to do so, subject to the following conditions:
  5749. *
  5750. * The above copyright notice and this permission notice shall be included in
  5751. * all copies or substantial portions of the Software.
  5752. *
  5753. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5754. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5755. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5756. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5757. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5758. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  5759. * DEALINGS IN THE SOFTWARE.
  5760. **/
  5761. /**
  5762. * Init namespace
  5763. */
  5764. if(!ORYX) {var ORYX = {};}
  5765. if(!ORYX.Core) {ORYX.Core = {};}
  5766. if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};}
  5767. /**
  5768. * Class Stencil
  5769. * uses Prototpye 1.5.0
  5770. * uses Inheritance
  5771. */
  5772. ORYX.Core.StencilSet.PropertyItem = Clazz.extend({
  5773. /**
  5774. * Constructor
  5775. */
  5776. construct: function(jsonItem, namespace, property) {
  5777. arguments.callee.$.construct.apply(this, arguments);
  5778. if(!jsonItem) {
  5779. throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter jsonItem is not defined.";
  5780. }
  5781. if(!namespace) {
  5782. throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter namespace is not defined.";
  5783. }
  5784. if(!property) {
  5785. throw "ORYX.Core.StencilSet.PropertyItem(construct): Parameter property is not defined.";
  5786. }
  5787. this._jsonItem = jsonItem;
  5788. this._namespace = namespace;
  5789. this._property = property;
  5790. //init all values
  5791. if(!jsonItem.value) {
  5792. throw "ORYX.Core.StencilSet.PropertyItem(construct): Value is not defined.";
  5793. }
  5794. if(this._jsonItem.refToView) {
  5795. if(!(this._jsonItem.refToView instanceof Array)) {
  5796. this._jsonItem.refToView = [this._jsonItem.refToView];
  5797. }
  5798. } else {
  5799. this._jsonItem.refToView = [];
  5800. }
  5801. },
  5802. /**
  5803. * @param {ORYX.Core.StencilSet.PropertyItem} item
  5804. * @return {Boolean} True, if item has the same namespace and id.
  5805. */
  5806. equals: function(item) {
  5807. return (this.property().equals(item.property()) &&
  5808. this.value() === item.value());
  5809. },
  5810. namespace: function() {
  5811. return this._namespace;
  5812. },
  5813. property: function() {
  5814. return this._property;
  5815. },
  5816. value: function() {
  5817. return this._jsonItem.value;
  5818. },
  5819. title: function() {
  5820. return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "title");
  5821. },
  5822. refToView: function() {
  5823. return this._jsonItem.refToView;
  5824. },
  5825. icon: function() {
  5826. return (this._jsonItem.icon) ? this.property().stencil()._source + "icons/" + this._jsonItem.icon : "";
  5827. },
  5828. toString: function() { return "PropertyItem " + this.property() + " (" + this.value() + ")"; }
  5829. });/**
  5830. * Copyright (c) 2006
  5831. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  5832. *
  5833. * Permission is hereby granted, free of charge, to any person obtaining a
  5834. * copy of this software and associated documentation files (the "Software"),
  5835. * to deal in the Software without restriction, including without limitation
  5836. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  5837. * and/or sell copies of the Software, and to permit persons to whom the
  5838. * Software is furnished to do so, subject to the following conditions:
  5839. *
  5840. * The above copyright notice and this permission notice shall be included in
  5841. * all copies or substantial portions of the Software.
  5842. *
  5843. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5844. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5845. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5846. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5847. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5848. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  5849. * DEALINGS IN THE SOFTWARE.
  5850. **/
  5851. /**
  5852. * Init namespaces
  5853. */
  5854. if(!ORYX) {var ORYX = {};}
  5855. if(!ORYX.Core) {ORYX.Core = {};}
  5856. if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};}
  5857. /**
  5858. * Class Stencil
  5859. * uses Prototpye 1.5.0
  5860. * uses Inheritance
  5861. */
  5862. ORYX.Core.StencilSet.ComplexPropertyItem = Clazz.extend({
  5863. /**
  5864. * Constructor
  5865. */
  5866. construct: function(jsonItem, namespace, property) {
  5867. arguments.callee.$.construct.apply(this, arguments);
  5868. if(!jsonItem) {
  5869. throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter jsonItem is not defined.";
  5870. }
  5871. if(!namespace) {
  5872. throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter namespace is not defined.";
  5873. }
  5874. if(!property) {
  5875. throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Parameter property is not defined.";
  5876. }
  5877. this._jsonItem = jsonItem;
  5878. this._namespace = namespace;
  5879. this._property = property;
  5880. this._items = new Hash();
  5881. this._complexItems = new Hash();
  5882. //init all values
  5883. if(!jsonItem.name) {
  5884. throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Name is not defined.";
  5885. }
  5886. if(!jsonItem.type) {
  5887. throw "ORYX.Core.StencilSet.ComplexPropertyItem(construct): Type is not defined.";
  5888. } else {
  5889. jsonItem.type = jsonItem.type.toLowerCase();
  5890. }
  5891. if(jsonItem.type === ORYX.CONFIG.TYPE_CHOICE) {
  5892. if(jsonItem.items && jsonItem.items instanceof Array) {
  5893. jsonItem.items.each((function(item) {
  5894. this._items[item.value] = new ORYX.Core.StencilSet.PropertyItem(item, namespace, this);
  5895. }).bind(this));
  5896. } else {
  5897. throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
  5898. }
  5899. } else if(jsonItem.type === ORYX.CONFIG.TYPE_COMPLEX) {
  5900. if(jsonItem.complexItems && jsonItem.complexItems instanceof Array) {
  5901. jsonItem.complexItems.each((function(complexItem) {
  5902. this._complexItems[complexItem.id] = new ORYX.Core.StencilSet.ComplexPropertyItem(complexItem, namespace, this);
  5903. }).bind(this));
  5904. } else {
  5905. throw "ORYX.Core.StencilSet.Property(construct): No property items defined."
  5906. }
  5907. }
  5908. },
  5909. /**
  5910. * @param {ORYX.Core.StencilSet.PropertyItem} item
  5911. * @return {Boolean} True, if item has the same namespace and id.
  5912. */
  5913. equals: function(item) {
  5914. return (this.property().equals(item.property()) &&
  5915. this.name() === item.name());
  5916. },
  5917. namespace: function() {
  5918. return this._namespace;
  5919. },
  5920. property: function() {
  5921. return this._property;
  5922. },
  5923. name: function() {
  5924. return ORYX.Core.StencilSet.getTranslation(this._jsonItem, "name");
  5925. },
  5926. id: function() {
  5927. return this._jsonItem.id;
  5928. },
  5929. type: function() {
  5930. return this._jsonItem.type;
  5931. },
  5932. optional: function() {
  5933. return this._jsonItem.optional;
  5934. },
  5935. width: function() {
  5936. return this._jsonItem.width;
  5937. },
  5938. value: function() {
  5939. return this._jsonItem.value;
  5940. },
  5941. items: function() {
  5942. return this._items.values();
  5943. },
  5944. complexItems: function() {
  5945. return this._complexItems.values();
  5946. },
  5947. disable: function() {
  5948. return this._jsonItem.disable;
  5949. }
  5950. });/**
  5951. * Copyright (c) 2006
  5952. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  5953. *
  5954. * Permission is hereby granted, free of charge, to any person obtaining a
  5955. * copy of this software and associated documentation files (the "Software"),
  5956. * to deal in the Software without restriction, including without limitation
  5957. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  5958. * and/or sell copies of the Software, and to permit persons to whom the
  5959. * Software is furnished to do so, subject to the following conditions:
  5960. *
  5961. * The above copyright notice and this permission notice shall be included in
  5962. * all copies or substantial portions of the Software.
  5963. *
  5964. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  5965. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  5966. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  5967. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  5968. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  5969. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  5970. * DEALINGS IN THE SOFTWARE.
  5971. **/
  5972. /**
  5973. * Init namespaces
  5974. */
  5975. if(!ORYX) {var ORYX = {};}
  5976. if(!ORYX.Core) {ORYX.Core = {};}
  5977. if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};}
  5978. /**
  5979. * Class Rules uses Prototpye 1.5.0 uses Inheritance
  5980. *
  5981. * This class implements the API to check the stencil sets' rules.
  5982. */
  5983. ORYX.Core.StencilSet.Rules = {
  5984. /**
  5985. * Constructor
  5986. */
  5987. construct: function() {
  5988. arguments.callee.$.construct.apply(this, arguments);
  5989. this._stencilSets = [];
  5990. this._stencils = [];
  5991. this._containerStencils = [];
  5992. this._cachedConnectSET = new Hash();
  5993. this._cachedConnectSE = new Hash();
  5994. this._cachedConnectTE = new Hash();
  5995. this._cachedCardSE = new Hash();
  5996. this._cachedCardTE = new Hash();
  5997. this._cachedContainPC = new Hash();
  5998. this._cachedMorphRS = new Hash();
  5999. this._connectionRules = new Hash();
  6000. this._cardinalityRules = new Hash();
  6001. this._containmentRules = new Hash();
  6002. this._morphingRules = new Hash();
  6003. this._layoutRules = new Hash();
  6004. },
  6005. /**
  6006. * Call this method to initialize the rules for a stencil set and all of its
  6007. * active extensions.
  6008. *
  6009. * @param {Object}
  6010. * stencilSet
  6011. */
  6012. initializeRules: function(stencilSet) {
  6013. var existingSS = this._stencilSets.find(function(ss) {
  6014. return (ss.namespace() == stencilSet.namespace());
  6015. });
  6016. if (existingSS) {
  6017. // reinitialize all rules
  6018. var stencilsets = this._stencilSets.clone();
  6019. stencilsets = stencilsets.without(existingSS);
  6020. stencilsets.push(stencilSet);
  6021. this._stencilSets = [];
  6022. this._stencils = [];
  6023. this._containerStencils = [];
  6024. this._cachedConnectSET = new Hash();
  6025. this._cachedConnectSE = new Hash();
  6026. this._cachedConnectTE = new Hash();
  6027. this._cachedCardSE = new Hash();
  6028. this._cachedCardTE = new Hash();
  6029. this._cachedContainPC = new Hash();
  6030. this._cachedMorphRS = new Hash();
  6031. this._connectionRules = new Hash();
  6032. this._cardinalityRules = new Hash();
  6033. this._containmentRules = new Hash();
  6034. this._morphingRules = new Hash();
  6035. this._layoutRules = new Hash();
  6036. stencilsets.each(function(ss){
  6037. this.initializeRules(ss);
  6038. }.bind(this));
  6039. return;
  6040. }
  6041. else {
  6042. this._stencilSets.push(stencilSet);
  6043. var jsonRules = new Hash(stencilSet.jsonRules());
  6044. var namespace = stencilSet.namespace();
  6045. var stencils = stencilSet.stencils();
  6046. stencilSet.extensions().values().each(function(extension) {
  6047. if(extension.rules) {
  6048. if(extension.rules.connectionRules)
  6049. jsonRules.connectionRules = jsonRules.connectionRules.concat(extension.rules.connectionRules);
  6050. if(extension.rules.cardinalityRules)
  6051. jsonRules.cardinalityRules = jsonRules.cardinalityRules.concat(extension.rules.cardinalityRules);
  6052. if(extension.rules.containmentRules)
  6053. jsonRules.containmentRules = jsonRules.containmentRules.concat(extension.rules.containmentRules);
  6054. if(extension.rules.morphingRules)
  6055. jsonRules.morphingRules = jsonRules.morphingRules.concat(extension.rules.morphingRules);
  6056. }
  6057. if(extension.stencils)
  6058. stencils = stencils.concat(extension.stencils);
  6059. });
  6060. this._stencils = this._stencils.concat(stencilSet.stencils());
  6061. // init connection rules
  6062. var cr = this._connectionRules;
  6063. if (jsonRules.connectionRules) {
  6064. jsonRules.connectionRules.each((function(rules){
  6065. if (this._isRoleOfOtherNamespace(rules.role)) {
  6066. if (!cr[rules.role]) {
  6067. cr[rules.role] = new Hash();
  6068. }
  6069. }
  6070. else {
  6071. if (!cr[namespace + rules.role])
  6072. cr[namespace + rules.role] = new Hash();
  6073. }
  6074. rules.connects.each((function(connect){
  6075. var toRoles = [];
  6076. if (connect.to) {
  6077. if (!(connect.to instanceof Array)) {
  6078. connect.to = [connect.to];
  6079. }
  6080. connect.to.each((function(to){
  6081. if (this._isRoleOfOtherNamespace(to)) {
  6082. toRoles.push(to);
  6083. }
  6084. else {
  6085. toRoles.push(namespace + to);
  6086. }
  6087. }).bind(this));
  6088. }
  6089. var role, from;
  6090. if (this._isRoleOfOtherNamespace(rules.role))
  6091. role = rules.role;
  6092. else
  6093. role = namespace + rules.role;
  6094. if (this._isRoleOfOtherNamespace(connect.from))
  6095. from = connect.from;
  6096. else
  6097. from = namespace + connect.from;
  6098. if (!cr[role][from])
  6099. cr[role][from] = toRoles;
  6100. else
  6101. cr[role][from] = cr[role][from].concat(toRoles);
  6102. }).bind(this));
  6103. }).bind(this));
  6104. }
  6105. // init cardinality rules
  6106. var cardr = this._cardinalityRules;
  6107. if (jsonRules.cardinalityRules) {
  6108. jsonRules.cardinalityRules.each((function(rules){
  6109. var cardrKey;
  6110. if (this._isRoleOfOtherNamespace(rules.role)) {
  6111. cardrKey = rules.role;
  6112. }
  6113. else {
  6114. cardrKey = namespace + rules.role;
  6115. }
  6116. if (!cardr[cardrKey]) {
  6117. cardr[cardrKey] = {};
  6118. for (i in rules) {
  6119. cardr[cardrKey][i] = rules[i];
  6120. }
  6121. }
  6122. var oe = new Hash();
  6123. if (rules.outgoingEdges) {
  6124. rules.outgoingEdges.each((function(rule){
  6125. if (this._isRoleOfOtherNamespace(rule.role)) {
  6126. oe[rule.role] = rule;
  6127. }
  6128. else {
  6129. oe[namespace + rule.role] = rule;
  6130. }
  6131. }).bind(this));
  6132. }
  6133. cardr[cardrKey].outgoingEdges = oe;
  6134. var ie = new Hash();
  6135. if (rules.incomingEdges) {
  6136. rules.incomingEdges.each((function(rule){
  6137. if (this._isRoleOfOtherNamespace(rule.role)) {
  6138. ie[rule.role] = rule;
  6139. }
  6140. else {
  6141. ie[namespace + rule.role] = rule;
  6142. }
  6143. }).bind(this));
  6144. }
  6145. cardr[cardrKey].incomingEdges = ie;
  6146. }).bind(this));
  6147. }
  6148. // init containment rules
  6149. var conr = this._containmentRules;
  6150. if (jsonRules.containmentRules) {
  6151. jsonRules.containmentRules.each((function(rules){
  6152. var conrKey;
  6153. if (this._isRoleOfOtherNamespace(rules.role)) {
  6154. conrKey = rules.role;
  6155. }
  6156. else {
  6157. this._containerStencils.push(namespace + rules.role);
  6158. conrKey = namespace + rules.role;
  6159. }
  6160. if (!conr[conrKey]) {
  6161. conr[conrKey] = [];
  6162. }
  6163. (rules.contains||[]).each((function(containRole){
  6164. if (this._isRoleOfOtherNamespace(containRole)) {
  6165. conr[conrKey].push(containRole);
  6166. }
  6167. else {
  6168. conr[conrKey].push(namespace + containRole);
  6169. }
  6170. }).bind(this));
  6171. }).bind(this));
  6172. }
  6173. // init morphing rules
  6174. var morphr = this._morphingRules;
  6175. if (jsonRules.morphingRules) {
  6176. jsonRules.morphingRules.each((function(rules){
  6177. var morphrKey;
  6178. if (this._isRoleOfOtherNamespace(rules.role)) {
  6179. morphrKey = rules.role;
  6180. }
  6181. else {
  6182. morphrKey = namespace + rules.role;
  6183. }
  6184. if (!morphr[morphrKey]) {
  6185. morphr[morphrKey] = [];
  6186. }
  6187. if(!rules.preserveBounds) {
  6188. rules.preserveBounds = false;
  6189. }
  6190. rules.baseMorphs.each((function(baseMorphStencilId){
  6191. var morphStencil = this._getStencilById(namespace + baseMorphStencilId);
  6192. if(morphStencil) {
  6193. morphr[morphrKey].push(morphStencil);
  6194. }
  6195. }).bind(this));
  6196. }).bind(this));
  6197. }
  6198. // init layouting rules
  6199. var layoutRules = this._layoutRules;
  6200. if (jsonRules.layoutRules) {
  6201. var getDirections = function(o){
  6202. return {
  6203. "edgeRole":o.edgeRole||undefined,
  6204. "t": o["t"]||1,
  6205. "r": o["r"]||1,
  6206. "b": o["b"]||1,
  6207. "l": o["l"]||1
  6208. }
  6209. }
  6210. jsonRules.layoutRules.each(function(rules){
  6211. var layoutKey;
  6212. if (this._isRoleOfOtherNamespace(rules.role)) {
  6213. layoutKey = rules.role;
  6214. }
  6215. else {
  6216. layoutKey = namespace + rules.role;
  6217. }
  6218. if (!layoutRules[layoutKey]) {
  6219. layoutRules[layoutKey] = {};
  6220. }
  6221. if (rules["in"]){
  6222. layoutRules[layoutKey]["in"] = getDirections(rules["in"]);
  6223. }
  6224. if (rules["ins"]){
  6225. layoutRules[layoutKey]["ins"] = (rules["ins"]||[]).map(function(e){ return getDirections(e) })
  6226. }
  6227. if (rules["out"]) {
  6228. layoutRules[layoutKey]["out"] = getDirections(rules["out"]);
  6229. }
  6230. if (rules["outs"]){
  6231. layoutRules[layoutKey]["outs"] = (rules["outs"]||[]).map(function(e){ return getDirections(e) })
  6232. }
  6233. }.bind(this));
  6234. }
  6235. }
  6236. },
  6237. _getStencilById: function(id) {
  6238. return this._stencils.find(function(stencil) {
  6239. return stencil.id()==id;
  6240. });
  6241. },
  6242. _cacheConnect: function(args) {
  6243. result = this._canConnect(args);
  6244. if (args.sourceStencil && args.targetStencil) {
  6245. var source = this._cachedConnectSET[args.sourceStencil.id()];
  6246. if(!source) {
  6247. source = new Hash();
  6248. this._cachedConnectSET[args.sourceStencil.id()] = source;
  6249. }
  6250. var edge = source[args.edgeStencil.id()];
  6251. if(!edge) {
  6252. edge = new Hash();
  6253. source[args.edgeStencil.id()] = edge;
  6254. }
  6255. edge[args.targetStencil.id()] = result;
  6256. } else if (args.sourceStencil) {
  6257. var source = this._cachedConnectSE[args.sourceStencil.id()];
  6258. if(!source) {
  6259. source = new Hash();
  6260. this._cachedConnectSE[args.sourceStencil.id()] = source;
  6261. }
  6262. source[args.edgeStencil.id()] = result;
  6263. } else {
  6264. var target = this._cachedConnectTE[args.targetStencil.id()];
  6265. if(!target) {
  6266. target = new Hash();
  6267. this._cachedConnectTE[args.targetStencil.id()] = target;
  6268. }
  6269. target[args.edgeStencil.id()] = result;
  6270. }
  6271. return result;
  6272. },
  6273. _cacheCard: function(args) {
  6274. if(args.sourceStencil) {
  6275. var source = this._cachedCardSE[args.sourceStencil.id()]
  6276. if(!source) {
  6277. source = new Hash();
  6278. this._cachedCardSE[args.sourceStencil.id()] = source;
  6279. }
  6280. var max = this._getMaximumNumberOfOutgoingEdge(args);
  6281. if(max == undefined)
  6282. max = -1;
  6283. source[args.edgeStencil.id()] = max;
  6284. }
  6285. if(args.targetStencil) {
  6286. var target = this._cachedCardTE[args.targetStencil.id()]
  6287. if(!target) {
  6288. target = new Hash();
  6289. this._cachedCardTE[args.targetStencil.id()] = target;
  6290. }
  6291. var max = this._getMaximumNumberOfIncomingEdge(args);
  6292. if(max == undefined)
  6293. max = -1;
  6294. target[args.edgeStencil.id()] = max;
  6295. }
  6296. },
  6297. _cacheContain: function(args) {
  6298. var result = [this._canContain(args),
  6299. this._getMaximumOccurrence(args.containingStencil, args.containedStencil)]
  6300. if(result[1] == undefined)
  6301. result[1] = -1;
  6302. var children = this._cachedContainPC[args.containingStencil.id()];
  6303. if(!children) {
  6304. children = new Hash();
  6305. this._cachedContainPC[args.containingStencil.id()] = children;
  6306. }
  6307. children[args.containedStencil.id()] = result;
  6308. return result;
  6309. },
  6310. /**
  6311. * Returns all stencils belonging to a morph group. (calculation result is
  6312. * cached)
  6313. */
  6314. _cacheMorph: function(role) {
  6315. var morphs = this._cachedMorphRS[role];
  6316. if(!morphs) {
  6317. morphs = [];
  6318. if(this._morphingRules.keys().include(role)) {
  6319. morphs = this._stencils.select(function(stencil) {
  6320. return stencil.roles().include(role);
  6321. });
  6322. }
  6323. this._cachedMorphRS[role] = morphs;
  6324. }
  6325. return morphs;
  6326. },
  6327. /** Begin connection rules' methods */
  6328. /**
  6329. *
  6330. * @param {Object}
  6331. * args sourceStencil: ORYX.Core.StencilSet.Stencil | undefined
  6332. * sourceShape: ORYX.Core.Shape | undefined
  6333. *
  6334. * At least sourceStencil or sourceShape has to be specified
  6335. *
  6336. * @return {Array} Array of stencils of edges that can be outgoing edges of
  6337. * the source.
  6338. */
  6339. outgoingEdgeStencils: function(args) {
  6340. // check arguments
  6341. if(!args.sourceShape && !args.sourceStencil) {
  6342. return [];
  6343. }
  6344. // init arguments
  6345. if(args.sourceShape) {
  6346. args.sourceStencil = args.sourceShape.getStencil();
  6347. }
  6348. var _edges = [];
  6349. // test each edge, if it can connect to source
  6350. this._stencils.each((function(stencil) {
  6351. if(stencil.type() === "edge") {
  6352. var newArgs = Object.clone(args);
  6353. newArgs.edgeStencil = stencil;
  6354. if(this.canConnect(newArgs)) {
  6355. _edges.push(stencil);
  6356. }
  6357. }
  6358. }).bind(this));
  6359. return _edges;
  6360. },
  6361. /**
  6362. *
  6363. * @param {Object}
  6364. * args targetStencil: ORYX.Core.StencilSet.Stencil | undefined
  6365. * targetShape: ORYX.Core.Shape | undefined
  6366. *
  6367. * At least targetStencil or targetShape has to be specified
  6368. *
  6369. * @return {Array} Array of stencils of edges that can be incoming edges of
  6370. * the target.
  6371. */
  6372. incomingEdgeStencils: function(args) {
  6373. // check arguments
  6374. if(!args.targetShape && !args.targetStencil) {
  6375. return [];
  6376. }
  6377. // init arguments
  6378. if(args.targetShape) {
  6379. args.targetStencil = args.targetShape.getStencil();
  6380. }
  6381. var _edges = [];
  6382. // test each edge, if it can connect to source
  6383. this._stencils.each((function(stencil) {
  6384. if(stencil.type() === "edge") {
  6385. var newArgs = Object.clone(args);
  6386. newArgs.edgeStencil = stencil;
  6387. if(this.canConnect(newArgs)) {
  6388. _edges.push(stencil);
  6389. }
  6390. }
  6391. }).bind(this));
  6392. return _edges;
  6393. },
  6394. /**
  6395. *
  6396. * @param {Object}
  6397. * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined
  6398. * edgeShape: ORYX.Core.Edge | undefined targetStencil:
  6399. * ORYX.Core.StencilSet.Stencil | undefined targetShape:
  6400. * ORYX.Core.Node | undefined
  6401. *
  6402. * At least edgeStencil or edgeShape has to be specified!!!
  6403. *
  6404. * @return {Array} Returns an array of stencils that can be source of the
  6405. * specified edge.
  6406. */
  6407. sourceStencils: function(args) {
  6408. // check arguments
  6409. if(!args ||
  6410. !args.edgeShape && !args.edgeStencil) {
  6411. return [];
  6412. }
  6413. // init arguments
  6414. if(args.targetShape) {
  6415. args.targetStencil = args.targetShape.getStencil();
  6416. }
  6417. if(args.edgeShape) {
  6418. args.edgeStencil = args.edgeShape.getStencil();
  6419. }
  6420. var _sources = [];
  6421. // check each stencil, if it can be a source
  6422. this._stencils.each((function(stencil) {
  6423. var newArgs = Object.clone(args);
  6424. newArgs.sourceStencil = stencil;
  6425. if(this.canConnect(newArgs)) {
  6426. _sources.push(stencil);
  6427. }
  6428. }).bind(this));
  6429. return _sources;
  6430. },
  6431. /**
  6432. *
  6433. * @param {Object}
  6434. * args edgeStencil: ORYX.Core.StencilSet.Stencil | undefined
  6435. * edgeShape: ORYX.Core.Edge | undefined sourceStencil:
  6436. * ORYX.Core.StencilSet.Stencil | undefined sourceShape:
  6437. * ORYX.Core.Node | undefined
  6438. *
  6439. * At least edgeStencil or edgeShape has to be specified!!!
  6440. *
  6441. * @return {Array} Returns an array of stencils that can be target of the
  6442. * specified edge.
  6443. */
  6444. targetStencils: function(args) {
  6445. // check arguments
  6446. if(!args ||
  6447. !args.edgeShape && !args.edgeStencil) {
  6448. return [];
  6449. }
  6450. // init arguments
  6451. if(args.sourceShape) {
  6452. args.sourceStencil = args.sourceShape.getStencil();
  6453. }
  6454. if(args.edgeShape) {
  6455. args.edgeStencil = args.edgeShape.getStencil();
  6456. }
  6457. var _targets = [];
  6458. // check stencil, if it can be a target
  6459. this._stencils.each((function(stencil) {
  6460. var newArgs = Object.clone(args);
  6461. newArgs.targetStencil = stencil;
  6462. if(this.canConnect(newArgs)) {
  6463. _targets.push(stencil);
  6464. }
  6465. }).bind(this));
  6466. return _targets;
  6467. },
  6468. /**
  6469. *
  6470. * @param {Object}
  6471. * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape:
  6472. * ORYX.Core.Edge |undefined sourceStencil:
  6473. * ORYX.Core.StencilSet.Stencil | undefined sourceShape:
  6474. * ORYX.Core.Node |undefined targetStencil:
  6475. * ORYX.Core.StencilSet.Stencil | undefined targetShape:
  6476. * ORYX.Core.Node |undefined
  6477. *
  6478. * At least source or target has to be specified!!!
  6479. *
  6480. * @return {Boolean} Returns, if the edge can connect source and target.
  6481. */
  6482. canConnect: function(args) {
  6483. // check arguments
  6484. if(!args ||
  6485. (!args.sourceShape && !args.sourceStencil &&
  6486. !args.targetShape && !args.targetStencil) ||
  6487. !args.edgeShape && !args.edgeStencil) {
  6488. return false;
  6489. }
  6490. // init arguments
  6491. if(args.sourceShape) {
  6492. args.sourceStencil = args.sourceShape.getStencil();
  6493. }
  6494. if(args.targetShape) {
  6495. args.targetStencil = args.targetShape.getStencil();
  6496. }
  6497. if(args.edgeShape) {
  6498. args.edgeStencil = args.edgeShape.getStencil();
  6499. }
  6500. var result;
  6501. if(args.sourceStencil && args.targetStencil) {
  6502. var source = this._cachedConnectSET[args.sourceStencil.id()];
  6503. if(!source)
  6504. result = this._cacheConnect(args);
  6505. else {
  6506. var edge = source[args.edgeStencil.id()];
  6507. if(!edge)
  6508. result = this._cacheConnect(args);
  6509. else {
  6510. var target = edge[args.targetStencil.id()];
  6511. if(target == undefined)
  6512. result = this._cacheConnect(args);
  6513. else
  6514. result = target;
  6515. }
  6516. }
  6517. } else if (args.sourceStencil) {
  6518. var source = this._cachedConnectSE[args.sourceStencil.id()];
  6519. if(!source)
  6520. result = this._cacheConnect(args);
  6521. else {
  6522. var edge = source[args.edgeStencil.id()];
  6523. if(edge == undefined)
  6524. result = this._cacheConnect(args);
  6525. else
  6526. result = edge;
  6527. }
  6528. } else { // args.targetStencil
  6529. var target = this._cachedConnectTE[args.targetStencil.id()];
  6530. if(!target)
  6531. result = this._cacheConnect(args);
  6532. else {
  6533. var edge = target[args.edgeStencil.id()];
  6534. if(edge == undefined)
  6535. result = this._cacheConnect(args);
  6536. else
  6537. result = edge;
  6538. }
  6539. }
  6540. // check cardinality
  6541. if (result) {
  6542. if(args.sourceShape) {
  6543. var source = this._cachedCardSE[args.sourceStencil.id()];
  6544. if(!source) {
  6545. this._cacheCard(args);
  6546. source = this._cachedCardSE[args.sourceStencil.id()];
  6547. }
  6548. var max = source[args.edgeStencil.id()];
  6549. if(max == undefined) {
  6550. this._cacheCard(args);
  6551. }
  6552. max = source[args.edgeStencil.id()];
  6553. if(max != -1) {
  6554. result = args.sourceShape.getOutgoingShapes().all(function(cs) {
  6555. if((cs.getStencil().id() === args.edgeStencil.id()) &&
  6556. ((args.edgeShape) ? cs !== args.edgeShape : true)) {
  6557. max--;
  6558. return (max > 0) ? true : false;
  6559. } else {
  6560. return true;
  6561. }
  6562. });
  6563. }
  6564. }
  6565. if (args.targetShape) {
  6566. var target = this._cachedCardTE[args.targetStencil.id()];
  6567. if(!target) {
  6568. this._cacheCard(args);
  6569. target = this._cachedCardTE[args.targetStencil.id()];
  6570. }
  6571. var max = target[args.edgeStencil.id()];
  6572. if(max == undefined) {
  6573. this._cacheCard(args);
  6574. }
  6575. max = target[args.edgeStencil.id()];
  6576. if(max != -1) {
  6577. result = args.targetShape.getIncomingShapes().all(function(cs){
  6578. if ((cs.getStencil().id() === args.edgeStencil.id()) &&
  6579. ((args.edgeShape) ? cs !== args.edgeShape : true)) {
  6580. max--;
  6581. return (max > 0) ? true : false;
  6582. }
  6583. else {
  6584. return true;
  6585. }
  6586. });
  6587. }
  6588. }
  6589. }
  6590. return result;
  6591. },
  6592. /**
  6593. *
  6594. * @param {Object}
  6595. * args edgeStencil: ORYX.Core.StencilSet.Stencil edgeShape:
  6596. * ORYX.Core.Edge |undefined sourceStencil:
  6597. * ORYX.Core.StencilSet.Stencil | undefined sourceShape:
  6598. * ORYX.Core.Node |undefined targetStencil:
  6599. * ORYX.Core.StencilSet.Stencil | undefined targetShape:
  6600. * ORYX.Core.Node |undefined
  6601. *
  6602. * At least source or target has to be specified!!!
  6603. *
  6604. * @return {Boolean} Returns, if the edge can connect source and target.
  6605. */
  6606. _canConnect: function(args) {
  6607. // check arguments
  6608. if(!args ||
  6609. (!args.sourceShape && !args.sourceStencil &&
  6610. !args.targetShape && !args.targetStencil) ||
  6611. !args.edgeShape && !args.edgeStencil) {
  6612. return false;
  6613. }
  6614. // init arguments
  6615. if(args.sourceShape) {
  6616. args.sourceStencil = args.sourceShape.getStencil();
  6617. }
  6618. if(args.targetShape) {
  6619. args.targetStencil = args.targetShape.getStencil();
  6620. }
  6621. if(args.edgeShape) {
  6622. args.edgeStencil = args.edgeShape.getStencil();
  6623. }
  6624. // 1. check connection rules
  6625. var resultCR;
  6626. // get all connection rules for this edge
  6627. var edgeRules = this._getConnectionRulesOfEdgeStencil(args.edgeStencil);
  6628. // check connection rules, if the source can be connected to the target
  6629. // with the specified edge.
  6630. if(edgeRules.keys().length === 0) {
  6631. resultCR = false;
  6632. } else {
  6633. if(args.sourceStencil) {
  6634. resultCR = args.sourceStencil.roles().any(function(sourceRole) {
  6635. var targetRoles = edgeRules[sourceRole];
  6636. if(!targetRoles) {return false;}
  6637. if(args.targetStencil) {
  6638. return (targetRoles.any(function(targetRole) {
  6639. return args.targetStencil.roles().member(targetRole);
  6640. }));
  6641. } else {
  6642. return true;
  6643. }
  6644. });
  6645. } else { // !args.sourceStencil -> there is args.targetStencil
  6646. resultCR = edgeRules.values().any(function(targetRoles) {
  6647. return args.targetStencil.roles().any(function(targetRole) {
  6648. return targetRoles.member(targetRole);
  6649. });
  6650. });
  6651. }
  6652. }
  6653. return resultCR;
  6654. },
  6655. /** End connection rules' methods */
  6656. /** Begin containment rules' methods */
  6657. isContainer: function(shape) {
  6658. return this._containerStencils.member(shape.getStencil().id());
  6659. },
  6660. /**
  6661. *
  6662. * @param {Object}
  6663. * args containingStencil: ORYX.Core.StencilSet.Stencil
  6664. * containingShape: ORYX.Core.AbstractShape containedStencil:
  6665. * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape
  6666. */
  6667. canContain: function(args) {
  6668. if(!args ||
  6669. !args.containingStencil && !args.containingShape ||
  6670. !args.containedStencil && !args.containedShape) {
  6671. return false;
  6672. }
  6673. // init arguments
  6674. if(args.containedShape) {
  6675. args.containedStencil = args.containedShape.getStencil();
  6676. }
  6677. if(args.containingShape) {
  6678. args.containingStencil = args.containingShape.getStencil();
  6679. }
  6680. //if(args.containingStencil.type() == 'edge' || args.containedStencil.type() == 'edge')
  6681. // return false;
  6682. if(args.containedStencil.type() == 'edge')
  6683. return false;
  6684. var childValues;
  6685. var parent = this._cachedContainPC[args.containingStencil.id()];
  6686. if(!parent)
  6687. childValues = this._cacheContain(args);
  6688. else {
  6689. childValues = parent[args.containedStencil.id()];
  6690. if(!childValues)
  6691. childValues = this._cacheContain(args);
  6692. }
  6693. if(!childValues[0])
  6694. return false;
  6695. else if (childValues[1] == -1)
  6696. return true;
  6697. else {
  6698. if(args.containingShape) {
  6699. var max = childValues[1];
  6700. return args.containingShape.getChildShapes(false).all(function(as) {
  6701. if(as.getStencil().id() === args.containedStencil.id()) {
  6702. max--;
  6703. return (max > 0) ? true : false;
  6704. } else {
  6705. return true;
  6706. }
  6707. });
  6708. } else {
  6709. return true;
  6710. }
  6711. }
  6712. },
  6713. /**
  6714. *
  6715. * @param {Object}
  6716. * args containingStencil: ORYX.Core.StencilSet.Stencil
  6717. * containingShape: ORYX.Core.AbstractShape containedStencil:
  6718. * ORYX.Core.StencilSet.Stencil containedShape: ORYX.Core.Shape
  6719. */
  6720. _canContain: function(args) {
  6721. if(!args ||
  6722. !args.containingStencil && !args.containingShape ||
  6723. !args.containedStencil && !args.containedShape) {
  6724. return false;
  6725. }
  6726. // init arguments
  6727. if(args.containedShape) {
  6728. args.containedStencil = args.containedShape.getStencil();
  6729. }
  6730. if(args.containingShape) {
  6731. args.containingStencil = args.containingShape.getStencil();
  6732. }
  6733. // if(args.containingShape) {
  6734. // if(args.containingShape instanceof ORYX.Core.Edge) {
  6735. // // edges cannot contain other shapes
  6736. // return false;
  6737. // }
  6738. // }
  6739. var result;
  6740. // check containment rules
  6741. result = args.containingStencil.roles().any((function(role) {
  6742. var roles = this._containmentRules[role];
  6743. if(roles) {
  6744. return roles.any(function(role) {
  6745. return args.containedStencil.roles().member(role);
  6746. });
  6747. } else {
  6748. return false;
  6749. }
  6750. }).bind(this));
  6751. return result;
  6752. },
  6753. /** End containment rules' methods */
  6754. /** Begin morphing rules' methods */
  6755. /**
  6756. *
  6757. * @param {Object}
  6758. * args
  6759. * stencil: ORYX.Core.StencilSet.Stencil | undefined
  6760. * shape: ORYX.Core.Shape | undefined
  6761. *
  6762. * At least stencil or shape has to be specified
  6763. *
  6764. * @return {Array} Array of stencils that the passed stencil/shape can be
  6765. * transformed to (including the current stencil itself)
  6766. */
  6767. morphStencils: function(args) {
  6768. // check arguments
  6769. if(!args.stencil && !args.shape) {
  6770. return [];
  6771. }
  6772. // init arguments
  6773. if(args.shape) {
  6774. args.stencil = args.shape.getStencil();
  6775. }
  6776. var _morphStencils = [];
  6777. args.stencil.roles().each(function(role) {
  6778. this._cacheMorph(role).each(function(stencil) {
  6779. _morphStencils.push(stencil);
  6780. })
  6781. }.bind(this));
  6782. var baseMorphs = this.baseMorphs();
  6783. // BaseMorphs should be in the front of the array
  6784. _morphStencils = _morphStencils.uniq().sort(function(a,b){ return baseMorphs.include(a)&&!baseMorphs.include(b) ? -1 : (baseMorphs.include(b)&&!baseMorphs.include(a) ? 1 : 0)})
  6785. return _morphStencils;
  6786. },
  6787. /**
  6788. * @return {Array} An array of all base morph stencils
  6789. */
  6790. baseMorphs: function() {
  6791. var _baseMorphs = [];
  6792. this._morphingRules.each(function(pair) {
  6793. pair.value.each(function(baseMorph) {
  6794. _baseMorphs.push(baseMorph);
  6795. });
  6796. });
  6797. return _baseMorphs;
  6798. },
  6799. /**
  6800. * Returns true if there are morphing rules defines
  6801. * @return {boolean}
  6802. */
  6803. containsMorphingRules: function(){
  6804. return this._stencilSets.any(function(ss){ return !!ss.jsonRules().morphingRules});
  6805. },
  6806. /**
  6807. *
  6808. * @param {Object}
  6809. * args
  6810. * sourceStencil:
  6811. * ORYX.Core.StencilSet.Stencil | undefined
  6812. * sourceShape:
  6813. * ORYX.Core.Node |undefined
  6814. * targetStencil:
  6815. * ORYX.Core.StencilSet.Stencil | undefined
  6816. * targetShape:
  6817. * ORYX.Core.Node |undefined
  6818. *
  6819. *
  6820. * @return {Stencil} Returns, the stencil for the connecting edge
  6821. * or null if connection is not possible
  6822. */
  6823. connectMorph: function(args) {
  6824. // check arguments
  6825. if(!args ||
  6826. (!args.sourceShape && !args.sourceStencil &&
  6827. !args.targetShape && !args.targetStencil)) {
  6828. return false;
  6829. }
  6830. // init arguments
  6831. if(args.sourceShape) {
  6832. args.sourceStencil = args.sourceShape.getStencil();
  6833. }
  6834. if(args.targetShape) {
  6835. args.targetStencil = args.targetShape.getStencil();
  6836. }
  6837. var incoming = this.incomingEdgeStencils(args);
  6838. var outgoing = this.outgoingEdgeStencils(args);
  6839. var edgeStencils = incoming.select(function(e) { return outgoing.member(e); }); // intersection of sets
  6840. var baseEdgeStencils = this.baseMorphs().select(function(e) { return edgeStencils.member(e); }); // again: intersection of sets
  6841. if(baseEdgeStencils.size()>0)
  6842. return baseEdgeStencils[0]; // return any of the possible base morphs
  6843. else if(edgeStencils.size()>0)
  6844. return edgeStencils[0]; // return any of the possible stencils
  6845. return null; //connection not possible
  6846. },
  6847. /**
  6848. * Return true if the stencil should be located in the shape menu
  6849. * @param {ORYX.Core.StencilSet.Stencil} morph
  6850. * @return {Boolean} Returns true if the morphs in the morph group of the
  6851. * specified morph shall be displayed in the shape menu
  6852. */
  6853. showInShapeMenu: function(stencil) {
  6854. return this._stencilSets.any(function(ss){
  6855. return ss.jsonRules().morphingRules
  6856. .any(function(r){
  6857. return stencil.roles().include(ss.namespace() + r.role)
  6858. && r.showInShapeMenu !== false;
  6859. })
  6860. });
  6861. },
  6862. preserveBounds: function(stencil) {
  6863. return this._stencilSets.any(function(ss) {
  6864. return ss.jsonRules().morphingRules.any(function(r) {
  6865. return stencil.roles().include(ss.namespace() + r.role)
  6866. && r.preserveBounds;
  6867. })
  6868. })
  6869. },
  6870. /** End morphing rules' methods */
  6871. /** Begin layouting rules' methods */
  6872. /**
  6873. * Returns a set on "in" and "out" layouting rules for a given shape
  6874. * @param {Object} shape
  6875. * @param {Object} edgeShape (Optional)
  6876. * @return {Object} "in" and "out" with a default value of {"t":1, "r":1, "b":1, "r":1} if not specified in the json
  6877. */
  6878. getLayoutingRules : function(shape, edgeShape){
  6879. if (!shape||!(shape instanceof ORYX.Core.Shape)){ return }
  6880. var layout = {"in":{},"out":{}};
  6881. var parseValues = function(o, v){
  6882. if (o && o[v]){
  6883. ["t","r","b","l"].each(function(d){
  6884. layout[v][d]=Math.max(o[v][d],layout[v][d]||0);
  6885. });
  6886. }
  6887. if (o && o[v+"s"] instanceof Array){
  6888. ["t","r","b","l"].each(function(d){
  6889. var defaultRule = o[v+"s"].find(function(e){ return !e.edgeRole });
  6890. var edgeRule;
  6891. if (edgeShape instanceof ORYX.Core.Edge) {
  6892. edgeRule = o[v + "s"].find(function(e){return this._hasRole(edgeShape, e.edgeRole) }.bind(this));
  6893. }
  6894. layout[v][d]=Math.max(edgeRule?edgeRule[d]:defaultRule[d],layout[v][d]||0);
  6895. }.bind(this));
  6896. }
  6897. }.bind(this)
  6898. // For each role
  6899. shape.getStencil().roles().each(function(role) {
  6900. // check if there are layout information
  6901. if (this._layoutRules[role]){
  6902. // if so, parse those information to the 'layout' variable
  6903. parseValues(this._layoutRules[role], "in");
  6904. parseValues(this._layoutRules[role], "out");
  6905. }
  6906. }.bind(this));
  6907. // Make sure, that every attribute has an value,
  6908. // otherwise set 1
  6909. ["in","out"].each(function(v){
  6910. ["t","r","b","l"].each(function(d){
  6911. layout[v][d]=layout[v][d]!==undefined?layout[v][d]:1;
  6912. });
  6913. })
  6914. return layout;
  6915. },
  6916. /** End layouting rules' methods */
  6917. /** Helper methods */
  6918. /**
  6919. * Checks wether a shape contains the given role or the role is equal the stencil id
  6920. * @param {ORYX.Core.Shape} shape
  6921. * @param {String} role
  6922. */
  6923. _hasRole: function(shape, role){
  6924. if (!(shape instanceof ORYX.Core.Shape)||!role){ return }
  6925. var isRole = shape.getStencil().roles().any(function(r){ return r == role});
  6926. return isRole || shape.getStencil().id() == (shape.getStencil().namespace()+role);
  6927. },
  6928. /**
  6929. *
  6930. * @param {String}
  6931. * role
  6932. *
  6933. * @return {Array} Returns an array of stencils that can act as role.
  6934. */
  6935. _stencilsWithRole: function(role) {
  6936. return this._stencils.findAll(function(stencil) {
  6937. return (stencil.roles().member(role)) ? true : false;
  6938. });
  6939. },
  6940. /**
  6941. *
  6942. * @param {String}
  6943. * role
  6944. *
  6945. * @return {Array} Returns an array of stencils that can act as role and
  6946. * have the type 'edge'.
  6947. */
  6948. _edgesWithRole: function(role) {
  6949. return this._stencils.findAll(function(stencil) {
  6950. return (stencil.roles().member(role) && stencil.type() === "edge") ? true : false;
  6951. });
  6952. },
  6953. /**
  6954. *
  6955. * @param {String}
  6956. * role
  6957. *
  6958. * @return {Array} Returns an array of stencils that can act as role and
  6959. * have the type 'node'.
  6960. */
  6961. _nodesWithRole: function(role) {
  6962. return this._stencils.findAll(function(stencil) {
  6963. return (stencil.roles().member(role) && stencil.type() === "node") ? true : false;
  6964. });
  6965. },
  6966. /**
  6967. *
  6968. * @param {ORYX.Core.StencilSet.Stencil}
  6969. * parent
  6970. * @param {ORYX.Core.StencilSet.Stencil}
  6971. * child
  6972. *
  6973. * @returns {Boolean} Returns the maximum occurrence of shapes of the
  6974. * stencil's type inside the parent.
  6975. */
  6976. _getMaximumOccurrence: function(parent, child) {
  6977. var max;
  6978. child.roles().each((function(role) {
  6979. var cardRule = this._cardinalityRules[role];
  6980. if(cardRule && cardRule.maximumOccurrence) {
  6981. if(max) {
  6982. max = Math.min(max, cardRule.maximumOccurrence);
  6983. } else {
  6984. max = cardRule.maximumOccurrence;
  6985. }
  6986. }
  6987. }).bind(this));
  6988. return max;
  6989. },
  6990. /**
  6991. *
  6992. * @param {Object}
  6993. * args sourceStencil: ORYX.Core.Node edgeStencil:
  6994. * ORYX.Core.StencilSet.Stencil
  6995. *
  6996. * @return {Boolean} Returns, the maximum number of outgoing edges of the
  6997. * type specified by edgeStencil of the sourceShape.
  6998. */
  6999. _getMaximumNumberOfOutgoingEdge: function(args) {
  7000. if(!args ||
  7001. !args.sourceStencil ||
  7002. !args.edgeStencil) {
  7003. return false;
  7004. }
  7005. var max;
  7006. args.sourceStencil.roles().each((function(role) {
  7007. var cardRule = this._cardinalityRules[role];
  7008. if(cardRule && cardRule.outgoingEdges) {
  7009. args.edgeStencil.roles().each(function(edgeRole) {
  7010. var oe = cardRule.outgoingEdges[edgeRole];
  7011. if(oe && oe.maximum) {
  7012. if(max) {
  7013. max = Math.min(max, oe.maximum);
  7014. } else {
  7015. max = oe.maximum;
  7016. }
  7017. }
  7018. });
  7019. }
  7020. }).bind(this));
  7021. return max;
  7022. },
  7023. /**
  7024. *
  7025. * @param {Object}
  7026. * args targetStencil: ORYX.Core.StencilSet.Stencil edgeStencil:
  7027. * ORYX.Core.StencilSet.Stencil
  7028. *
  7029. * @return {Boolean} Returns the maximum number of incoming edges of the
  7030. * type specified by edgeStencil of the targetShape.
  7031. */
  7032. _getMaximumNumberOfIncomingEdge: function(args) {
  7033. if(!args ||
  7034. !args.targetStencil ||
  7035. !args.edgeStencil) {
  7036. return false;
  7037. }
  7038. var max;
  7039. args.targetStencil.roles().each((function(role) {
  7040. var cardRule = this._cardinalityRules[role];
  7041. if(cardRule && cardRule.incomingEdges) {
  7042. args.edgeStencil.roles().each(function(edgeRole) {
  7043. var ie = cardRule.incomingEdges[edgeRole];
  7044. if(ie && ie.maximum) {
  7045. if(max) {
  7046. max = Math.min(max, ie.maximum);
  7047. } else {
  7048. max = ie.maximum;
  7049. }
  7050. }
  7051. });
  7052. }
  7053. }).bind(this));
  7054. return max;
  7055. },
  7056. /**
  7057. *
  7058. * @param {ORYX.Core.StencilSet.Stencil}
  7059. * edgeStencil
  7060. *
  7061. * @return {Hash} Returns a hash map of all connection rules for
  7062. * edgeStencil.
  7063. */
  7064. _getConnectionRulesOfEdgeStencil: function(edgeStencil) {
  7065. var edgeRules = new Hash();
  7066. edgeStencil.roles().each((function(role) {
  7067. if(this._connectionRules[role]) {
  7068. this._connectionRules[role].each(function(cr) {
  7069. if(edgeRules[cr.key]) {
  7070. edgeRules[cr.key] = edgeRules[cr.key].concat(cr.value);
  7071. } else {
  7072. edgeRules[cr.key] = cr.value;
  7073. }
  7074. });
  7075. }
  7076. }).bind(this));
  7077. return edgeRules;
  7078. },
  7079. _isRoleOfOtherNamespace: function(role) {
  7080. return (role.indexOf("#") > 0);
  7081. },
  7082. toString: function() { return "Rules"; }
  7083. }
  7084. ORYX.Core.StencilSet.Rules = Clazz.extend(ORYX.Core.StencilSet.Rules);
  7085. /**
  7086. * Copyright (c) 2006
  7087. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  7088. *
  7089. * Permission is hereby granted, free of charge, to any person obtaining a
  7090. * copy of this software and associated documentation files (the "Software"),
  7091. * to deal in the Software without restriction, including without limitation
  7092. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7093. * and/or sell copies of the Software, and to permit persons to whom the
  7094. * Software is furnished to do so, subject to the following conditions:
  7095. *
  7096. * The above copyright notice and this permission notice shall be included in
  7097. * all copies or substantial portions of the Software.
  7098. *
  7099. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7100. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7101. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  7102. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  7103. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  7104. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  7105. * DEALINGS IN THE SOFTWARE.
  7106. **/
  7107. /**
  7108. * Init namespace
  7109. */
  7110. if (!ORYX) {
  7111. var ORYX = {};
  7112. }
  7113. if (!ORYX.Core) {
  7114. ORYX.Core = {};
  7115. }
  7116. if (!ORYX.Core.StencilSet) {
  7117. ORYX.Core.StencilSet = {};
  7118. }
  7119. /**
  7120. * This class represents a stencil set. It offers methods for accessing
  7121. * the attributes of the stencil set description JSON file and the stencil set's
  7122. * stencils.
  7123. */
  7124. ORYX.Core.StencilSet.StencilSet = Clazz.extend({
  7125. /**
  7126. * Constructor
  7127. * @param source {URL} A reference to the stencil set specification.
  7128. *
  7129. */
  7130. construct: function(source){
  7131. arguments.callee.$.construct.apply(this, arguments);
  7132. if (!source) {
  7133. throw "ORYX.Core.StencilSet.StencilSet(construct): Parameter 'source' is not defined.";
  7134. }
  7135. if (source.endsWith("/")) {
  7136. source = source.substr(0, source.length - 1);
  7137. }
  7138. this._extensions = new Hash();
  7139. this._source = source;
  7140. this._baseUrl = source.substring(0, source.lastIndexOf("/") + 1);
  7141. this._jsonObject = {};
  7142. this._stencils = new Hash();
  7143. this._availableStencils = new Hash();
  7144. if(ORYX.CONFIG.BACKEND_SWITCH) {
  7145. this._baseUrl = "../editor/stencilsets/bpmn2.0/";
  7146. this._source = "../stencilsets/bpmn2.0/bpmn2.0.json";
  7147. new Ajax.Request("../service/editor/stencilset", {
  7148. asynchronous: false,
  7149. method: 'get',
  7150. onSuccess: this._init.bind(this),
  7151. onFailure: this._cancelInit.bind(this)
  7152. });
  7153. } else {
  7154. new Ajax.Request(source, {
  7155. asynchronous: false,
  7156. method: 'get',
  7157. onSuccess: this._init.bind(this),
  7158. onFailure: this._cancelInit.bind(this)
  7159. });
  7160. }
  7161. if (this.errornous)
  7162. throw "Loading stencil set " + source + " failed.";
  7163. },
  7164. /**
  7165. * Finds a root stencil in this stencil set. There may be many of these. If
  7166. * there are, the first one found will be used. In Firefox, this is the
  7167. * topmost definition in the stencil set description file.
  7168. */
  7169. findRootStencilName: function(){
  7170. // find any stencil that may be root.
  7171. var rootStencil = this._stencils.values().find(function(stencil){
  7172. return stencil._jsonStencil.mayBeRoot
  7173. });
  7174. // if there is none, just guess the first.
  7175. if (!rootStencil) {
  7176. ORYX.Log.warn("Did not find any stencil that may be root. Taking a guess.");
  7177. rootStencil = this._stencils.values()[0];
  7178. }
  7179. // return its id.
  7180. return rootStencil.id();
  7181. },
  7182. /**
  7183. * @param {ORYX.Core.StencilSet.StencilSet} stencilSet
  7184. * @return {Boolean} True, if stencil set has the same namespace.
  7185. */
  7186. equals: function(stencilSet){
  7187. return (this.namespace() === stencilSet.namespace());
  7188. },
  7189. /**
  7190. *
  7191. * @param {Oryx.Core.StencilSet.Stencil} rootStencil If rootStencil is defined, it only returns stencils
  7192. * that could be (in)direct child of that stencil.
  7193. */
  7194. stencils: function(rootStencil, rules, sortByGroup){
  7195. if(rootStencil && rules) {
  7196. var stencils = this._availableStencils.values();
  7197. var containers = [rootStencil];
  7198. var checkedContainers = [];
  7199. var result = [];
  7200. while (containers.size() > 0) {
  7201. var container = containers.pop();
  7202. checkedContainers.push(container);
  7203. var children = stencils.findAll(function(stencil){
  7204. var args = {
  7205. containingStencil: container,
  7206. containedStencil: stencil
  7207. };
  7208. return rules.canContain(args);
  7209. });
  7210. for(var i = 0; i < children.size(); i++) {
  7211. if (!checkedContainers.member(children[i])) {
  7212. containers.push(children[i]);
  7213. }
  7214. }
  7215. result = result.concat(children).uniq();
  7216. }
  7217. // Sort the result to the origin order
  7218. result = result.sortBy(function(stencil) {
  7219. return stencils.indexOf(stencil);
  7220. });
  7221. if(sortByGroup) {
  7222. result = result.sortBy(function(stencil) {
  7223. return stencil.groups().first();
  7224. });
  7225. }
  7226. var edges = stencils.findAll(function(stencil) {
  7227. return stencil.type() == "edge";
  7228. });
  7229. result = result.concat(edges);
  7230. return result;
  7231. } else {
  7232. if(sortByGroup) {
  7233. return this._availableStencils.values().sortBy(function(stencil) {
  7234. return stencil.groups().first();
  7235. });
  7236. } else {
  7237. return this._availableStencils.values();
  7238. }
  7239. }
  7240. },
  7241. nodes: function(){
  7242. return this._availableStencils.values().findAll(function(stencil){
  7243. return (stencil.type() === 'node')
  7244. });
  7245. },
  7246. edges: function(){
  7247. return this._availableStencils.values().findAll(function(stencil){
  7248. return (stencil.type() === 'edge')
  7249. });
  7250. },
  7251. stencil: function(id){
  7252. return this._stencils[id];
  7253. },
  7254. title: function(){
  7255. return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "title");
  7256. },
  7257. description: function(){
  7258. return ORYX.Core.StencilSet.getTranslation(this._jsonObject, "description");
  7259. },
  7260. namespace: function(){
  7261. return this._jsonObject ? this._jsonObject.namespace : null;
  7262. },
  7263. jsonRules: function(){
  7264. return this._jsonObject ? this._jsonObject.rules : null;
  7265. },
  7266. source: function(){
  7267. return this._source;
  7268. },
  7269. extensions: function() {
  7270. return this._extensions;
  7271. },
  7272. addExtension: function(url) {
  7273. new Ajax.Request(url, {
  7274. method: 'GET',
  7275. asynchronous: false,
  7276. onSuccess: (function(transport) {
  7277. this.addExtensionDirectly(transport.responseText);
  7278. }).bind(this),
  7279. onFailure: (function(transport) {
  7280. ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport);
  7281. }).bind(this),
  7282. onException: (function(transport) {
  7283. ORYX.Log.debug("Loading stencil set extension file failed. The request returned an error." + transport);
  7284. }).bind(this)
  7285. });
  7286. },
  7287. addExtensionDirectly: function(str){
  7288. try {
  7289. eval("var jsonExtension = " + str);
  7290. if(!(jsonExtension["extends"].endsWith("#")))
  7291. jsonExtension["extends"] += "#";
  7292. if(jsonExtension["extends"] == this.namespace()) {
  7293. this._extensions[jsonExtension.namespace] = jsonExtension;
  7294. var defaultPosition = this._stencils.keys().size();
  7295. //load new stencils
  7296. if(jsonExtension.stencils) {
  7297. $A(jsonExtension.stencils).each(function(stencil) {
  7298. defaultPosition++;
  7299. var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, undefined, defaultPosition);
  7300. this._stencils[oStencil.id()] = oStencil;
  7301. this._availableStencils[oStencil.id()] = oStencil;
  7302. }.bind(this));
  7303. }
  7304. //load additional properties
  7305. if (jsonExtension.properties) {
  7306. var stencils = this._stencils.values();
  7307. stencils.each(function(stencil){
  7308. var roles = stencil.roles();
  7309. jsonExtension.properties.each(function(prop){
  7310. prop.roles.any(function(role){
  7311. role = jsonExtension["extends"] + role;
  7312. if (roles.member(role)) {
  7313. prop.properties.each(function(property){
  7314. stencil.addProperty(property, jsonExtension.namespace);
  7315. });
  7316. return true;
  7317. }
  7318. else
  7319. return false;
  7320. })
  7321. })
  7322. }.bind(this));
  7323. }
  7324. //remove stencil properties
  7325. if(jsonExtension.removeproperties) {
  7326. jsonExtension.removeproperties.each(function(remprop) {
  7327. var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil);
  7328. if(stencil) {
  7329. remprop.properties.each(function(propId) {
  7330. stencil.removeProperty(propId);
  7331. });
  7332. }
  7333. }.bind(this));
  7334. }
  7335. //remove stencils
  7336. if(jsonExtension.removestencils) {
  7337. $A(jsonExtension.removestencils).each(function(remstencil) {
  7338. delete this._availableStencils[jsonExtension["extends"] + remstencil];
  7339. }.bind(this));
  7340. }
  7341. }
  7342. } catch (e) {
  7343. ORYX.Log.debug("StencilSet.addExtension: Something went wrong when initialising the stencil set extension. " + e);
  7344. }
  7345. },
  7346. removeExtension: function(namespace) {
  7347. var jsonExtension = this._extensions[namespace];
  7348. if(jsonExtension) {
  7349. //unload extension's stencils
  7350. if(jsonExtension.stencils) {
  7351. $A(jsonExtension.stencils).each(function(stencil) {
  7352. var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this);
  7353. delete this._stencils[oStencil.id()]; // maybe not ??
  7354. delete this._availableStencils[oStencil.id()];
  7355. }.bind(this));
  7356. }
  7357. //unload extension's properties
  7358. if (jsonExtension.properties) {
  7359. var stencils = this._stencils.values();
  7360. stencils.each(function(stencil){
  7361. var roles = stencil.roles();
  7362. jsonExtension.properties.each(function(prop){
  7363. prop.roles.any(function(role){
  7364. role = jsonExtension["extends"] + role;
  7365. if (roles.member(role)) {
  7366. prop.properties.each(function(property){
  7367. stencil.removeProperty(property.id);
  7368. });
  7369. return true;
  7370. }
  7371. else
  7372. return false;
  7373. })
  7374. })
  7375. }.bind(this));
  7376. }
  7377. //restore removed stencil properties
  7378. if(jsonExtension.removeproperties) {
  7379. jsonExtension.removeproperties.each(function(remprop) {
  7380. var stencil = this.stencil(jsonExtension["extends"] + remprop.stencil);
  7381. if(stencil) {
  7382. var stencilJson = $A(this._jsonObject.stencils).find(function(s) { return s.id == stencil.id() });
  7383. remprop.properties.each(function(propId) {
  7384. var propertyJson = $A(stencilJson.properties).find(function(p) { return p.id == propId });
  7385. stencil.addProperty(propertyJson, this.namespace());
  7386. }.bind(this));
  7387. }
  7388. }.bind(this));
  7389. }
  7390. //restore removed stencils
  7391. if(jsonExtension.removestencils) {
  7392. $A(jsonExtension.removestencils).each(function(remstencil) {
  7393. var sId = jsonExtension["extends"] + remstencil;
  7394. this._availableStencils[sId] = this._stencils[sId];
  7395. }.bind(this));
  7396. }
  7397. }
  7398. delete this._extensions[namespace];
  7399. },
  7400. __handleStencilset: function(response){
  7401. try {
  7402. // using eval instead of prototype's parsing,
  7403. // since there are functions in this JSON.
  7404. eval("this._jsonObject =" + response.responseText);
  7405. }
  7406. catch (e) {
  7407. throw "Stenciset corrupt: " + e;
  7408. }
  7409. // assert it was parsed.
  7410. if (!this._jsonObject) {
  7411. throw "Error evaluating stencilset. It may be corrupt.";
  7412. }
  7413. with (this._jsonObject) {
  7414. // assert there is a namespace.
  7415. if (!namespace || namespace === "")
  7416. throw "Namespace definition missing in stencilset.";
  7417. if (!(stencils instanceof Array))
  7418. throw "Stencilset corrupt.";
  7419. // assert namespace ends with '#'.
  7420. if (!namespace.endsWith("#"))
  7421. namespace = namespace + "#";
  7422. // assert title and description are strings.
  7423. if (!title)
  7424. title = "";
  7425. if (!description)
  7426. description = "";
  7427. }
  7428. },
  7429. /**
  7430. * This method is called when the HTTP request to get the requested stencil
  7431. * set succeeds. The response is supposed to be a JSON representation
  7432. * according to the stencil set specification.
  7433. * @param {Object} response The JSON representation according to the
  7434. * stencil set specification.
  7435. */
  7436. _init: function(response){
  7437. // init and check consistency.
  7438. this.__handleStencilset(response);
  7439. var pps = new Hash();
  7440. // init property packages
  7441. if(this._jsonObject.propertyPackages) {
  7442. $A(this._jsonObject.propertyPackages).each((function(pp) {
  7443. pps[pp.name] = pp.properties;
  7444. }).bind(this));
  7445. }
  7446. var defaultPosition = 0;
  7447. // init each stencil
  7448. $A(this._jsonObject.stencils).each((function(stencil){
  7449. defaultPosition++;
  7450. // instantiate normally.
  7451. var oStencil = new ORYX.Core.StencilSet.Stencil(stencil, this.namespace(), this._baseUrl, this, pps, defaultPosition);
  7452. this._stencils[oStencil.id()] = oStencil;
  7453. this._availableStencils[oStencil.id()] = oStencil;
  7454. }).bind(this));
  7455. },
  7456. _cancelInit: function(response){
  7457. this.errornous = true;
  7458. },
  7459. toString: function(){
  7460. return "StencilSet " + this.title() + " (" + this.namespace() + ")";
  7461. }
  7462. });
  7463. /**
  7464. * Copyright (c) 2006
  7465. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  7466. *
  7467. * Permission is hereby granted, free of charge, to any person obtaining a
  7468. * copy of this software and associated documentation files (the "Software"),
  7469. * to deal in the Software without restriction, including without limitation
  7470. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7471. * and/or sell copies of the Software, and to permit persons to whom the
  7472. * Software is furnished to do so, subject to the following conditions:
  7473. *
  7474. * The above copyright notice and this permission notice shall be included in
  7475. * all copies or substantial portions of the Software.
  7476. *
  7477. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7478. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7479. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  7480. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  7481. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  7482. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  7483. * DEALINGS IN THE SOFTWARE.
  7484. **/
  7485. /**
  7486. * Init namespace
  7487. */
  7488. if(!ORYX) {var ORYX = {};}
  7489. if(!ORYX.Core) {ORYX.Core = {};}
  7490. if(!ORYX.Core.StencilSet) {ORYX.Core.StencilSet = {};}
  7491. /**
  7492. * Class StencilSets
  7493. * uses Prototpye 1.5.0
  7494. * uses Inheritance
  7495. *
  7496. * Singleton
  7497. */
  7498. //storage for loaded stencil sets by namespace
  7499. ORYX.Core.StencilSet._stencilSetsByNamespace = new Hash();
  7500. //storage for stencil sets by url
  7501. ORYX.Core.StencilSet._stencilSetsByUrl = new Hash();
  7502. //storage for stencil set namespaces by editor instances
  7503. ORYX.Core.StencilSet._StencilSetNSByEditorInstance = new Hash();
  7504. //storage for rules by editor instances
  7505. ORYX.Core.StencilSet._rulesByEditorInstance = new Hash();
  7506. /**
  7507. *
  7508. * @param {String} editorId
  7509. *
  7510. * @return {Hash} Returns a hash map with all stencil sets that are loaded by
  7511. * the editor with the editorId.
  7512. */
  7513. ORYX.Core.StencilSet.stencilSets = function(editorId) {
  7514. var stencilSetNSs = ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId];
  7515. var stencilSets = new Hash();
  7516. if(stencilSetNSs) {
  7517. stencilSetNSs.each(function(stencilSetNS) {
  7518. var stencilSet = ORYX.Core.StencilSet.stencilSet(stencilSetNS)
  7519. stencilSets[stencilSet.namespace()] = stencilSet;
  7520. });
  7521. }
  7522. return stencilSets;
  7523. };
  7524. /**
  7525. *
  7526. * @param {String} namespace
  7527. *
  7528. * @return {ORYX.Core.StencilSet.StencilSet} Returns the stencil set with the specified
  7529. * namespace.
  7530. *
  7531. * The method can handle namespace strings like
  7532. * http://www.example.org/stencilset
  7533. * http://www.example.org/stencilset#
  7534. * http://www.example.org/stencilset#ANode
  7535. */
  7536. ORYX.Core.StencilSet.stencilSet = function(namespace) {
  7537. ORYX.Log.trace("Getting stencil set %0", namespace);
  7538. var splitted = namespace.split("#", 1);
  7539. if(splitted.length === 1) {
  7540. ORYX.Log.trace("Getting stencil set %0", splitted[0]);
  7541. return ORYX.Core.StencilSet._stencilSetsByNamespace[splitted[0] + "#"];
  7542. } else {
  7543. return undefined;
  7544. }
  7545. };
  7546. /**
  7547. *
  7548. * @param {String} id
  7549. *
  7550. * @return {ORYX.Core.StencilSet.Stencil} Returns the stencil specified by the id.
  7551. *
  7552. * The id must be unique and contains the namespace of the stencil's stencil set.
  7553. * e.g. http://www.example.org/stencilset#ANode
  7554. */
  7555. ORYX.Core.StencilSet.stencil = function(id) {
  7556. ORYX.Log.trace("Getting stencil for %0", id);
  7557. var ss = ORYX.Core.StencilSet.stencilSet(id);
  7558. if(ss) {
  7559. return ss.stencil(id);
  7560. } else {
  7561. ORYX.Log.trace("Cannot fild stencil for %0", id);
  7562. return undefined;
  7563. }
  7564. };
  7565. /**
  7566. *
  7567. * @param {String} editorId
  7568. *
  7569. * @return {ORYX.Core.StencilSet.Rules} Returns the rules object for the editor
  7570. * specified by its editor id.
  7571. */
  7572. ORYX.Core.StencilSet.rules = function(editorId) {
  7573. if(!ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) {
  7574. ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = new ORYX.Core.StencilSet.Rules();;
  7575. }
  7576. return ORYX.Core.StencilSet._rulesByEditorInstance[editorId];
  7577. };
  7578. /**
  7579. *
  7580. * @param {String} url
  7581. * @param {String} editorId
  7582. *
  7583. * Loads a stencil set from url, if it is not already loaded.
  7584. * It also stores which editor instance loads the stencil set and
  7585. * initializes the Rules object for the editor instance.
  7586. */
  7587. ORYX.Core.StencilSet.loadStencilSet = function(url, editorId) {
  7588. var stencilSet = ORYX.Core.StencilSet._stencilSetsByUrl[url];
  7589. if(!stencilSet) {
  7590. //load stencil set
  7591. stencilSet = new ORYX.Core.StencilSet.StencilSet(url);
  7592. //store stencil set
  7593. ORYX.Core.StencilSet._stencilSetsByNamespace[stencilSet.namespace()] = stencilSet;
  7594. //store stencil set by url
  7595. ORYX.Core.StencilSet._stencilSetsByUrl[url] = stencilSet;
  7596. }
  7597. var namespace = stencilSet.namespace();
  7598. //store which editorInstance loads the stencil set
  7599. if(ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId]) {
  7600. ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId].push(namespace);
  7601. } else {
  7602. ORYX.Core.StencilSet._StencilSetNSByEditorInstance[editorId] = [namespace];
  7603. }
  7604. //store the rules for the editor instance
  7605. if(ORYX.Core.StencilSet._rulesByEditorInstance[editorId]) {
  7606. ORYX.Core.StencilSet._rulesByEditorInstance[editorId].initializeRules(stencilSet);
  7607. } else {
  7608. var rules = new ORYX.Core.StencilSet.Rules();
  7609. rules.initializeRules(stencilSet);
  7610. ORYX.Core.StencilSet._rulesByEditorInstance[editorId] = rules;
  7611. }
  7612. };
  7613. /**
  7614. * Returns the translation of an attribute in jsonObject specified by its name
  7615. * according to navigator.language
  7616. */
  7617. ORYX.Core.StencilSet.getTranslation = function(jsonObject, name) {
  7618. var lang = ORYX.I18N.Language.toLowerCase();
  7619. var result = jsonObject[name + "_" + lang];
  7620. if(result)
  7621. return result;
  7622. result = jsonObject[name + "_" + lang.substr(0, 2)];
  7623. if(result)
  7624. return result;
  7625. return jsonObject[name];
  7626. };
  7627. /**
  7628. * Copyright (c) 2006
  7629. * Willi Tscheschner
  7630. *
  7631. * Permission is hereby granted, free of charge, to any person obtaining a
  7632. * copy of this software and associated documentation files (the "Software"),
  7633. * to deal in the Software without restriction, including without limitation
  7634. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7635. * and/or sell copies of the Software, and to permit persons to whom the
  7636. * Software is furnished to do so, subject to the following conditions:
  7637. *
  7638. * The above copyright notice and this permission notice shall be included in
  7639. * all copies or substantial portions of the Software.
  7640. *
  7641. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7642. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7643. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  7644. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  7645. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  7646. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  7647. * DEALINGS IN THE SOFTWARE.
  7648. **/
  7649. /**
  7650. * Init namespaces
  7651. */
  7652. if(!ORYX) {var ORYX = {};}
  7653. if(!ORYX.Core) {ORYX.Core = {};}
  7654. /**
  7655. * @classDescription With Bounds you can set and get position and size of UIObjects.
  7656. */
  7657. ORYX.Core.Command = Clazz.extend({
  7658. /**
  7659. * Constructor
  7660. */
  7661. construct: function() {
  7662. },
  7663. execute: function(){
  7664. throw "Command.execute() has to be implemented!"
  7665. },
  7666. rollback: function(){
  7667. throw "Command.rollback() has to be implemented!"
  7668. }
  7669. });/**
  7670. * Copyright (c) 2006
  7671. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  7672. *
  7673. * Permission is hereby granted, free of charge, to any person obtaining a
  7674. * copy of this software and associated documentation files (the "Software"),
  7675. * to deal in the Software without restriction, including without limitation
  7676. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  7677. * and/or sell copies of the Software, and to permit persons to whom the
  7678. * Software is furnished to do so, subject to the following conditions:
  7679. *
  7680. * The above copyright notice and this permission notice shall be included in
  7681. * all copies or substantial portions of the Software.
  7682. *
  7683. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  7684. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  7685. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  7686. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  7687. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  7688. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  7689. * DEALINGS IN THE SOFTWARE.
  7690. **/
  7691. /**
  7692. * Init namespaces
  7693. */
  7694. if(!ORYX) {var ORYX = {};}
  7695. if(!ORYX.Core) {ORYX.Core = {};}
  7696. /**
  7697. * @classDescription With Bounds you can set and get position and size of UIObjects.
  7698. */
  7699. ORYX.Core.Bounds = {
  7700. /**
  7701. * Constructor
  7702. */
  7703. construct: function() {
  7704. this._changedCallbacks = []; //register a callback with changedCallacks.push(this.method.bind(this));
  7705. this.a = {};
  7706. this.b = {};
  7707. this.set.apply(this, arguments);
  7708. this.suspendChange = false;
  7709. this.changedWhileSuspend = false;
  7710. },
  7711. /**
  7712. * Calls all registered callbacks.
  7713. */
  7714. _changed: function(sizeChanged) {
  7715. if(!this.suspendChange) {
  7716. this._changedCallbacks.each(function(callback) {
  7717. callback(this, sizeChanged);
  7718. }.bind(this));
  7719. this.changedWhileSuspend = false;
  7720. } else
  7721. this.changedWhileSuspend = true;
  7722. },
  7723. /**
  7724. * Registers a callback that is called, if the bounds changes.
  7725. * @param callback {Function} The callback function.
  7726. */
  7727. registerCallback: function(callback) {
  7728. if(!this._changedCallbacks.member(callback)) {
  7729. this._changedCallbacks.push(callback);
  7730. }
  7731. },
  7732. /**
  7733. * Unregisters a callback.
  7734. * @param callback {Function} The callback function.
  7735. */
  7736. unregisterCallback: function(callback) {
  7737. this._changedCallbacks = this._changedCallbacks.without(callback);
  7738. },
  7739. /**
  7740. * Sets position and size of the shape dependent of four coordinates
  7741. * (set(ax, ay, bx, by);), two points (set({x: ax, y: ay}, {x: bx, y: by});)
  7742. * or one bound (set({a: {x: ax, y: ay}, b: {x: bx, y: by}});).
  7743. */
  7744. set: function() {
  7745. var changed = false;
  7746. switch (arguments.length) {
  7747. case 1:
  7748. if(this.a.x !== arguments[0].a.x) {
  7749. changed = true;
  7750. this.a.x = arguments[0].a.x;
  7751. }
  7752. if(this.a.y !== arguments[0].a.y) {
  7753. changed = true;
  7754. this.a.y = arguments[0].a.y;
  7755. }
  7756. if(this.b.x !== arguments[0].b.x) {
  7757. changed = true;
  7758. this.b.x = arguments[0].b.x;
  7759. }
  7760. if(this.b.y !== arguments[0].b.y) {
  7761. changed = true;
  7762. this.b.y = arguments[0].b.y;
  7763. }
  7764. break;
  7765. case 2:
  7766. var ax = Math.min(arguments[0].x, arguments[1].x);
  7767. var ay = Math.min(arguments[0].y, arguments[1].y);
  7768. var bx = Math.max(arguments[0].x, arguments[1].x);
  7769. var by = Math.max(arguments[0].y, arguments[1].y);
  7770. if(this.a.x !== ax) {
  7771. changed = true;
  7772. this.a.x = ax;
  7773. }
  7774. if(this.a.y !== ay) {
  7775. changed = true;
  7776. this.a.y = ay;
  7777. }
  7778. if(this.b.x !== bx) {
  7779. changed = true;
  7780. this.b.x = bx;
  7781. }
  7782. if(this.b.y !== by) {
  7783. changed = true;
  7784. this.b.y = by;
  7785. }
  7786. break;
  7787. case 4:
  7788. var ax = Math.min(arguments[0], arguments[2]);
  7789. var ay = Math.min(arguments[1], arguments[3]);
  7790. var bx = Math.max(arguments[0], arguments[2]);
  7791. var by = Math.max(arguments[1], arguments[3]);
  7792. if(this.a.x !== ax) {
  7793. changed = true;
  7794. this.a.x = ax;
  7795. }
  7796. if(this.a.y !== ay) {
  7797. changed = true;
  7798. this.a.y = ay;
  7799. }
  7800. if(this.b.x !== bx) {
  7801. changed = true;
  7802. this.b.x = bx;
  7803. }
  7804. if(this.b.y !== by) {
  7805. changed = true;
  7806. this.b.y = by;
  7807. }
  7808. break;
  7809. }
  7810. if(changed) {
  7811. this._changed(true);
  7812. }
  7813. },
  7814. /**
  7815. * Moves the bounds so that the point p will be the new upper left corner.
  7816. * @param {Point} p
  7817. * or
  7818. * @param {Number} x
  7819. * @param {Number} y
  7820. */
  7821. moveTo: function() {
  7822. var currentPosition = this.upperLeft();
  7823. switch (arguments.length) {
  7824. case 1:
  7825. this.moveBy({
  7826. x: arguments[0].x - currentPosition.x,
  7827. y: arguments[0].y - currentPosition.y
  7828. });
  7829. break;
  7830. case 2:
  7831. this.moveBy({
  7832. x: arguments[0] - currentPosition.x,
  7833. y: arguments[1] - currentPosition.y
  7834. });
  7835. break;
  7836. default:
  7837. //TODO error
  7838. }
  7839. },
  7840. /**
  7841. * Moves the bounds relatively by p.
  7842. * @param {Point} p
  7843. * or
  7844. * @param {Number} x
  7845. * @param {Number} y
  7846. *
  7847. */
  7848. moveBy: function() {
  7849. var changed = false;
  7850. switch (arguments.length) {
  7851. case 1:
  7852. var p = arguments[0];
  7853. if(p.x !== 0 || p.y !== 0) {
  7854. changed = true;
  7855. this.a.x += p.x;
  7856. this.b.x += p.x;
  7857. this.a.y += p.y;
  7858. this.b.y += p.y;
  7859. }
  7860. break;
  7861. case 2:
  7862. var x = arguments[0];
  7863. var y = arguments[1];
  7864. if(x !== 0 || y !== 0) {
  7865. changed = true;
  7866. this.a.x += x;
  7867. this.b.x += x;
  7868. this.a.y += y;
  7869. this.b.y += y;
  7870. }
  7871. break;
  7872. default:
  7873. //TODO error
  7874. }
  7875. if(changed) {
  7876. this._changed();
  7877. }
  7878. },
  7879. /***
  7880. * Includes the bounds b into the current bounds.
  7881. * @param {Bounds} b
  7882. */
  7883. include: function(b) {
  7884. if( (this.a.x === undefined) && (this.a.y === undefined) &&
  7885. (this.b.x === undefined) && (this.b.y === undefined)) {
  7886. return b;
  7887. };
  7888. var cx = Math.min(this.a.x,b.a.x);
  7889. var cy = Math.min(this.a.y,b.a.y);
  7890. var dx = Math.max(this.b.x,b.b.x);
  7891. var dy = Math.max(this.b.y,b.b.y);
  7892. this.set(cx, cy, dx, dy);
  7893. },
  7894. /**
  7895. * Relatively extends the bounds by p.
  7896. * @param {Point} p
  7897. */
  7898. extend: function(p) {
  7899. if(p.x !== 0 || p.y !== 0) {
  7900. // this is over cross for the case that a and b have same coordinates.
  7901. //((this.a.x > this.b.x) ? this.a : this.b).x += p.x;
  7902. //((this.b.y > this.a.y) ? this.b : this.a).y += p.y;
  7903. this.b.x += p.x;
  7904. this.b.y += p.y;
  7905. this._changed(true);
  7906. }
  7907. },
  7908. /**
  7909. * Widens the scope of the bounds by x.
  7910. * @param {Number} x
  7911. */
  7912. widen: function(x) {
  7913. if (x !== 0) {
  7914. this.suspendChange = true;
  7915. this.moveBy({x: -x, y: -x});
  7916. this.extend({x: 2*x, y: 2*x});
  7917. this.suspendChange = false;
  7918. if(this.changedWhileSuspend) {
  7919. this._changed(true);
  7920. }
  7921. }
  7922. },
  7923. /**
  7924. * Returns the upper left corner's point regardless of the
  7925. * bound delimiter points.
  7926. */
  7927. upperLeft: function() {
  7928. return {x:this.a.x, y:this.a.y};
  7929. },
  7930. /**
  7931. * Returns the lower Right left corner's point regardless of the
  7932. * bound delimiter points.
  7933. */
  7934. lowerRight: function() {
  7935. return {x:this.b.x, y:this.b.y};
  7936. },
  7937. /**
  7938. * @return {Number} Width of bounds.
  7939. */
  7940. width: function() {
  7941. return this.b.x - this.a.x;
  7942. },
  7943. /**
  7944. * @return {Number} Height of bounds.
  7945. */
  7946. height: function() {
  7947. return this.b.y - this.a.y;
  7948. },
  7949. /**
  7950. * @return {Point} The center point of this bounds.
  7951. */
  7952. center: function() {
  7953. return {
  7954. x: (this.a.x + this.b.x)/2.0,
  7955. y: (this.a.y + this.b.y)/2.0
  7956. };
  7957. },
  7958. /**
  7959. * @return {Point} The center point of this bounds relative to upperLeft.
  7960. */
  7961. midPoint: function() {
  7962. return {
  7963. x: (this.b.x - this.a.x)/2.0,
  7964. y: (this.b.y - this.a.y)/2.0
  7965. };
  7966. },
  7967. /**
  7968. * Moves the center point of this bounds to the new position.
  7969. * @param p {Point}
  7970. * or
  7971. * @param x {Number}
  7972. * @param y {Number}
  7973. */
  7974. centerMoveTo: function() {
  7975. var currentPosition = this.center();
  7976. switch (arguments.length) {
  7977. case 1:
  7978. this.moveBy(arguments[0].x - currentPosition.x,
  7979. arguments[0].y - currentPosition.y);
  7980. break;
  7981. case 2:
  7982. this.moveBy(arguments[0] - currentPosition.x,
  7983. arguments[1] - currentPosition.y);
  7984. break;
  7985. }
  7986. },
  7987. isIncluded: function(point, offset) {
  7988. var pointX, pointY, offset;
  7989. // Get the the two Points
  7990. switch(arguments.length) {
  7991. case 1:
  7992. pointX = arguments[0].x;
  7993. pointY = arguments[0].y;
  7994. offset = 0;
  7995. break;
  7996. case 2:
  7997. if(arguments[0].x && arguments[0].y) {
  7998. pointX = arguments[0].x;
  7999. pointY = arguments[0].y;
  8000. offset = Math.abs(arguments[1]);
  8001. } else {
  8002. pointX = arguments[0];
  8003. pointY = arguments[1];
  8004. offset = 0;
  8005. }
  8006. break;
  8007. case 3:
  8008. pointX = arguments[0];
  8009. pointY = arguments[1];
  8010. offset = Math.abs(arguments[2]);
  8011. break;
  8012. default:
  8013. throw "isIncluded needs one, two or three arguments";
  8014. }
  8015. var ul = this.upperLeft();
  8016. var lr = this.lowerRight();
  8017. if(pointX >= ul.x - offset
  8018. && pointX <= lr.x + offset && pointY >= ul.y - offset
  8019. && pointY <= lr.y + offset)
  8020. return true;
  8021. else
  8022. return false;
  8023. },
  8024. /**
  8025. * @return {Bounds} A copy of this bounds.
  8026. */
  8027. clone: function() {
  8028. //Returns a new bounds object without the callback
  8029. // references of the original bounds
  8030. return new ORYX.Core.Bounds(this);
  8031. },
  8032. toString: function() {
  8033. return "( "+this.a.x+" | "+this.a.y+" )/( "+this.b.x+" | "+this.b.y+" )";
  8034. },
  8035. serializeForERDF: function() {
  8036. return this.a.x+","+this.a.y+","+this.b.x+","+this.b.y;
  8037. }
  8038. };
  8039. ORYX.Core.Bounds = Clazz.extend(ORYX.Core.Bounds);/**
  8040. * Copyright (c) 2006
  8041. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  8042. *
  8043. * Permission is hereby granted, free of charge, to any person obtaining a
  8044. * copy of this software and associated documentation files (the "Software"),
  8045. * to deal in the Software without restriction, including without limitation
  8046. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8047. * and/or sell copies of the Software, and to permit persons to whom the
  8048. * Software is furnished to do so, subject to the following conditions:
  8049. *
  8050. * The above copyright notice and this permission notice shall be included in
  8051. * all copies or substantial portions of the Software.
  8052. *
  8053. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  8054. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  8055. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8056. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  8057. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  8058. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  8059. * DEALINGS IN THE SOFTWARE.
  8060. **/
  8061. /**
  8062. * Init namespaces
  8063. */
  8064. if(!ORYX) {var ORYX = {};}
  8065. if(!ORYX.Core) {ORYX.Core = {};}
  8066. /**
  8067. * @classDescription Abstract base class for all objects that have a graphical representation
  8068. * within the editor.
  8069. * @extends Clazz
  8070. */
  8071. ORYX.Core.UIObject = {
  8072. /**
  8073. * Constructor of the UIObject class.
  8074. */
  8075. construct: function(options) {
  8076. this.isChanged = true; //Flag, if UIObject has been changed since last update.
  8077. this.isResized = true;
  8078. this.isVisible = true; //Flag, if UIObject's display attribute is set to 'inherit' or 'none'
  8079. this.isSelectable = false; //Flag, if UIObject is selectable.
  8080. this.isResizable = false; //Flag, if UIObject is resizable.
  8081. this.isMovable = false; //Flag, if UIObject is movable.
  8082. this.id = ORYX.Editor.provideId(); //get unique id
  8083. this.parent = undefined; //parent is defined, if this object is added to another uiObject.
  8084. this.node = undefined; //this is a reference to the SVG representation, either locally or in DOM.
  8085. this.children = []; //array for all add uiObjects
  8086. this.bounds = new ORYX.Core.Bounds(); //bounds with undefined values
  8087. this._changedCallback = this._changed.bind(this); //callback reference for calling _changed
  8088. this.bounds.registerCallback(this._changedCallback); //set callback in bounds
  8089. if(options && options.eventHandlerCallback) {
  8090. this.eventHandlerCallback = options.eventHandlerCallback;
  8091. }
  8092. },
  8093. /**
  8094. * Sets isChanged flag to true. Callback for the bounds object.
  8095. */
  8096. _changed: function(bounds, isResized) {
  8097. this.isChanged = true;
  8098. if(this.bounds == bounds)
  8099. this.isResized = isResized || this.isResized;
  8100. },
  8101. /**
  8102. * If something changed, this method calls the refresh method that must be implemented by subclasses.
  8103. */
  8104. update: function() {
  8105. if(this.isChanged) {
  8106. this.refresh();
  8107. this.isChanged = false;
  8108. //call update of all children
  8109. this.children.each(function(value) {
  8110. value.update();
  8111. });
  8112. }
  8113. },
  8114. /**
  8115. * Is called in update method, if isChanged is set to true. Sub classes should call the super class method.
  8116. */
  8117. refresh: function() {
  8118. },
  8119. /**
  8120. * @return {Array} Array of all child UIObjects.
  8121. */
  8122. getChildren: function() {
  8123. return this.children.clone();
  8124. },
  8125. /**
  8126. * @return {Array} Array of all parent UIObjects.
  8127. */
  8128. getParents: function(){
  8129. var parents = [];
  8130. var parent = this.parent;
  8131. while(parent){
  8132. parents.push(parent);
  8133. parent = parent.parent;
  8134. }
  8135. return parents;
  8136. },
  8137. /**
  8138. * Returns TRUE if the given parent is one of the UIObjects parents or the UIObject themselves, otherwise FALSE.
  8139. * @param {UIObject} parent
  8140. * @return {Boolean}
  8141. */
  8142. isParent: function(parent){
  8143. var cparent = this;
  8144. while(cparent){
  8145. if (cparent === parent){
  8146. return true;
  8147. }
  8148. cparent = cparent.parent;
  8149. }
  8150. return false;
  8151. },
  8152. /**
  8153. * @return {String} Id of this UIObject
  8154. */
  8155. getId: function() {
  8156. return this.id;
  8157. },
  8158. /**
  8159. * Method for accessing child uiObjects by id.
  8160. * @param {String} id
  8161. * @param {Boolean} deep
  8162. *
  8163. * @return {UIObject} If found, it returns the UIObject with id.
  8164. */
  8165. getChildById: function(id, deep) {
  8166. return this.children.find(function(uiObj) {
  8167. if(uiObj.getId() === id) {
  8168. return uiObj;
  8169. } else {
  8170. if(deep) {
  8171. var obj = uiObj.getChildById(id, deep);
  8172. if(obj) {
  8173. return obj;
  8174. }
  8175. }
  8176. }
  8177. });
  8178. },
  8179. /**
  8180. * Adds an UIObject to this UIObject and sets the parent of the
  8181. * added UIObject. It is also added to the SVG representation of this
  8182. * UIObject.
  8183. * @param {UIObject} uiObject
  8184. */
  8185. add: function(uiObject) {
  8186. //add uiObject, if it is not already a child of this object
  8187. if (!(this.children.member(uiObject))) {
  8188. //if uiObject is child of another parent, remove it from that parent.
  8189. if(uiObject.parent) {
  8190. uiObject.remove(uiObject);
  8191. }
  8192. //add uiObject to children
  8193. this.children.push(uiObject);
  8194. //set parent reference
  8195. uiObject.parent = this;
  8196. //add uiObject.node to this.node
  8197. uiObject.node = this.node.appendChild(uiObject.node);
  8198. //register callback to get informed, if child is changed
  8199. uiObject.bounds.registerCallback(this._changedCallback);
  8200. //uiObject.update();
  8201. } else {
  8202. ORYX.Log.info("add: ORYX.Core.UIObject is already a child of this object.");
  8203. }
  8204. },
  8205. /**
  8206. * Removes UIObject from this UIObject. The SVG representation will also
  8207. * be removed from this UIObject's SVG representation.
  8208. * @param {UIObject} uiObject
  8209. */
  8210. remove: function(uiObject) {
  8211. //if uiObject is a child of this object, remove it.
  8212. if (this.children.member(uiObject)) {
  8213. //remove uiObject from children
  8214. this.children = this._uiObjects.without(uiObject);
  8215. //delete parent reference of uiObject
  8216. uiObject.parent = undefined;
  8217. //delete uiObject.node from this.node
  8218. uiObject.node = this.node.removeChild(uiObject.node);
  8219. //unregister callback to get informed, if child is changed
  8220. uiObject.bounds.unregisterCallback(this._changedCallback);
  8221. } else {
  8222. ORYX.Log.info("remove: ORYX.Core.UIObject is not a child of this object.");
  8223. }
  8224. },
  8225. /**
  8226. * Calculates absolute bounds of this UIObject.
  8227. */
  8228. absoluteBounds: function() {
  8229. if(this.parent) {
  8230. var absUL = this.absoluteXY();
  8231. return new ORYX.Core.Bounds(absUL.x, absUL.y,
  8232. absUL.x + this.bounds.width(),
  8233. absUL.y + this.bounds.height());
  8234. } else {
  8235. return this.bounds.clone();
  8236. }
  8237. },
  8238. /**
  8239. * @return {Point} The absolute position of this UIObject.
  8240. */
  8241. absoluteXY: function() {
  8242. if(this.parent) {
  8243. var pXY = this.parent.absoluteXY();
  8244. return {x: pXY.x + this.bounds.upperLeft().x , y: pXY.y + this.bounds.upperLeft().y};
  8245. } else {
  8246. return {x: this.bounds.upperLeft().x , y: this.bounds.upperLeft().y};
  8247. }
  8248. },
  8249. /**
  8250. * @return {Point} The absolute position from the Center of this UIObject.
  8251. */
  8252. absoluteCenterXY: function() {
  8253. if(this.parent) {
  8254. var pXY = this.parent.absoluteXY();
  8255. return {x: pXY.x + this.bounds.center().x , y: pXY.y + this.bounds.center().y};
  8256. } else {
  8257. return {x: this.bounds.center().x , y: this.bounds.center().y};
  8258. }
  8259. },
  8260. /**
  8261. * Hides this UIObject and all its children.
  8262. */
  8263. hide: function() {
  8264. this.node.setAttributeNS(null, 'display', 'none');
  8265. this.isVisible = false;
  8266. this.children.each(function(uiObj) {
  8267. uiObj.hide();
  8268. });
  8269. },
  8270. /**
  8271. * Enables visibility of this UIObject and all its children.
  8272. */
  8273. show: function() {
  8274. this.node.setAttributeNS(null, 'display', 'inherit');
  8275. this.isVisible = true;
  8276. this.children.each(function(uiObj) {
  8277. uiObj.show();
  8278. });
  8279. },
  8280. addEventHandlers: function(node) {
  8281. node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this._delegateEvent.bind(this), false);
  8282. node.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this._delegateEvent.bind(this), false);
  8283. node.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this._delegateEvent.bind(this), false);
  8284. node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this._delegateEvent.bind(this), false);
  8285. node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this._delegateEvent.bind(this), false);
  8286. node.addEventListener('click', this._delegateEvent.bind(this), false);
  8287. node.addEventListener(ORYX.CONFIG.EVENT_DBLCLICK, this._delegateEvent.bind(this), false);
  8288. },
  8289. _delegateEvent: function(event) {
  8290. if(this.eventHandlerCallback) {
  8291. this.eventHandlerCallback(event, this);
  8292. }
  8293. },
  8294. toString: function() { return "UIObject " + this.id }
  8295. };
  8296. ORYX.Core.UIObject = Clazz.extend(ORYX.Core.UIObject);/**
  8297. * Copyright (c) 2006
  8298. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  8299. *
  8300. * Permission is hereby granted, free of charge, to any person obtaining a
  8301. * copy of this software and associated documentation files (the "Software"),
  8302. * to deal in the Software without restriction, including without limitation
  8303. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8304. * and/or sell copies of the Software, and to permit persons to whom the
  8305. * Software is furnished to do so, subject to the following conditions:
  8306. *
  8307. * The above copyright notice and this permission notice shall be included in
  8308. * all copies or substantial portions of the Software.
  8309. *
  8310. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  8311. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  8312. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8313. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  8314. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  8315. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  8316. * DEALINGS IN THE SOFTWARE.
  8317. **/
  8318. /**
  8319. * Init namespaces
  8320. */
  8321. if(!ORYX) {var ORYX = {};}
  8322. if(!ORYX.Core) {ORYX.Core = {};}
  8323. /**
  8324. * Top Level uiobject.
  8325. * @class ORYX.Core.AbstractShape
  8326. * @extends ORYX.Core.UIObject
  8327. */
  8328. ORYX.Core.AbstractShape = ORYX.Core.UIObject.extend(
  8329. /** @lends ORYX.Core.AbstractShape.prototype */
  8330. {
  8331. /**
  8332. * Constructor
  8333. */
  8334. construct: function(options, stencil) {
  8335. arguments.callee.$.construct.apply(this, arguments);
  8336. this.resourceId = ORYX.Editor.provideId(); //Id of resource in DOM
  8337. // stencil reference
  8338. this._stencil = stencil;
  8339. // if the stencil defines a super stencil that should be used for its instances, set it.
  8340. if (this._stencil._jsonStencil.superId){
  8341. stencilId = this._stencil.id()
  8342. superStencilId = stencilId.substring(0, stencilId.indexOf("#") + 1) + stencil._jsonStencil.superId;
  8343. stencilSet = this._stencil.stencilSet();
  8344. this._stencil = stencilSet.stencil(superStencilId);
  8345. }
  8346. //Hash map for all properties. Only stores the values of the properties.
  8347. this.properties = new Hash();
  8348. this.propertiesChanged = new Hash();
  8349. // List of properties which are not included in the stencilset,
  8350. // but which gets (de)serialized
  8351. this.hiddenProperties = new Hash();
  8352. //Initialization of property map and initial value.
  8353. this._stencil.properties().each((function(property) {
  8354. var key = property.prefix() + "-" + property.id();
  8355. this.properties[key] = property.value();
  8356. this.propertiesChanged[key] = true;
  8357. }).bind(this));
  8358. // if super stencil was defined, also regard stencil's properties:
  8359. if (stencil._jsonStencil.superId) {
  8360. stencil.properties().each((function(property) {
  8361. var key = property.prefix() + "-" + property.id();
  8362. var value = property.value();
  8363. var oldValue = this.properties[key];
  8364. this.properties[key] = value;
  8365. this.propertiesChanged[key] = true;
  8366. // Raise an event, to show that the property has changed
  8367. // required for plugins like processLink.js
  8368. //window.setTimeout( function(){
  8369. this._delegateEvent({
  8370. type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
  8371. name : key,
  8372. value : value,
  8373. oldValue: oldValue
  8374. });
  8375. //}.bind(this), 10)
  8376. }).bind(this));
  8377. }
  8378. },
  8379. layout: function() {
  8380. },
  8381. /**
  8382. * Returns the stencil object specifiing the type of the shape.
  8383. */
  8384. getStencil: function() {
  8385. return this._stencil;
  8386. },
  8387. /**
  8388. *
  8389. * @param {Object} resourceId
  8390. */
  8391. getChildShapeByResourceId: function(resourceId) {
  8392. resourceId = ERDF.__stripHashes(resourceId);
  8393. return this.getChildShapes(true).find(function(shape) {
  8394. return shape.resourceId == resourceId
  8395. });
  8396. },
  8397. /**
  8398. *
  8399. * @param {Object} deep
  8400. * @param {Object} iterator
  8401. */
  8402. getChildShapes: function(deep, iterator) {
  8403. var result = [];
  8404. this.children.each(function(uiObject) {
  8405. if(uiObject instanceof ORYX.Core.Shape && uiObject.isVisible ) {
  8406. if(iterator) {
  8407. iterator(uiObject);
  8408. }
  8409. result.push(uiObject);
  8410. if(deep) {
  8411. result = result.concat(uiObject.getChildShapes(deep, iterator));
  8412. }
  8413. }
  8414. });
  8415. return result;
  8416. },
  8417. /**
  8418. * @param {Object} shape
  8419. * @return {boolean} true if any of shape's childs is given shape
  8420. */
  8421. hasChildShape: function(shape){
  8422. return this.getChildShapes().any(function(child){
  8423. return (child === shape) || child.hasChildShape(shape);
  8424. });
  8425. },
  8426. /**
  8427. *
  8428. * @param {Object} deep
  8429. * @param {Object} iterator
  8430. */
  8431. getChildNodes: function(deep, iterator) {
  8432. var result = [];
  8433. this.children.each(function(uiObject) {
  8434. if(uiObject instanceof ORYX.Core.Node && uiObject.isVisible) {
  8435. if(iterator) {
  8436. iterator(uiObject);
  8437. }
  8438. result.push(uiObject);
  8439. }
  8440. if(uiObject instanceof ORYX.Core.Shape) {
  8441. if(deep) {
  8442. result = result.concat(uiObject.getChildNodes(deep, iterator));
  8443. }
  8444. }
  8445. });
  8446. return result;
  8447. },
  8448. /**
  8449. *
  8450. * @param {Object} deep
  8451. * @param {Object} iterator
  8452. */
  8453. getChildEdges: function(deep, iterator) {
  8454. var result = [];
  8455. this.children.each(function(uiObject) {
  8456. if(uiObject instanceof ORYX.Core.Edge && uiObject.isVisible) {
  8457. if(iterator) {
  8458. iterator(uiObject);
  8459. }
  8460. result.push(uiObject);
  8461. }
  8462. if(uiObject instanceof ORYX.Core.Shape) {
  8463. if(deep) {
  8464. result = result.concat(uiObject.getChildEdges(deep, iterator));
  8465. }
  8466. }
  8467. });
  8468. return result;
  8469. },
  8470. /**
  8471. * Returns a sorted array of ORYX.Core.Node objects.
  8472. * Ordered in z Order, the last object has the highest z Order.
  8473. */
  8474. //TODO deep iterator
  8475. getAbstractShapesAtPosition: function() {
  8476. var x, y;
  8477. switch (arguments.length) {
  8478. case 1:
  8479. x = arguments[0].x;
  8480. y = arguments[0].y;
  8481. break;
  8482. case 2: //two or more arguments
  8483. x = arguments[0];
  8484. y = arguments[1];
  8485. break;
  8486. default:
  8487. throw "getAbstractShapesAtPosition needs 1 or 2 arguments!"
  8488. }
  8489. if(this.isPointIncluded(x, y)) {
  8490. var result = [];
  8491. result.push(this);
  8492. //check, if one child is at that position
  8493. var childNodes = this.getChildNodes();
  8494. var childEdges = this.getChildEdges();
  8495. [childNodes, childEdges].each(function(ne){
  8496. var nodesAtPosition = new Hash();
  8497. ne.each(function(node) {
  8498. if(!node.isVisible){ return }
  8499. var candidates = node.getAbstractShapesAtPosition( x , y );
  8500. if(candidates.length > 0) {
  8501. var nodesInZOrder = $A(node.node.parentNode.childNodes);
  8502. var zOrderIndex = nodesInZOrder.indexOf(node.node);
  8503. nodesAtPosition[zOrderIndex] = candidates;
  8504. }
  8505. });
  8506. nodesAtPosition.keys().sort().each(function(key) {
  8507. result = result.concat(nodesAtPosition[key]);
  8508. });
  8509. });
  8510. return result;
  8511. } else {
  8512. return [];
  8513. }
  8514. },
  8515. /**
  8516. *
  8517. * @param key {String} Must be 'prefix-id' of property
  8518. * @param value {Object} Can be of type String or Number according to property type.
  8519. */
  8520. setProperty: function(key, value, force) {
  8521. var oldValue = this.properties[key];
  8522. if(oldValue !== value || force === true) {
  8523. this.properties[key] = value;
  8524. this.propertiesChanged[key] = true;
  8525. this._changed();
  8526. // Raise an event, to show that the property has changed
  8527. //window.setTimeout( function(){
  8528. if (!this._isInSetProperty) {
  8529. this._isInSetProperty = true;
  8530. this._delegateEvent({
  8531. type : ORYX.CONFIG.EVENT_PROPERTY_CHANGED,
  8532. elements : [this],
  8533. name : key,
  8534. value : value,
  8535. oldValue: oldValue
  8536. });
  8537. delete this._isInSetProperty;
  8538. }
  8539. //}.bind(this), 10)
  8540. }
  8541. },
  8542. /**
  8543. * Returns TRUE if one of the properties is flagged as dirty
  8544. * @return {boolean}
  8545. */
  8546. isPropertyChanged: function(){
  8547. return this.propertiesChanged.any(function(property){ return property.value });
  8548. },
  8549. /**
  8550. *
  8551. * @param {String} Must be 'prefix-id' of property
  8552. * @param {Object} Can be of type String or Number according to property type.
  8553. */
  8554. setHiddenProperty: function(key, value) {
  8555. // IF undefined, Delete
  8556. if (value === undefined) {
  8557. delete this.hiddenProperties[key];
  8558. return;
  8559. }
  8560. var oldValue = this.hiddenProperties[key];
  8561. if (oldValue !== value) {
  8562. this.hiddenProperties[key] = value;
  8563. }
  8564. },
  8565. /**
  8566. * Calculate if the point is inside the Shape
  8567. * @param {Point}
  8568. */
  8569. isPointIncluded: function(pointX, pointY, absoluteBounds) {
  8570. var absBounds = absoluteBounds ? absoluteBounds : this.absoluteBounds();
  8571. return absBounds.isIncluded(pointX, pointY);
  8572. },
  8573. /**
  8574. * Get the serialized object
  8575. * return Array with hash-entrees (prefix, name, value)
  8576. * Following values will given:
  8577. * Type
  8578. * Properties
  8579. */
  8580. serialize: function() {
  8581. var serializedObject = [];
  8582. // Add the type
  8583. serializedObject.push({name: 'type', prefix:'oryx', value: this.getStencil().id(), type: 'literal'});
  8584. // Add hidden properties
  8585. this.hiddenProperties.each(function(prop){
  8586. serializedObject.push({name: prop.key.replace("oryx-", ""), prefix: "oryx", value: prop.value, type: 'literal'});
  8587. }.bind(this));
  8588. // Add all properties
  8589. this.getStencil().properties().each((function(property){
  8590. var prefix = property.prefix(); // Get prefix
  8591. var name = property.id(); // Get name
  8592. //if(typeof this.properties[prefix+'-'+name] == 'boolean' || this.properties[prefix+'-'+name] != "")
  8593. serializedObject.push({name: name, prefix: prefix, value: this.properties[prefix+'-'+name], type: 'literal'});
  8594. }).bind(this));
  8595. return serializedObject;
  8596. },
  8597. deserialize: function(serialize){
  8598. // Search in Serialize
  8599. var initializedDocker = 0;
  8600. // Sort properties so that the hidden properties are first in the list
  8601. serialize = serialize.sort(function(a,b){ a = Number(this.properties.keys().member(a.prefix+"-"+a.name)); b = Number(this.properties.keys().member(b.prefix+"-"+b.name)); return a > b ? 1 : (a < b ? -1 : 0) }.bind(this));
  8602. serialize.each((function(obj){
  8603. var name = obj.name;
  8604. var prefix = obj.prefix;
  8605. var value = obj.value;
  8606. // Complex properties can be real json objects, encode them to a string
  8607. if(Ext.type(value) === "object") value = Ext.encode(value);
  8608. switch(prefix + "-" + name){
  8609. case 'raziel-parent':
  8610. // Set parent
  8611. if(!this.parent) {break};
  8612. // Set outgoing Shape
  8613. var parent = this.getCanvas().getChildShapeByResourceId(value);
  8614. if(parent) {
  8615. parent.add(this);
  8616. }
  8617. break;
  8618. default:
  8619. // If list, eval as an array
  8620. var prop = this.getStencil().property(prefix+"-"+name);
  8621. if (prop && prop.isList() && typeof value === "string"){
  8622. if ((value||"").strip()&&!value.startsWith("[")&&!value.startsWith("]"))
  8623. value = "[\""+value.strip()+"\"]";
  8624. value = ((value||"").strip()||"[]").evalJSON();
  8625. }
  8626. // Set property
  8627. if(this.properties.keys().member(prefix+"-"+name)) {
  8628. this.setProperty(prefix+"-"+name, value);
  8629. } else if(!(name === "bounds"||name === "parent"||name === "target"||name === "dockers"||name === "docker"||name === "outgoing"||name === "incoming")) {
  8630. this.setHiddenProperty(prefix+"-"+name, value);
  8631. }
  8632. }
  8633. }).bind(this));
  8634. },
  8635. toString: function() { return "ORYX.Core.AbstractShape " + this.id },
  8636. /**
  8637. * Converts the shape to a JSON representation.
  8638. * @return {Object} A JSON object with included ORYX.Core.AbstractShape.JSONHelper and getShape() method.
  8639. */
  8640. toJSON: function(){
  8641. var json = {
  8642. resourceId: this.resourceId,
  8643. properties: Ext.apply({}, this.properties, this.hiddenProperties).inject({}, function(props, prop){
  8644. var key = prop[0];
  8645. var value = prop[1];
  8646. //If complex property, value should be a json object
  8647. if ( this.getStencil().property(key)
  8648. && this.getStencil().property(key).type() === ORYX.CONFIG.TYPE_COMPLEX
  8649. && Ext.type(value) === "string"){
  8650. try {value = Ext.decode(value);} catch(error){}
  8651. // Parse date
  8652. } else if (value instanceof Date&&this.getStencil().property(key)){
  8653. try {
  8654. value = value.format(this.getStencil().property(key).dateFormat());
  8655. } catch(e){}
  8656. }
  8657. //Takes "my_property" instead of "oryx-my_property" as key
  8658. key = key.replace(/^[\w_]+-/, "");
  8659. props[key] = value;
  8660. return props;
  8661. }.bind(this)),
  8662. stencil: {
  8663. id: this.getStencil().idWithoutNs()
  8664. },
  8665. childShapes: this.getChildShapes().map(function(shape){
  8666. return shape.toJSON()
  8667. })
  8668. };
  8669. if(this.getOutgoingShapes){
  8670. json.outgoing = this.getOutgoingShapes().map(function(shape){
  8671. return {
  8672. resourceId: shape.resourceId
  8673. };
  8674. });
  8675. }
  8676. if(this.bounds){
  8677. json.bounds = {
  8678. lowerRight: this.bounds.lowerRight(),
  8679. upperLeft: this.bounds.upperLeft()
  8680. };
  8681. }
  8682. if(this.dockers){
  8683. json.dockers = this.dockers.map(function(docker){
  8684. var d = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center();
  8685. d.getDocker = function(){return docker;};
  8686. return d;
  8687. })
  8688. }
  8689. Ext.apply(json, ORYX.Core.AbstractShape.JSONHelper);
  8690. // do not pollute the json attributes (for serialization), so put the corresponding
  8691. // shape is encapsulated in a method
  8692. json.getShape = function(){
  8693. return this;
  8694. }.bind(this);
  8695. return json;
  8696. }
  8697. });
  8698. /**
  8699. * @namespace Collection of methods which can be used on a shape json object (ORYX.Core.AbstractShape#toJSON()).
  8700. * @example
  8701. * Ext.apply(shapeAsJson, ORYX.Core.AbstractShape.JSONHelper);
  8702. */
  8703. ORYX.Core.AbstractShape.JSONHelper = {
  8704. /**
  8705. * Iterates over each child shape.
  8706. * @param {Object} iterator Iterator function getting a child shape and his parent as arguments.
  8707. * @param {boolean} [deep=false] Iterate recursively (childShapes of childShapes)
  8708. * @param {boolean} [modify=false] If true, the result of the iterator function is taken as new shape, return false to delete it. This enables modifying the object while iterating through the child shapes.
  8709. * @example
  8710. * // Increases the lowerRight x value of each direct child shape by one.
  8711. * myShapeAsJson.eachChild(function(shape, parentShape){
  8712. * shape.bounds.lowerRight.x = shape.bounds.lowerRight.x + 1;
  8713. * return shape;
  8714. * }, false, true);
  8715. */
  8716. eachChild: function(iterator, deep, modify){
  8717. if(!this.childShapes) return;
  8718. var newChildShapes = []; //needed if modify = true
  8719. this.childShapes.each(function(shape){
  8720. if (!(shape.eachChild instanceof Function)){
  8721. Ext.apply(shape, ORYX.Core.AbstractShape.JSONHelper);
  8722. }
  8723. var res = iterator(shape, this);
  8724. if(res) newChildShapes.push(res); //if false is returned, and modify = true, current shape is deleted.
  8725. if(deep) shape.eachChild(iterator, deep, modify);
  8726. }.bind(this));
  8727. if(modify) this.childShapes = newChildShapes;
  8728. },
  8729. getShape: function(){
  8730. return null;
  8731. },
  8732. getChildShapes: function(deep){
  8733. var allShapes = this.childShapes;
  8734. if(deep){
  8735. this.eachChild(function(shape){
  8736. if (!(shape.getChildShapes instanceof Function)){
  8737. Ext.apply(shape, ORYX.Core.AbstractShape.JSONHelper);
  8738. }
  8739. allShapes = allShapes.concat(shape.getChildShapes(deep));
  8740. }, true);
  8741. }
  8742. return allShapes;
  8743. },
  8744. /**
  8745. * @return {String} Serialized JSON object
  8746. */
  8747. serialize: function(){
  8748. return Ext.encode(this);
  8749. }
  8750. }
  8751. /**
  8752. * Copyright (c) 2006
  8753. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  8754. *
  8755. * Permission is hereby granted, free of charge, to any person obtaining a
  8756. * copy of this software and associated documentation files (the "Software"),
  8757. * to deal in the Software without restriction, including without limitation
  8758. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8759. * and/or sell copies of the Software, and to permit persons to whom the
  8760. * Software is furnished to do so, subject to the following conditions:
  8761. *
  8762. * The above copyright notice and this permission notice shall be included in
  8763. * all copies or substantial portions of the Software.
  8764. *
  8765. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  8766. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  8767. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  8768. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  8769. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  8770. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  8771. * DEALINGS IN THE SOFTWARE.
  8772. **/
  8773. /**
  8774. * Init namespaces
  8775. */
  8776. if(!ORYX) {var ORYX = {};}
  8777. /**
  8778. @namespace Namespace for the Oryx core elements.
  8779. @name ORYX.Core
  8780. */
  8781. if(!ORYX.Core) {ORYX.Core = {};}
  8782. /**
  8783. * @class Oryx canvas.
  8784. * @extends ORYX.Core.AbstractShape
  8785. *
  8786. */
  8787. ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({
  8788. /** @lends ORYX.Core.Canvas.prototype */
  8789. /**
  8790. * Defines the current zoom level
  8791. */
  8792. zoomLevel:1,
  8793. /**
  8794. * Constructor
  8795. */
  8796. construct: function(options) {
  8797. arguments.callee.$.construct.apply(this, arguments);
  8798. if(!(options && options.width && options.height)) {
  8799. ORYX.Log.fatal("Canvas is missing mandatory parameters options.width and options.height.");
  8800. return;
  8801. }
  8802. //TODO: set document resource id
  8803. this.resourceId = options.id;
  8804. this.nodes = [];
  8805. this.edges = [];
  8806. //init svg document
  8807. this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", options.parentNode,
  8808. ['svg', {id: this.id, width: options.width, height: options.height},
  8809. ['defs', {}]
  8810. ]);
  8811. this.rootNode.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
  8812. this.rootNode.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");
  8813. this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", options.parentNode,
  8814. ['div', {id: "oryx_canvas_htmlContainer", style:"position:absolute; top:5px"}]);
  8815. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode,
  8816. ['g', {},
  8817. ['g', {"class": "stencils"},
  8818. ['g', {"class": "me"}],
  8819. ['g', {"class": "children"}],
  8820. ['g', {"class": "edge"}]
  8821. ],
  8822. ['g', {"class":"svgcontainer"}]
  8823. ]);
  8824. /*
  8825. var off = 2 * ORYX.CONFIG.GRID_DISTANCE;
  8826. var size = 3;
  8827. var d = "";
  8828. for(var i = 0; i <= options.width; i += off)
  8829. for(var j = 0; j <= options.height; j += off)
  8830. d = d + "M" + (i - size) + " " + j + " l" + (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + " m0" + (-size) + " ";
  8831. ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node.firstChild.firstChild,
  8832. ['path', {d:d , stroke:'#000000', 'stroke-width':'0.15px'},]);
  8833. */
  8834. //Global definition of default font for shapes
  8835. //Definitions in the SVG definition of a stencil will overwrite these settings for
  8836. // that stencil.
  8837. /*if(navigator.platform.indexOf("Mac") > -1) {
  8838. this.node.setAttributeNS(null, 'stroke', 'black');
  8839. this.node.setAttributeNS(null, 'stroke-width', '0.5px');
  8840. this.node.setAttributeNS(null, 'font-family', 'Skia');
  8841. //this.node.setAttributeNS(null, 'letter-spacing', '2px');
  8842. this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT);
  8843. } else {
  8844. this.node.setAttributeNS(null, 'stroke', 'none');
  8845. this.node.setAttributeNS(null, 'font-family', 'Verdana');
  8846. this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT);
  8847. }*/
  8848. this.node.setAttributeNS(null, 'stroke', 'black');
  8849. this.node.setAttributeNS(null, 'font-family', 'Verdana, sans-serif');
  8850. this.node.setAttributeNS(null, 'font-size-adjust', 'none');
  8851. this.node.setAttributeNS(null, 'font-style', 'normal');
  8852. this.node.setAttributeNS(null, 'font-variant', 'normal');
  8853. this.node.setAttributeNS(null, 'font-weight', 'normal');
  8854. this.node.setAttributeNS(null, 'line-heigth', 'normal');
  8855. this.node.setAttributeNS(null, 'font-size', ORYX.CONFIG.LABEL_DEFAULT_LINE_HEIGHT);
  8856. this.bounds.set(0,0,options.width, options.height);
  8857. this.addEventHandlers(this.rootNode.parentNode);
  8858. //disable context menu
  8859. this.rootNode.oncontextmenu = function() {return false;};
  8860. },
  8861. getScrollNode: function(){
  8862. return Ext.get(this.rootNode).parent("div{overflow=auto}", true);
  8863. },
  8864. focus: function(){
  8865. try {
  8866. // Get a href
  8867. if (!this.focusEl) {
  8868. this.focusEl = Ext.getBody().createChild({
  8869. tag: "a",
  8870. href: "#",
  8871. cls: "x-grid3-focus x-grid3-focus-canvas",
  8872. tabIndex: "-1"
  8873. });
  8874. this.focusEl.swallowEvent("click", true);
  8875. }
  8876. // Focus it
  8877. if (Ext.isGecko) {
  8878. this.focusEl.focus();
  8879. }
  8880. else {
  8881. this.focusEl.focus.defer(1, this.focusEl);
  8882. }
  8883. this.focusEl.blur.defer(3, this.focusEl);
  8884. } catch(e){}
  8885. },
  8886. update: function() {
  8887. this.nodes.each(function(node) {
  8888. this._traverseForUpdate(node);
  8889. }.bind(this));
  8890. // call stencil's layout callback
  8891. // (needed for row layouting of xforms)
  8892. //this.getStencil().layout(this);
  8893. var layoutEvents = this.getStencil().layout();
  8894. if(layoutEvents) {
  8895. layoutEvents.each(function(event) {
  8896. // setup additional attributes
  8897. event.shape = this;
  8898. event.forceExecution = true;
  8899. event.target = this.rootNode;
  8900. // do layouting
  8901. this._delegateEvent(event);
  8902. }.bind(this))
  8903. }
  8904. this.nodes.invoke("_update");
  8905. this.edges.invoke("_update", true);
  8906. /*this.children.each(function(child) {
  8907. child._update();
  8908. });*/
  8909. },
  8910. _traverseForUpdate: function(shape) {
  8911. var childRet = shape.isChanged;
  8912. shape.getChildNodes(false, function(child) {
  8913. if(this._traverseForUpdate(child)) {
  8914. childRet = true;
  8915. }
  8916. }.bind(this));
  8917. if(childRet) {
  8918. shape.layout();
  8919. return true;
  8920. } else {
  8921. return false;
  8922. }
  8923. },
  8924. layout: function() {
  8925. },
  8926. /**
  8927. *
  8928. * @param {Object} deep
  8929. * @param {Object} iterator
  8930. */
  8931. getChildNodes: function(deep, iterator) {
  8932. if(!deep && !iterator) {
  8933. return this.nodes.clone();
  8934. } else {
  8935. var result = [];
  8936. this.nodes.each(function(uiObject) {
  8937. if(iterator) {
  8938. iterator(uiObject);
  8939. }
  8940. result.push(uiObject);
  8941. if(deep && uiObject instanceof ORYX.Core.Shape) {
  8942. result = result.concat(uiObject.getChildNodes(deep, iterator));
  8943. }
  8944. });
  8945. return result;
  8946. }
  8947. },
  8948. /**
  8949. * buggy crap! use base class impl instead!
  8950. * @param {Object} iterator
  8951. */
  8952. /* getChildEdges: function(iterator) {
  8953. if(iterator) {
  8954. this.edges.each(function(edge) {
  8955. iterator(edge);
  8956. });
  8957. }
  8958. return this.edges.clone();
  8959. },
  8960. */
  8961. /**
  8962. * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
  8963. * @param {UIObject} uiObject
  8964. */
  8965. add: function(uiObject, index, silent) {
  8966. //if uiObject is child of another UIObject, remove it.
  8967. if(uiObject instanceof ORYX.Core.UIObject) {
  8968. if (!(this.children.member(uiObject))) {
  8969. //if uiObject is child of another parent, remove it from that parent.
  8970. if(uiObject.parent) {
  8971. uiObject.parent.remove(uiObject, true);
  8972. }
  8973. //add uiObject to the Canvas
  8974. //add uiObject to this Shape
  8975. if(index != undefined)
  8976. this.children.splice(index, 0, uiObject);
  8977. else
  8978. this.children.push(uiObject);
  8979. //set parent reference
  8980. uiObject.parent = this;
  8981. //add uiObject.node to this.node depending on the type of uiObject
  8982. if(uiObject instanceof ORYX.Core.Shape) {
  8983. if(uiObject instanceof ORYX.Core.Edge) {
  8984. uiObject.addMarkers(this.rootNode.getElementsByTagNameNS(NAMESPACE_SVG, "defs")[0]);
  8985. uiObject.node = this.node.childNodes[0].childNodes[2].appendChild(uiObject.node);
  8986. this.edges.push(uiObject);
  8987. } else {
  8988. uiObject.node = this.node.childNodes[0].childNodes[1].appendChild(uiObject.node);
  8989. this.nodes.push(uiObject);
  8990. }
  8991. } else { //UIObject
  8992. uiObject.node = this.node.appendChild(uiObject.node);
  8993. }
  8994. uiObject.bounds.registerCallback(this._changedCallback);
  8995. if(this.eventHandlerCallback && silent !== true)
  8996. this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEADDED,shape:uiObject})
  8997. } else {
  8998. ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object.");
  8999. }
  9000. } else {
  9001. ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject.");
  9002. }
  9003. },
  9004. /**
  9005. * Overrides the UIObject.remove method. Removes uiObject.
  9006. * @param {UIObject} uiObject
  9007. */
  9008. remove: function(uiObject, silent) {
  9009. //if uiObject is a child of this object, remove it.
  9010. if (this.children.member(uiObject)) {
  9011. //remove uiObject from children
  9012. var parent = uiObject.parent;
  9013. this.children = this.children.without(uiObject);
  9014. //delete parent reference of uiObject
  9015. uiObject.parent = undefined;
  9016. //delete uiObject.node from this.node
  9017. if(uiObject instanceof ORYX.Core.Shape) {
  9018. if(uiObject instanceof ORYX.Core.Edge) {
  9019. uiObject.removeMarkers();
  9020. uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node);
  9021. this.edges = this.edges.without(uiObject);
  9022. } else {
  9023. uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node);
  9024. this.nodes = this.nodes.without(uiObject);
  9025. }
  9026. } else { //UIObject
  9027. uiObject.node = this.node.removeChild(uiObject.node);
  9028. }
  9029. if(this.eventHandlerCallback && silent !== true)
  9030. this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEREMOVED,shape:uiObject, parent:parent});
  9031. uiObject.bounds.unregisterCallback(this._changedCallback);
  9032. } else {
  9033. ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object.");
  9034. }
  9035. },
  9036. /**
  9037. * Creates shapes out of the given collection of shape objects and adds them to the canvas.
  9038. * @example
  9039. * canvas.addShapeObjects({
  9040. bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } },
  9041. resourceId:"oryx_F0715955-50F2-403D-9851-C08CFE70F8BD",
  9042. childShapes:[],
  9043. properties:{},
  9044. stencil:{
  9045. id:"Subprocess"
  9046. },
  9047. outgoing:[{resourceId: 'aShape'}],
  9048. target: {resourceId: 'aShape'}
  9049. });
  9050. * @param {Object} shapeObjects
  9051. * @param {Function} [eventHandler] An event handler passed to each newly created shape (as eventHandlerCallback)
  9052. * @return {Array} A collection of ORYX.Core.Shape
  9053. * @methodOf ORYX.Core.Canvas.prototype
  9054. */
  9055. addShapeObjects: function(shapeObjects, eventHandler){
  9056. if(!shapeObjects) return;
  9057. this.initializingShapes = true;
  9058. /*FIXME This implementation is very evil! At first, all shapes are created on
  9059. canvas. In a second step, the attributes are applied. There must be a distinction
  9060. between the configuration phase (where the outgoings, for example, are just named),
  9061. and the creation phase (where the outgoings are evaluated). This must be reflected
  9062. in code to provide a nicer API/ implementation!!! */
  9063. var addShape = function(shape, parent){
  9064. // Create a new Stencil
  9065. var stencil = ORYX.Core.StencilSet.stencil(this.getStencil().namespace() + shape.stencil.id );
  9066. // Create a new Shape
  9067. var ShapeClass = (stencil.type() == "node") ? ORYX.Core.Node : ORYX.Core.Edge;
  9068. var newShape = new ShapeClass(
  9069. {'eventHandlerCallback': eventHandler},
  9070. stencil);
  9071. // Set the resource id
  9072. newShape.resourceId = shape.resourceId;
  9073. newShape.node.id = "svg-" + shape.resourceId;
  9074. // Set parent to json object to be used later
  9075. // Due to the nested json structure, normally shape.parent is not set/ must not be set.
  9076. // In special cases, it can be easier to set this directly instead of a nested structure.
  9077. shape.parent = "#" + ((shape.parent && shape.parent.resourceId) || parent.resourceId);
  9078. // Add the shape to the canvas
  9079. this.add( newShape );
  9080. return {
  9081. json: shape,
  9082. object: newShape
  9083. };
  9084. }.bind(this);
  9085. /** Builds up recursively a flatted array of shapes, including a javascript object and json representation
  9086. * @param {Object} shape Any object that has Object#childShapes
  9087. */
  9088. var addChildShapesRecursively = function(shape){
  9089. var addedShapes = [];
  9090. shape.childShapes.each(function(childShape){
  9091. addedShapes.push(addShape(childShape, shape));
  9092. addedShapes = addedShapes.concat(addChildShapesRecursively(childShape));
  9093. });
  9094. return addedShapes;
  9095. }.bind(this);
  9096. var shapes = addChildShapesRecursively({
  9097. childShapes: shapeObjects,
  9098. resourceId: this.resourceId
  9099. });
  9100. // prepare deserialisation parameter
  9101. shapes.each(
  9102. function(shape){
  9103. var properties = [];
  9104. for(field in shape.json.properties){
  9105. properties.push({
  9106. prefix: 'oryx',
  9107. name: field,
  9108. value: shape.json.properties[field]
  9109. });
  9110. }
  9111. // Outgoings
  9112. shape.json.outgoing.each(function(out){
  9113. properties.push({
  9114. prefix: 'raziel',
  9115. name: 'outgoing',
  9116. value: "#"+out.resourceId
  9117. });
  9118. });
  9119. // Target
  9120. // (because of a bug, the first outgoing is taken when there is no target,
  9121. // can be removed after some time)
  9122. if(shape.object instanceof ORYX.Core.Edge) {
  9123. var target = shape.json.target || shape.json.outgoing[0];
  9124. if(target){
  9125. properties.push({
  9126. prefix: 'raziel',
  9127. name: 'target',
  9128. value: "#"+target.resourceId
  9129. });
  9130. }
  9131. }
  9132. // Bounds
  9133. if (shape.json.bounds) {
  9134. properties.push({
  9135. prefix: 'oryx',
  9136. name: 'bounds',
  9137. value: shape.json.bounds.upperLeft.x + "," + shape.json.bounds.upperLeft.y + "," + shape.json.bounds.lowerRight.x + "," + shape.json.bounds.lowerRight.y
  9138. });
  9139. }
  9140. //Dockers [{x:40, y:50}, {x:30, y:60}] => "40 50 30 60 #"
  9141. if(shape.json.dockers){
  9142. properties.push({
  9143. prefix: 'oryx',
  9144. name: 'dockers',
  9145. value: shape.json.dockers.inject("", function(dockersStr, docker){
  9146. return dockersStr + docker.x + " " + docker.y + " ";
  9147. }) + " #"
  9148. });
  9149. }
  9150. //Parent
  9151. properties.push({
  9152. prefix: 'raziel',
  9153. name: 'parent',
  9154. value: shape.json.parent
  9155. });
  9156. shape.__properties = properties;
  9157. }.bind(this)
  9158. );
  9159. // Deserialize the properties from the shapes
  9160. // This can't be done earlier because Shape#deserialize expects that all referenced nodes are already there
  9161. // first, deserialize all nodes
  9162. shapes.each(function(shape) {
  9163. if(shape.object instanceof ORYX.Core.Node) {
  9164. shape.object.deserialize(shape.__properties, shape.json);
  9165. }
  9166. });
  9167. // second, deserialize all edges
  9168. shapes.each(function(shape) {
  9169. if(shape.object instanceof ORYX.Core.Edge) {
  9170. shape.object.deserialize(shape.__properties, shape.json);
  9171. shape.object._oldBounds = shape.object.bounds.clone();
  9172. shape.object._update();
  9173. }
  9174. });
  9175. delete this.initializingShapes;
  9176. return shapes.pluck("object");
  9177. },
  9178. /**
  9179. * Updates the size of the canvas, regarding to the containg shapes.
  9180. */
  9181. updateSize: function(){
  9182. // Check the size for the canvas
  9183. var maxWidth = 0;
  9184. var maxHeight = 0;
  9185. var offset = 100;
  9186. this.getChildShapes(true, function(shape){
  9187. var b = shape.bounds;
  9188. maxWidth = Math.max( maxWidth, b.lowerRight().x + offset)
  9189. maxHeight = Math.max( maxHeight, b.lowerRight().y + offset)
  9190. });
  9191. if( this.bounds.width() < maxWidth || this.bounds.height() < maxHeight ){
  9192. this.setSize({width: Math.max(this.bounds.width(), maxWidth), height: Math.max(this.bounds.height(), maxHeight)})
  9193. }
  9194. },
  9195. getRootNode: function() {
  9196. return this.rootNode;
  9197. },
  9198. getSvgContainer: function() {
  9199. return this.node.childNodes[1];
  9200. },
  9201. getHTMLContainer: function() {
  9202. return this._htmlContainer;
  9203. },
  9204. /**
  9205. * Return all elements of the same highest level
  9206. * @param {Object} elements
  9207. */
  9208. getShapesWithSharedParent: function(elements) {
  9209. // If there is no elements, return []
  9210. if(!elements || elements.length < 1) { return [] }
  9211. // If there is one element, return this element
  9212. if(elements.length == 1) { return elements}
  9213. return elements.findAll(function(value){
  9214. var parentShape = value.parent;
  9215. while(parentShape){
  9216. if(elements.member(parentShape)) return false;
  9217. parentShape = parentShape.parent
  9218. }
  9219. return true;
  9220. });
  9221. },
  9222. setSize: function(size, dontSetBounds) {
  9223. if(!size || !size.width || !size.height){return}
  9224. if(this.rootNode.parentNode){
  9225. this.rootNode.parentNode.style.width = size.width + 'px';
  9226. this.rootNode.parentNode.style.height = size.height + 'px';
  9227. }
  9228. this.rootNode.setAttributeNS(null, 'width', size.width);
  9229. this.rootNode.setAttributeNS(null, 'height', size.height);
  9230. //this._htmlContainer.style.top = "-" + (size.height + 4) + 'px';
  9231. if( !dontSetBounds ){
  9232. this.bounds.set({a:{x:0,y:0},b:{x:size.width/this.zoomLevel,y:size.height/this.zoomLevel}})
  9233. }
  9234. },
  9235. /**
  9236. * Returns an SVG document of the current process.
  9237. * @param {Boolean} escapeText Use true, if you want to parse it with an XmlParser,
  9238. * false, if you want to use the SVG document in browser on client side.
  9239. */
  9240. getSVGRepresentation: function(escapeText) {
  9241. // Get the serialized svg image source
  9242. var svgClone = this.getRootNode().cloneNode(true);
  9243. this._removeInvisibleElements(svgClone);
  9244. var x1, y1, x2, y2;
  9245. try {
  9246. var bb = this.getRootNode().childNodes[1].getBBox();
  9247. x1 = bb.x;
  9248. y1 = bb.y;
  9249. x2 = bb.x + bb.width;
  9250. y2 = bb.y + bb.height;
  9251. } catch(e) {
  9252. this.getChildShapes(true).each(function(shape) {
  9253. var absBounds = shape.absoluteBounds();
  9254. var ul = absBounds.upperLeft();
  9255. var lr = absBounds.lowerRight();
  9256. if(x1 == undefined) {
  9257. x1 = ul.x;
  9258. y1 = ul.y;
  9259. x2 = lr.x;
  9260. y2 = lr.y;
  9261. } else {
  9262. x1 = Math.min(x1, ul.x);
  9263. y1 = Math.min(y1, ul.y);
  9264. x2 = Math.max(x2, lr.x);
  9265. y2 = Math.max(y2, lr.y);
  9266. }
  9267. });
  9268. }
  9269. var margin = 50;
  9270. var width, height, tx, ty;
  9271. if(x1 == undefined) {
  9272. width = 0;
  9273. height = 0;
  9274. tx = 0;
  9275. ty = 0;
  9276. } else {
  9277. width = x2 - x1;
  9278. height = y2 - y1;
  9279. tx = -x1+margin/2;
  9280. ty = -y1+margin/2;
  9281. }
  9282. // Set the width and height
  9283. svgClone.setAttributeNS(null, 'width', width + margin);
  9284. svgClone.setAttributeNS(null, 'height', height + margin);
  9285. svgClone.childNodes[1].firstChild.setAttributeNS(null, 'transform', 'translate(' + tx + ", " + ty + ')');
  9286. //remove scale factor
  9287. svgClone.childNodes[1].removeAttributeNS(null, 'transform');
  9288. try{
  9289. var svgCont = svgClone.childNodes[1].childNodes[1];
  9290. svgCont.parentNode.removeChild(svgCont);
  9291. } catch(e) {}
  9292. if(escapeText) {
  9293. $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')).each(function(elem) {
  9294. elem.textContent = elem.textContent.escapeHTML();
  9295. });
  9296. $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text')).each(function(elem) {
  9297. if(elem.childNodes.length == 0)
  9298. elem.textContent = elem.textContent.escapeHTML();
  9299. });
  9300. }
  9301. // generating absolute urls for the pdf-exporter
  9302. $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'image')).each(function(elem) {
  9303. var href = elem.getAttributeNS("http://www.w3.org/1999/xlink","href");
  9304. if(!href.match("^(http|https)://")) {
  9305. href = window.location.protocol + "//" + window.location.host + href;
  9306. elem.setAttributeNS("http://www.w3.org/1999/xlink", "href", href);
  9307. }
  9308. });
  9309. // escape all links
  9310. $A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'a')).each(function(elem) {
  9311. elem.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", (elem.getAttributeNS("http://www.w3.org/1999/xlink","href")||"").escapeHTML());
  9312. });
  9313. return svgClone;
  9314. },
  9315. /**
  9316. * Removes all nodes (and its children) that has the
  9317. * attribute visibility set to "hidden"
  9318. */
  9319. _removeInvisibleElements: function(element) {
  9320. var index = 0;
  9321. while(index < element.childNodes.length) {
  9322. var child = element.childNodes[index];
  9323. if(child.getAttributeNS &&
  9324. child.getAttributeNS(null, "visibility") === "hidden") {
  9325. element.removeChild(child);
  9326. } else {
  9327. this._removeInvisibleElements(child);
  9328. index++;
  9329. }
  9330. }
  9331. },
  9332. /**
  9333. * This method checks all shapes on the canvas and removes all shapes that
  9334. * contain invalid bounds values or dockers values(NaN)
  9335. */
  9336. /*cleanUp: function(parent) {
  9337. if (!parent) {
  9338. parent = this;
  9339. }
  9340. parent.getChildShapes().each(function(shape){
  9341. var a = shape.bounds.a;
  9342. var b = shape.bounds.b;
  9343. if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) {
  9344. parent.remove(shape);
  9345. }
  9346. else {
  9347. shape.getDockers().any(function(docker) {
  9348. a = docker.bounds.a;
  9349. b = docker.bounds.b;
  9350. if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) {
  9351. parent.remove(shape);
  9352. return true;
  9353. }
  9354. return false;
  9355. });
  9356. shape.getMagnets().any(function(magnet) {
  9357. a = magnet.bounds.a;
  9358. b = magnet.bounds.b;
  9359. if (isNaN(a.x) || isNaN(a.y) || isNaN(b.x) || isNaN(b.y)) {
  9360. parent.remove(shape);
  9361. return true;
  9362. }
  9363. return false;
  9364. });
  9365. this.cleanUp(shape);
  9366. }
  9367. }.bind(this));
  9368. },*/
  9369. _delegateEvent: function(event) {
  9370. if(this.eventHandlerCallback && ( event.target == this.rootNode || event.target == this.rootNode.parentNode )) {
  9371. this.eventHandlerCallback(event, this);
  9372. }
  9373. },
  9374. toString: function() { return "Canvas " + this.id },
  9375. /**
  9376. * Calls {@link ORYX.Core.AbstractShape#toJSON} and adds some stencil set information.
  9377. */
  9378. toJSON: function() {
  9379. var json = arguments.callee.$.toJSON.apply(this, arguments);
  9380. // if(ORYX.CONFIG.STENCILSET_HANDLER.length > 0) {
  9381. // json.stencilset = {
  9382. // url: this.getStencil().stencilSet().namespace()
  9383. // };
  9384. // } else {
  9385. json.stencilset = {
  9386. url: this.getStencil().stencilSet().source(),
  9387. namespace: this.getStencil().stencilSet().namespace()
  9388. };
  9389. // }
  9390. return json;
  9391. }
  9392. });/**
  9393. * Copyright (c) 2006
  9394. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  9395. *
  9396. * Permission is hereby granted, free of charge, to any person obtaining a
  9397. * copy of this software and associated documentation files (the "Software"),
  9398. * to deal in the Software without restriction, including without limitation
  9399. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9400. * and/or sell copies of the Software, and to permit persons to whom the
  9401. * Software is furnished to do so, subject to the following conditions:
  9402. *
  9403. * The above copyright notice and this permission notice shall be included in
  9404. * all copies or substantial portions of the Software.
  9405. *
  9406. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  9407. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  9408. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  9409. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  9410. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  9411. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  9412. * DEALINGS IN THE SOFTWARE.
  9413. **/
  9414. var idCounter = 0;
  9415. var ID_PREFIX = "resource";
  9416. /**
  9417. * Main initialization method. To be called when loading
  9418. * of the document, including all scripts, is completed.
  9419. */
  9420. function init() {
  9421. /* When the blank image url is not set programatically to a local
  9422. * representation, a spacer gif on the site of ext is loaded from the
  9423. * internet. This causes problems when internet or the ext site are not
  9424. * available. */
  9425. Ext.BLANK_IMAGE_URL = (ORYX.CONFIG.BLANK_IMAGE) || (ORYX.PATH + 'libs/ext-2.0.2/resources/images/default/s.gif');
  9426. ORYX.Log.debug("Querying editor instances");
  9427. // Hack for WebKit to set the SVGElement-Classes
  9428. ORYX.Editor.setMissingClasses();
  9429. // If someone wants to create the editor instance himself
  9430. if (window.onOryxResourcesLoaded) {
  9431. window.onOryxResourcesLoaded();
  9432. }
  9433. // Else if this is a newly created model
  9434. else if(window.location.pathname.include(ORYX.CONFIG.ORYX_NEW_URL)){
  9435. new ORYX.Editor({
  9436. id: 'oryx-canvas123',
  9437. fullscreen: true,
  9438. stencilset: {
  9439. url: "/oryx" + ORYX.Utils.getParamFromUrl("stencilset")
  9440. }
  9441. });
  9442. }
  9443. // Else fetch the model from server and display editor
  9444. else {
  9445. //HACK for distinguishing between different backends
  9446. // Backend of 2008 uses /self URL ending
  9447. var modelUrl = window.location.href.replace(/#.*/g, "");
  9448. if(modelUrl.endsWith("/self")) {
  9449. modelUrl = modelUrl.replace("/self","/json");
  9450. } else {
  9451. var modelId = window.location.search.substring(4);
  9452. modelUrl = "../service/model/" + modelId + "/json";
  9453. }
  9454. ORYX.Editor.createByUrl(modelUrl, {
  9455. id: modelUrl
  9456. });
  9457. }
  9458. }
  9459. /**
  9460. @namespace Global Oryx name space
  9461. @name ORYX
  9462. */
  9463. if(!ORYX) {var ORYX = {};}
  9464. /**
  9465. * The Editor class.
  9466. * @class ORYX.Editor
  9467. * @extends Clazz
  9468. * @param {Object} config An editor object, passed to {@link ORYX.Editor#loadSerialized}
  9469. * @param {String} config.id Any ID that can be used inside the editor. If fullscreen=false, any HTML node with this id must be present to render the editor to this node.
  9470. * @param {boolean} [config.fullscreen=true] Render editor in fullscreen mode or not.
  9471. * @param {String} config.stencilset.url Stencil set URL.
  9472. * @param {String} [config.stencil.id] Stencil type used for creating the canvas.
  9473. * @param {Object} config.properties Any properties applied to the canvas.
  9474. */
  9475. ORYX.Editor = {
  9476. /** @lends ORYX.Editor.prototype */
  9477. // Defines the global dom event listener
  9478. DOMEventListeners: new Hash(),
  9479. // Defines the selection
  9480. selection: [],
  9481. // Defines the current zoom level
  9482. zoomLevel:1.0,
  9483. construct: function(config) {
  9484. // initialization.
  9485. this._eventsQueue = [];
  9486. this.loadedPlugins = [];
  9487. this.pluginsData = [];
  9488. //meta data about the model for the signavio warehouse
  9489. //directory, new, name, description, revision, model (the model data)
  9490. this.modelMetaData = config;
  9491. var model = config;
  9492. if(config.model) {
  9493. model = config.model;
  9494. }
  9495. this.id = model.resourceId;
  9496. if(!this.id) {
  9497. this.id = model.id;
  9498. if(!this.id) {
  9499. this.id = ORYX.Editor.provideId();
  9500. }
  9501. }
  9502. // Defines if the editor should be fullscreen or not
  9503. this.fullscreen = config.fullscreen !== false;
  9504. if (Signavio&&Signavio.Helper&&Signavio.Helper.ShowMask instanceof Function) {
  9505. Signavio.Helper.ShowMask(true, !this.fullscreen ? this.id : Ext.getBody());
  9506. }
  9507. // Initialize the eventlistener
  9508. this._initEventListener();
  9509. // Load particular stencilset
  9510. if(ORYX.CONFIG.BACKEND_SWITCH) {
  9511. var ssUrl = (model.stencilset.namespace||model.stencilset.url).replace("#", "%23");
  9512. ORYX.Core.StencilSet.loadStencilSet(ORYX.CONFIG.STENCILSET_HANDLER + ssUrl, this.id);
  9513. } else {
  9514. var ssUrl = model.stencilset.url;
  9515. ORYX.Core.StencilSet.loadStencilSet(ssUrl, this.id);
  9516. }
  9517. // CREATES the canvas
  9518. this._createCanvas(model.stencil ? model.stencil.id : null, model.properties);
  9519. // GENERATES the whole EXT.VIEWPORT
  9520. this._generateGUI();
  9521. // Initializing of a callback to check loading ends
  9522. var loadPluginFinished = false;
  9523. var loadContentFinished = false;
  9524. var initFinished = function(){
  9525. if( !loadPluginFinished || !loadContentFinished ){ return }
  9526. this._finishedLoading();
  9527. }.bind(this)
  9528. // disable key events when Ext modal window is active
  9529. ORYX.Editor.makeExtModalWindowKeysave(this._getPluginFacade());
  9530. // LOAD the plugins
  9531. window.setTimeout(function(){
  9532. this.loadPlugins();
  9533. loadPluginFinished = true;
  9534. initFinished();
  9535. }.bind(this), 100);
  9536. // LOAD the content of the current editor instance
  9537. window.setTimeout(function(){
  9538. this.loadSerialized(model, true); // Request the meta data as well
  9539. this.getCanvas().update();
  9540. loadContentFinished = true;
  9541. initFinished();
  9542. }.bind(this), 200);
  9543. },
  9544. _finishedLoading: function() {
  9545. if(Ext.getCmp('oryx-loading-panel')){
  9546. Ext.getCmp('oryx-loading-panel').hide()
  9547. }
  9548. // Do Layout for viewport
  9549. this.layout.doLayout();
  9550. // Generate a drop target
  9551. new Ext.dd.DropTarget(this.getCanvas().rootNode.parentNode);
  9552. // Fixed the problem that the viewport can not
  9553. // start with collapsed panels correctly
  9554. if (ORYX.CONFIG.PANEL_RIGHT_COLLAPSED === true){
  9555. this.layout_regions.east.collapse();
  9556. }
  9557. if (ORYX.CONFIG.PANEL_LEFT_COLLAPSED === true){
  9558. this.layout_regions.west.collapse();
  9559. }
  9560. // Raise Loaded Event
  9561. this.handleEvents( {type:ORYX.CONFIG.EVENT_LOADED} )
  9562. },
  9563. _initEventListener: function(){
  9564. // Register on Events
  9565. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYDOWN, this.catchKeyDownEvents.bind(this), false);
  9566. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_KEYUP, this.catchKeyUpEvents.bind(this), false);
  9567. // Enable Key up and down Event
  9568. this._keydownEnabled = true;
  9569. this._keyupEnabled = true;
  9570. this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEDOWN] = [];
  9571. this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEUP] = [];
  9572. this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOVER] = [];
  9573. this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEOUT] = [];
  9574. this.DOMEventListeners[ORYX.CONFIG.EVENT_SELECTION_CHANGED] = [];
  9575. this.DOMEventListeners[ORYX.CONFIG.EVENT_MOUSEMOVE] = [];
  9576. },
  9577. /**
  9578. * Generate the whole viewport of the
  9579. * Editor and initialized the Ext-Framework
  9580. *
  9581. */
  9582. _generateGUI: function() {
  9583. //TODO make the height be read from eRDF data from the canvas.
  9584. // default, a non-fullscreen editor shall define its height by layout.setHeight(int)
  9585. // Defines the layout hight if it's NOT fullscreen
  9586. var layoutHeight = ORYX.CONFIG.WINDOW_HEIGHT;
  9587. var canvasParent = this.getCanvas().rootNode.parentNode;
  9588. /**
  9589. * Extend the Region implementation so that,
  9590. * the clicking area can be extend to the whole collapse area and
  9591. * an title can now be shown.
  9592. *
  9593. */
  9594. var oldGetCollapsedEl = Ext.layout.BorderLayout.Region.prototype.getCollapsedEl;
  9595. Ext.layout.BorderLayout.Region.prototype.getCollapsedEl = function(){
  9596. oldGetCollapsedEl.apply(this, arguments);
  9597. if(this.collapseMode !== 'mini' && this.floatable === false && this.expandTriggerAll === true){
  9598. this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
  9599. this.collapsedEl.on("mouseover", this.collapsedEl.addClass.bind(this.collapsedEl, "x-layout-collapsed-over"));
  9600. this.collapsedEl.on("click", this.onExpandClick, this);
  9601. }
  9602. if (this.collapseTitle){
  9603. /* // Use CSS3 Attribute
  9604. this.collapsedEl.createChild({
  9605. cls: "x-collapse-text", html: this.collapseTitle
  9606. });*/
  9607. // Use SVG to rotate text
  9608. var svg = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.collapsedEl.dom,
  9609. ['svg', {style:"position:relative;left:"+(this.position === "west" ? 4 : 6)+"px;top:"+(this.position === "west" ? 2 : 5)+"px;"},
  9610. ['text', {transform:"rotate(90)", x:0, y:0, "stroke-width":"0px", fill:"#EEEEEE", style:"font-weight:bold;", "font-size":"11"}, this.collapseTitle]
  9611. ]);
  9612. var text = svg.childNodes[0];
  9613. svg.setAttribute("xmlns:svg", "http://www.w3.org/2000/svg");
  9614. // Rotate the west into the other side
  9615. if (this.position === "west" && text.getComputedTextLength instanceof Function){
  9616. // Wait till rendered
  9617. window.setTimeout(function(){
  9618. var length = text.getComputedTextLength();
  9619. text.setAttributeNS(null, "transform", "rotate(-90, " + ((length / 2) + 7) + ", " + ((length / 2) - 3) + ")");;
  9620. }, 1)
  9621. }
  9622. delete this.collapseTitle;
  9623. }
  9624. return this.collapsedEl;
  9625. }
  9626. // DEFINITION OF THE VIEWPORT AREAS
  9627. this.layout_regions = {
  9628. // DEFINES TOP-AREA
  9629. north : new Ext.Panel({ //TOOO make a composite of the oryx header and addable elements (for toolbar), second one should contain margins
  9630. region : 'north',
  9631. cls : 'x-panel-editor-north',
  9632. autoEl : 'div',
  9633. border : false
  9634. }),
  9635. // DEFINES RIGHT-AREA
  9636. east : new Ext.Panel({
  9637. region : 'east',
  9638. layout : 'fit',
  9639. cls : 'x-panel-editor-east',
  9640. /*layout: 'accordion',
  9641. layoutConfig: {
  9642. // layout-specific configs go here
  9643. titleCollapse: true,
  9644. animate: true,
  9645. activeOnTop: true
  9646. },*/
  9647. autoEl : 'div',
  9648. collapseTitle : ORYX.I18N.View.East,
  9649. border :false,
  9650. cmargins: {left:0, right:0},
  9651. floatable: false,
  9652. expandTriggerAll:true,
  9653. collapsible : true,
  9654. width : ORYX.CONFIG.PANEL_RIGHT_WIDTH || 200,
  9655. split : true,
  9656. title : "East"
  9657. }),
  9658. // DEFINES BOTTOM-AREA
  9659. south : new Ext.Panel({
  9660. region : 'south',
  9661. cls : 'x-panel-editor-south',
  9662. autoEl : 'div',
  9663. border : false
  9664. }),
  9665. // DEFINES LEFT-AREA
  9666. west : new Ext.Panel({
  9667. region : 'west',
  9668. layout : 'anchor',
  9669. autoEl : 'div',
  9670. cls : 'x-panel-editor-west',
  9671. collapsible : true,
  9672. collapseTitle : ORYX.I18N.View.West,
  9673. width : ORYX.CONFIG.PANEL_LEFT_WIDTH || 200,
  9674. autoScroll:true,
  9675. cmargins: {left:0, right:0},
  9676. floatable: false,
  9677. expandTriggerAll:true,
  9678. split : true,
  9679. title : "West"
  9680. }),
  9681. // DEFINES CENTER-AREA (FOR THE EDITOR)
  9682. center : new Ext.Panel({
  9683. region : 'center',
  9684. cls : 'x-panel-editor-center',
  9685. autoScroll: true,
  9686. items : {
  9687. layout : "fit",
  9688. autoHeight: true,
  9689. el : canvasParent
  9690. }
  9691. })
  9692. }
  9693. // Hide every region except the center
  9694. for (region in this.layout_regions) {
  9695. if ( region != "center" ) {
  9696. //this.layout_regions[ region ].hide();
  9697. }
  9698. }
  9699. // Config for the Ext.Viewport
  9700. var layout_config = {
  9701. layout: 'border',
  9702. items: [
  9703. this.layout_regions.north,
  9704. this.layout_regions.east,
  9705. this.layout_regions.south,
  9706. this.layout_regions.west,
  9707. this.layout_regions.center
  9708. ]
  9709. }
  9710. // IF Fullscreen, use a viewport
  9711. if (this.fullscreen) {
  9712. this.layout = new Ext.Viewport( layout_config )
  9713. // IF NOT, use a panel and render it to the given id
  9714. } else {
  9715. layout_config.renderTo = this.id;
  9716. layout_config.height = layoutHeight;
  9717. this.layout = new Ext.Panel( layout_config )
  9718. }
  9719. //Generates the ORYX-Header
  9720. //this._generateHeader();
  9721. // Set the editor to the center, and refresh the size
  9722. canvasParent.parentNode.setAttributeNS(null, 'align', 'center');
  9723. canvasParent.setAttributeNS(null, 'align', 'left');
  9724. this.getCanvas().setSize({
  9725. width : ORYX.CONFIG.CANVAS_WIDTH,
  9726. height : ORYX.CONFIG.CANVAS_HEIGHT
  9727. });
  9728. },
  9729. _generateHeader: function(){
  9730. var headerPanel = new Ext.Panel({
  9731. height : 30,
  9732. autoHeight : false,
  9733. border : false,
  9734. html : "<div id='oryx_editor_header'><a href=\""+ORYX.CONFIG.WEB_URL+"\" target=\"_self\"><img src='"+ORYX.PATH+"images/oryx.small.gif' border=\"0\" /></a><div style='clear: both;'></div><div id='close_editor'></div></div>"
  9735. });
  9736. var maActive = ORYX.MashupAPI && ORYX.MashupAPI.isUsed;
  9737. var maKey = maActive ? ORYX.MashupAPI.key : "";
  9738. var maCanRun = maActive ? ORYX.MashupAPI.canRun : false;
  9739. var maIsRemoteM = maActive ? ORYX.MashupAPI.isModelRemote : true;
  9740. var maModelImage= maIsRemoteM ? "<img src='"+ORYX.PATH+"images/page_white_put.png'/>" : "";
  9741. var maModelAuthI= maActive ? "<span class='mashupinfo'><img src='"+ORYX.PATH+"images/" +( maCanRun ? "plugin_error" : "plugin") +".png'/>" + maModelImage + "</span>" : "";
  9742. // Callback if the user changes
  9743. var fn = function(val){
  9744. var publicText = ORYX.I18N.Oryx.notLoggedOn;
  9745. var user = val && val.identifier && val.identifier != "public" ? decodeURI(val.identifier.gsub('"', "")).replace(/\+/g," ") : "";
  9746. if( user.length <= 0 ){
  9747. user = publicText;
  9748. }
  9749. var content = "<div id='editor_header'>" +
  9750. "<div id='header_logo_image'>" +
  9751. "<img src='../explorer/src/img/signavio/smoky/logo2.png' border=\"0\" usemap=\"#kisbpmmap\"/>" +
  9752. "<map id=\"kisbpmmap\" name=\"kisbpmmap\"><area shape=\"rect\" alt=\"kisbpm.com\" title=\"kisbpm.com\" coords=\"15,2,322,44\" href=\"http://kisbpm.com\" target=\"_blank\" /></map>" +
  9753. "</div>" +
  9754. "<span class='openid " + (publicText == user ? "not" : "") + "'>" +
  9755. (unescape(user)) +
  9756. maModelAuthI +
  9757. "</span>" +
  9758. // "<div id='header_close_image'>" +
  9759. // "<a href=\""+ORYX.CONFIG.WEB_URL+"\" target=\"_self\" title=\"close modeler\">" +
  9760. // "<img src='../editor/images/close_button.png' border=\"0\" />" +
  9761. // "</a>" +
  9762. // "</div>" +
  9763. "</div>";
  9764. if( headerPanel.body ){
  9765. headerPanel.body.dom.innerHTML = content;
  9766. } else {
  9767. headerPanel.html = content
  9768. }
  9769. };
  9770. ORYX.Editor.Cookie.onChange(fn);
  9771. fn(ORYX.Editor.Cookie.getParams());
  9772. // The oryx header
  9773. this.addToRegion("north", headerPanel );
  9774. },
  9775. /**
  9776. * adds a component to the specified region
  9777. *
  9778. * @param {String} region
  9779. * @param {Ext.Component} component
  9780. * @param {String} title, optional
  9781. * @return {Ext.Component} dom reference to the current region or null if specified region is unknown
  9782. */
  9783. addToRegion: function(region, component, title) {
  9784. if (region.toLowerCase && this.layout_regions[region.toLowerCase()]) {
  9785. var current_region = this.layout_regions[region.toLowerCase()];
  9786. current_region.add(component);
  9787. /*if( (region.toLowerCase() == 'east' || region.toLowerCase() == 'west') && current_region.items.length == 2){ //!current_region.getLayout() instanceof Ext.layout.Accordion ){
  9788. var layout = new Ext.layout.Accordion( current_region.layoutConfig );
  9789. current_region.setLayout( layout );
  9790. var items = current_region.items.clone();
  9791. current_region.items.each(function(item){ current_region.remove( item )})
  9792. items.each(function(item){ current_region.add( item )})
  9793. } */
  9794. ORYX.Log.debug("original dimensions of region %0: %1 x %2", current_region.region, current_region.width, current_region.height)
  9795. // update dimensions of region if required.
  9796. if (!current_region.width && component.initialConfig && component.initialConfig.width) {
  9797. ORYX.Log.debug("resizing width of region %0: %1", current_region.region, component.initialConfig.width)
  9798. current_region.setWidth(component.initialConfig.width)
  9799. }
  9800. if (component.initialConfig && component.initialConfig.height) {
  9801. ORYX.Log.debug("resizing height of region %0: %1", current_region.region, component.initialConfig.height)
  9802. var current_height = current_region.height || 0;
  9803. current_region.height = component.initialConfig.height + current_height;
  9804. current_region.setHeight(component.initialConfig.height + current_height)
  9805. }
  9806. // set title if provided as parameter.
  9807. if (typeof title == "string") {
  9808. current_region.setTitle(title);
  9809. }
  9810. // trigger doLayout() and show the pane
  9811. current_region.ownerCt.doLayout();
  9812. current_region.show();
  9813. if(Ext.isMac)
  9814. ORYX.Editor.resizeFix();
  9815. return current_region;
  9816. }
  9817. return null;
  9818. },
  9819. getAvailablePlugins: function(){
  9820. var curAvailablePlugins=ORYX.availablePlugins.clone();
  9821. curAvailablePlugins.each(function(plugin){
  9822. if(this.loadedPlugins.find(function(loadedPlugin){
  9823. return loadedPlugin.type==this.name;
  9824. }.bind(plugin))){
  9825. plugin.engaged=true;
  9826. }else{
  9827. plugin.engaged=false;
  9828. }
  9829. }.bind(this));
  9830. return curAvailablePlugins;
  9831. },
  9832. loadScript: function (url, callback){
  9833. var script = document.createElement("script")
  9834. script.type = "text/javascript";
  9835. if (script.readyState){ //IE
  9836. script.onreadystatechange = function(){
  9837. if (script.readyState == "loaded" || script.readyState == "complete"){
  9838. script.onreadystatechange = null;
  9839. callback();
  9840. }
  9841. };
  9842. } else { //Others
  9843. script.onload = function(){
  9844. callback();
  9845. };
  9846. }
  9847. script.src = url;
  9848. document.getElementsByTagName("head")[0].appendChild(script);
  9849. },
  9850. /**
  9851. * activate Plugin
  9852. *
  9853. * @param {String} name
  9854. * @param {Function} callback
  9855. * callback(sucess, [errorCode])
  9856. * errorCodes: NOTUSEINSTENCILSET, REQUIRESTENCILSET, NOTFOUND, YETACTIVATED
  9857. */
  9858. activatePluginByName: function(name, callback, loadTry){
  9859. var match=this.getAvailablePlugins().find(function(value){return value.name==name});
  9860. if(match && (!match.engaged || (match.engaged==='false'))){
  9861. var loadedStencilSetsNamespaces = this.getStencilSets().keys();
  9862. var facade = this._getPluginFacade();
  9863. var newPlugin;
  9864. var me=this;
  9865. ORYX.Log.debug("Initializing plugin '%0'", match.name);
  9866. if (!match.requires || !match.requires.namespaces || match.requires.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) ){
  9867. if(!match.notUsesIn || !match.notUsesIn.namespaces || !match.notUsesIn.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 })){
  9868. try {
  9869. var className = eval(match.name);
  9870. var newPlugin = new className(facade, match);
  9871. newPlugin.type = match.name;
  9872. // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data
  9873. if (newPlugin.registryChanged)
  9874. newPlugin.registryChanged(me.pluginsData);
  9875. // If there have an onSelection-Method it will pushed to the Editor Event-Handler
  9876. if (newPlugin.onSelectionChanged)
  9877. me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, newPlugin.onSelectionChanged.bind(newPlugin));
  9878. this.loadedPlugins.push(newPlugin);
  9879. this.loadedPlugins.each(function(loaded){
  9880. if(loaded.registryChanged)
  9881. loaded.registryChanged(this.pluginsData);
  9882. }.bind(me));
  9883. callback(true);
  9884. } catch(e) {
  9885. ORYX.Log.warn("Plugin %0 is not available", match.name);
  9886. if(!!loadTry){
  9887. callback(false,"INITFAILED");
  9888. return;
  9889. }
  9890. this.loadScript("plugins/scripts/"+match.source, this.activatePluginByName.bind(this,match.name,callback,true));
  9891. }
  9892. }else{
  9893. callback(false,"NOTUSEINSTENCILSET");
  9894. ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name);
  9895. }
  9896. } else {
  9897. callback(false,"REQUIRESTENCILSET");
  9898. ORYX.Log.info("Plugin need a stencilset which is not loaded'", match.name);
  9899. }
  9900. }else{
  9901. callback(false, match?"NOTFOUND":"YETACTIVATED");
  9902. //TODO error handling
  9903. }
  9904. },
  9905. /**
  9906. * Laden der Plugins
  9907. */
  9908. loadPlugins: function() {
  9909. // if there should be plugins but still are none, try again.
  9910. // TODO this should wait for every plugin respectively.
  9911. /*if (!ORYX.Plugins && ORYX.availablePlugins.length > 0) {
  9912. window.setTimeout(this.loadPlugins.bind(this), 100);
  9913. return;
  9914. }*/
  9915. var me = this;
  9916. var newPlugins = [];
  9917. var loadedStencilSetsNamespaces = this.getStencilSets().keys();
  9918. // Available Plugins will be initalize
  9919. var facade = this._getPluginFacade();
  9920. // If there is an Array where all plugins are described, than only take those
  9921. // (that comes from the usage of oryx with a mashup api)
  9922. if( ORYX.MashupAPI && ORYX.MashupAPI.loadablePlugins && ORYX.MashupAPI.loadablePlugins instanceof Array ){
  9923. // Get the plugins from the available plugins (those who are in the plugins.xml)
  9924. ORYX.availablePlugins = $A(ORYX.availablePlugins).findAll(function(value){
  9925. return ORYX.MashupAPI.loadablePlugins.include( value.name )
  9926. })
  9927. // Add those plugins to the list, which are only in the loadablePlugins list
  9928. ORYX.MashupAPI.loadablePlugins.each(function( className ){
  9929. if( !(ORYX.availablePlugins.find(function(val){ return val.name == className }))){
  9930. ORYX.availablePlugins.push( {name: className } );
  9931. }
  9932. })
  9933. }
  9934. ORYX.availablePlugins.each(function(value) {
  9935. ORYX.Log.debug("Initializing plugin '%0'", value.name);
  9936. if( (!value.requires || !value.requires.namespaces || value.requires.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) ) &&
  9937. (!value.notUsesIn || !value.notUsesIn.namespaces || !value.notUsesIn.namespaces.any(function(req){ return loadedStencilSetsNamespaces.indexOf(req) >= 0 }) )&&
  9938. /*only load activated plugins or undefined */
  9939. (value.engaged || (value.engaged===undefined)) ){
  9940. try {
  9941. var className = eval(value.name);
  9942. if( className ){
  9943. var plugin = new className(facade, value);
  9944. plugin.type = value.name;
  9945. newPlugins.push( plugin );
  9946. plugin.engaged=true;
  9947. }
  9948. } catch(e) {
  9949. ORYX.Log.warn("Plugin %0 is not available %1", value.name, e);
  9950. }
  9951. } else {
  9952. ORYX.Log.info("Plugin need a stencilset which is not loaded'", value.name);
  9953. }
  9954. });
  9955. newPlugins.each(function(value) {
  9956. // If there is an GUI-Plugin, they get all Plugins-Offer-Meta-Data
  9957. if(value.registryChanged)
  9958. value.registryChanged(me.pluginsData);
  9959. // If there have an onSelection-Method it will pushed to the Editor Event-Handler
  9960. if(value.onSelectionChanged)
  9961. me.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, value.onSelectionChanged.bind(value));
  9962. });
  9963. this.loadedPlugins = newPlugins;
  9964. // Hack for the Scrollbars
  9965. if(Ext.isMac) {
  9966. ORYX.Editor.resizeFix();
  9967. }
  9968. this.registerPluginsOnKeyEvents();
  9969. this.setSelection();
  9970. },
  9971. /**
  9972. * Creates the Canvas
  9973. * @param {String} [stencilType] The stencil type used for creating the canvas. If not given, a stencil with myBeRoot = true from current stencil set is taken.
  9974. * @param {Object} [canvasConfig] Any canvas properties (like language).
  9975. */
  9976. _createCanvas: function(stencilType, canvasConfig) {
  9977. if (stencilType) {
  9978. // Add namespace to stencilType
  9979. if (stencilType.search(/^http/) === -1) {
  9980. stencilType = this.getStencilSets().values()[0].namespace() + stencilType;
  9981. }
  9982. }
  9983. else {
  9984. // Get any root stencil type
  9985. stencilType = this.getStencilSets().values()[0].findRootStencilName();
  9986. }
  9987. // get the stencil associated with the type
  9988. var canvasStencil = ORYX.Core.StencilSet.stencil(stencilType);
  9989. if (!canvasStencil)
  9990. ORYX.Log.fatal("Initialisation failed, because the stencil with the type %0 is not part of one of the loaded stencil sets.", stencilType);
  9991. // create all dom
  9992. // TODO fix border, so the visible canvas has a double border and some spacing to the scrollbars
  9993. var div = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null, ['div']);
  9994. // set class for custom styling
  9995. div.addClassName("ORYX_Editor");
  9996. // create the canvas
  9997. this._canvas = new ORYX.Core.Canvas({
  9998. width : ORYX.CONFIG.CANVAS_WIDTH,
  9999. height : ORYX.CONFIG.CANVAS_HEIGHT,
  10000. 'eventHandlerCallback' : this.handleEvents.bind(this),
  10001. id : this.id,
  10002. parentNode : div
  10003. }, canvasStencil);
  10004. if (canvasConfig) {
  10005. // Migrate canvasConfig to an RDF-like structure
  10006. //FIXME this isn't nice at all because we don't want rdf any longer
  10007. var properties = [];
  10008. for(field in canvasConfig){
  10009. properties.push({
  10010. prefix: 'oryx',
  10011. name: field,
  10012. value: canvasConfig[field]
  10013. });
  10014. }
  10015. this._canvas.deserialize(properties);
  10016. }
  10017. },
  10018. /**
  10019. * Returns a per-editor singleton plugin facade.
  10020. * To be used in plugin initialization.
  10021. */
  10022. _getPluginFacade: function() {
  10023. // if there is no pluginfacade already created:
  10024. if(!(this._pluginFacade))
  10025. // create it.
  10026. this._pluginFacade = {
  10027. activatePluginByName: this.activatePluginByName.bind(this),
  10028. //deactivatePluginByName: this.deactivatePluginByName.bind(this),
  10029. getAvailablePlugins: this.getAvailablePlugins.bind(this),
  10030. offer: this.offer.bind(this),
  10031. getStencilSets: this.getStencilSets.bind(this),
  10032. getStencilSetExtensionDefinition:function(){ return Object.clone(this.ss_extensions_def||{})}.bind(this),
  10033. getRules: this.getRules.bind(this),
  10034. loadStencilSet: this.loadStencilSet.bind(this),
  10035. createShape: this.createShape.bind(this),
  10036. deleteShape: this.deleteShape.bind(this),
  10037. getSelection: this.getSelection.bind(this),
  10038. setSelection: this.setSelection.bind(this),
  10039. updateSelection: this.updateSelection.bind(this),
  10040. getCanvas: this.getCanvas.bind(this),
  10041. importJSON: this.importJSON.bind(this),
  10042. importERDF: this.importERDF.bind(this),
  10043. getERDF: this.getERDF.bind(this),
  10044. getJSON: this.getJSON.bind(this),
  10045. getSerializedJSON: this.getSerializedJSON.bind(this),
  10046. executeCommands: this.executeCommands.bind(this),
  10047. isExecutingCommands: this.isExecutingCommands.bind(this),
  10048. registerOnEvent: this.registerOnEvent.bind(this),
  10049. unregisterOnEvent: this.unregisterOnEvent.bind(this),
  10050. raiseEvent: this.handleEvents.bind(this),
  10051. enableEvent: this.enableEvent.bind(this),
  10052. disableEvent: this.disableEvent.bind(this),
  10053. eventCoordinates: this.eventCoordinates.bind(this),
  10054. addToRegion: this.addToRegion.bind(this),
  10055. getModelMetaData: this.getModelMetaData.bind(this)
  10056. };
  10057. // return it.
  10058. return this._pluginFacade;
  10059. },
  10060. isExecutingCommands: function(){
  10061. return !!this.commandExecuting;
  10062. },
  10063. /**
  10064. * Implementes the command pattern
  10065. * (The real usage of the command pattern
  10066. * is implemented and shown in the Plugins/undo.js)
  10067. *
  10068. * @param <Oryx.Core.Command>[] Array of commands
  10069. */
  10070. executeCommands: function(commands){
  10071. if (!this.commandStack){
  10072. this.commandStack = [];
  10073. }
  10074. if (!this.commandStackExecuted){
  10075. this.commandStackExecuted = [];
  10076. }
  10077. this.commandStack = [].concat(this.commandStack)
  10078. .concat(commands);
  10079. // Check if already executes
  10080. if (this.commandExecuting){ return; }
  10081. // Start execution
  10082. this.commandExecuting = true;
  10083. // Iterate over all commands
  10084. while(this.commandStack.length > 0){
  10085. var command = this.commandStack.shift();
  10086. // and execute it
  10087. command.execute();
  10088. this.commandStackExecuted.push(command);
  10089. }
  10090. // Raise event for executing commands
  10091. this.handleEvents({
  10092. type : ORYX.CONFIG.EVENT_EXECUTE_COMMANDS,
  10093. commands : this.commandStackExecuted
  10094. });
  10095. // Remove temporary vars
  10096. delete this.commandStack;
  10097. delete this.commandStackExecuted;
  10098. delete this.commandExecuting;
  10099. this.updateSelection();
  10100. },
  10101. /**
  10102. * Returns JSON of underlying canvas (calls ORYX.Canvas#toJSON()).
  10103. * @return {Object} Returns JSON representation as JSON object.
  10104. */
  10105. getJSON: function(){
  10106. var canvas = this.getCanvas().toJSON();
  10107. canvas.ssextensions = this.getStencilSets().values()[0].extensions().keys().findAll(function(sse){ return !sse.endsWith('/meta#') });
  10108. return canvas;
  10109. },
  10110. /**
  10111. * Serializes a call to toJSON().
  10112. * @return {String} Returns JSON representation as string.
  10113. */
  10114. getSerializedJSON: function(){
  10115. return Ext.encode(this.getJSON());
  10116. },
  10117. /**
  10118. * @return {String} Returns eRDF representation.
  10119. * @deprecated Use ORYX.Editor#getJSON instead, if possible.
  10120. */
  10121. getERDF:function(){
  10122. // Get the serialized dom
  10123. var serializedDOM = DataManager.serializeDOM( this._getPluginFacade() );
  10124. // Add xml definition if there is no
  10125. serializedDOM = '<?xml version="1.0" encoding="utf-8"?>' +
  10126. '<html xmlns="http://www.w3.org/1999/xhtml" ' +
  10127. 'xmlns:b3mn="http://b3mn.org/2007/b3mn" ' +
  10128. 'xmlns:ext="http://b3mn.org/2007/ext" ' +
  10129. 'xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ' +
  10130. 'xmlns:atom="http://b3mn.org/2007/atom+xhtml">' +
  10131. '<head profile="http://purl.org/NET/erdf/profile">' +
  10132. '<link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />' +
  10133. '<link rel="schema.dcTerms" href="http://purl.org/dc/terms/ " />' +
  10134. '<link rel="schema.b3mn" href="http://b3mn.org" />' +
  10135. '<link rel="schema.oryx" href="http://oryx-editor.org/" />' +
  10136. '<link rel="schema.raziel" href="http://raziel.org/" />' +
  10137. '<base href="' +
  10138. location.href.split("?")[0] +
  10139. '" />' +
  10140. '</head><body>' +
  10141. serializedDOM +
  10142. '</body></html>';
  10143. return serializedDOM;
  10144. },
  10145. /**
  10146. * Imports shapes in JSON as expected by {@link ORYX.Editor#loadSerialized}
  10147. * @param {Object|String} jsonObject The (serialized) json object to be imported
  10148. * @param {boolean } [noSelectionAfterImport=false] Set to true if no shapes should be selected after import
  10149. * @throws {SyntaxError} If the serialized json object contains syntax errors
  10150. */
  10151. importJSON: function(jsonObject, noSelectionAfterImport) {
  10152. try {
  10153. jsonObject = this.renewResourceIds(jsonObject);
  10154. } catch(error){
  10155. throw error;
  10156. }
  10157. //check, if the imported json model can be loaded in this editor
  10158. // (stencil set has to fit)
  10159. if(jsonObject.stencilset.namespace && jsonObject.stencilset.namespace !== this.getCanvas().getStencil().stencilSet().namespace()) {
  10160. Ext.Msg.alert(ORYX.I18N.JSONImport.title, String.format(ORYX.I18N.JSONImport.wrongSS, jsonObject.stencilset.namespace, this.getCanvas().getStencil().stencilSet().namespace()));
  10161. return null;
  10162. } else {
  10163. var commandClass = ORYX.Core.Command.extend({
  10164. construct: function(jsonObject, loadSerializedCB, noSelectionAfterImport, facade){
  10165. this.jsonObject = jsonObject;
  10166. this.noSelection = noSelectionAfterImport;
  10167. this.facade = facade;
  10168. this.shapes;
  10169. this.connections = [];
  10170. this.parents = new Hash();
  10171. this.selection = this.facade.getSelection();
  10172. this.loadSerialized = loadSerializedCB;
  10173. },
  10174. execute: function(){
  10175. if (!this.shapes) {
  10176. // Import the shapes out of the serialization
  10177. this.shapes = this.loadSerialized( this.jsonObject );
  10178. //store all connections
  10179. this.shapes.each(function(shape) {
  10180. if (shape.getDockers) {
  10181. var dockers = shape.getDockers();
  10182. if (dockers) {
  10183. if (dockers.length > 0) {
  10184. this.connections.push([dockers.first(), dockers.first().getDockedShape(), dockers.first().referencePoint]);
  10185. }
  10186. if (dockers.length > 1) {
  10187. this.connections.push([dockers.last(), dockers.last().getDockedShape(), dockers.last().referencePoint]);
  10188. }
  10189. }
  10190. }
  10191. //store parents
  10192. this.parents[shape.id] = shape.parent;
  10193. }.bind(this));
  10194. } else {
  10195. this.shapes.each(function(shape) {
  10196. this.parents[shape.id].add(shape);
  10197. }.bind(this));
  10198. this.connections.each(function(con) {
  10199. con[0].setDockedShape(con[1]);
  10200. con[0].setReferencePoint(con[2]);
  10201. con[0].update();
  10202. });
  10203. }
  10204. //this.parents.values().uniq().invoke("update");
  10205. this.facade.getCanvas().update();
  10206. if(!this.noSelection)
  10207. this.facade.setSelection(this.shapes);
  10208. else
  10209. this.facade.updateSelection();
  10210. // call updateSize again, because during loadSerialized the edges' bounds
  10211. // are not yet initialized properly
  10212. this.facade.getCanvas().updateSize();
  10213. },
  10214. rollback: function(){
  10215. var selection = this.facade.getSelection();
  10216. this.shapes.each(function(shape) {
  10217. selection = selection.without(shape);
  10218. this.facade.deleteShape(shape);
  10219. }.bind(this));
  10220. /*this.parents.values().uniq().each(function(parent) {
  10221. if(!this.shapes.member(parent))
  10222. parent.update();
  10223. }.bind(this));*/
  10224. this.facade.getCanvas().update();
  10225. this.facade.setSelection(selection);
  10226. }
  10227. })
  10228. var command = new commandClass(jsonObject,
  10229. this.loadSerialized.bind(this),
  10230. noSelectionAfterImport,
  10231. this._getPluginFacade());
  10232. this.executeCommands([command]);
  10233. return command.shapes.clone();
  10234. }
  10235. },
  10236. /**
  10237. * This method renew all resource Ids and according references.
  10238. * Warning: The implementation performs a substitution on the serialized object for
  10239. * easier implementation. This results in a low performance which is acceptable if this
  10240. * is only used when importing models.
  10241. * @param {Object|String} jsonObject
  10242. * @throws {SyntaxError} If the serialized json object contains syntax errors.
  10243. * @return {Object} The jsonObject with renewed ids.
  10244. * @private
  10245. */
  10246. renewResourceIds: function(jsonObject){
  10247. // For renewing resource ids, a serialized and object version is needed
  10248. if(Ext.type(jsonObject) === "string"){
  10249. try {
  10250. var serJsonObject = jsonObject;
  10251. jsonObject = Ext.decode(jsonObject);
  10252. } catch(error){
  10253. throw new SyntaxError(error.message);
  10254. }
  10255. } else {
  10256. var serJsonObject = Ext.encode(jsonObject);
  10257. }
  10258. // collect all resourceIds recursively
  10259. var collectResourceIds = function(shapes){
  10260. if(!shapes) return [];
  10261. return shapes.map(function(shape){
  10262. return collectResourceIds(shape.childShapes).concat(shape.resourceId);
  10263. }).flatten();
  10264. }
  10265. var resourceIds = collectResourceIds(jsonObject.childShapes);
  10266. // Replace each resource id by a new one
  10267. resourceIds.each(function(oldResourceId){
  10268. var newResourceId = ORYX.Editor.provideId();
  10269. serJsonObject = serJsonObject.gsub('"'+oldResourceId+'"', '"'+newResourceId+'"')
  10270. });
  10271. return Ext.decode(serJsonObject);
  10272. },
  10273. /**
  10274. * Import erdf structure to the editor
  10275. *
  10276. */
  10277. importERDF: function( erdfDOM ){
  10278. var serialized = this.parseToSerializeObjects( erdfDOM );
  10279. if(serialized)
  10280. return this.importJSON(serialized, true);
  10281. },
  10282. /**
  10283. * Parses one model (eRDF) to the serialized form (JSON)
  10284. *
  10285. * @param {Object} oneProcessData
  10286. * @return {Object} The JSON form of given eRDF model, or null if it couldn't be extracted
  10287. */
  10288. parseToSerializeObjects: function( oneProcessData ){
  10289. // Firefox splits a long text node into chunks of 4096 characters.
  10290. // To prevent truncation of long property values the normalize method must be called
  10291. if(oneProcessData.normalize) oneProcessData.normalize();
  10292. try {
  10293. var xsl = "";
  10294. var source=ORYX.PATH + "lib/extract-rdf.xsl";
  10295. new Ajax.Request(source, {
  10296. asynchronous: false,
  10297. method: 'get',
  10298. onSuccess: function(transport){
  10299. xsl = transport.responseText
  10300. }.bind(this),
  10301. onFailure: (function(transport){
  10302. ORYX.Log.error("XSL load failed" + transport);
  10303. }).bind(this)
  10304. });
  10305. var domParser = new DOMParser();
  10306. var xmlObject = oneProcessData;
  10307. var xslObject = domParser.parseFromString(xsl, "text/xml");
  10308. var xsltProcessor = new XSLTProcessor();
  10309. var xslRef = document.implementation.createDocument("", "", null);
  10310. xsltProcessor.importStylesheet(xslObject);
  10311. var new_rdf = xsltProcessor.transformToFragment(xmlObject, document);
  10312. var serialized_rdf = (new XMLSerializer()).serializeToString(new_rdf);
  10313. }catch(e){
  10314. Ext.Msg.alert("Oryx", error);
  10315. var serialized_rdf = "";
  10316. }
  10317. // Firefox 2 to 3 problem?!
  10318. serialized_rdf = !serialized_rdf.startsWith("<?xml") ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serialized_rdf : serialized_rdf;
  10319. var req = new Ajax.Request(ORYX.CONFIG.ROOT_PATH+"rdf2json", {
  10320. method: 'POST',
  10321. asynchronous: false,
  10322. onSuccess: function(transport) {
  10323. Ext.decode(transport.responseText);
  10324. },
  10325. parameters: {
  10326. rdf: serialized_rdf
  10327. }
  10328. });
  10329. return Ext.decode(req.transport.responseText);
  10330. },
  10331. /**
  10332. * Loads serialized model to the oryx.
  10333. * @example
  10334. * editor.loadSerialized({
  10335. * resourceId: "mymodel1",
  10336. * childShapes: [
  10337. * {
  10338. * stencil:{ id:"Subprocess" },
  10339. * outgoing:[{resourceId: 'aShape'}],
  10340. * target: {resourceId: 'aShape'},
  10341. * bounds:{ lowerRight:{ y:510, x:633 }, upperLeft:{ y:146, x:210 } },
  10342. * resourceId: "myshape1",
  10343. * childShapes:[],
  10344. * properties:{},
  10345. * }
  10346. * ],
  10347. * properties:{
  10348. * language: "English"
  10349. * },
  10350. * stencilset:{
  10351. * url:"http://localhost:8080/oryx/stencilsets/bpmn1.1/bpmn1.1.json"
  10352. * },
  10353. * stencil:{
  10354. * id:"BPMNDiagram"
  10355. * }
  10356. * });
  10357. * @param {Object} model Description of the model to load.
  10358. * @param {Array} [model.ssextensions] List of stenctil set extensions.
  10359. * @param {String} model.stencilset.url
  10360. * @param {String} model.stencil.id
  10361. * @param {Array} model.childShapes
  10362. * @param {Array} [model.properties]
  10363. * @param {String} model.resourceId
  10364. * @return {ORYX.Core.Shape[]} List of created shapes
  10365. * @methodOf ORYX.Editor.prototype
  10366. */
  10367. loadSerialized: function(model, requestMeta){
  10368. var canvas = this.getCanvas();
  10369. // Bugfix (cf. http://code.google.com/p/oryx-editor/issues/detail?id=240)
  10370. // Deserialize the canvas' stencil set extensions properties first!
  10371. this.loadSSExtensions(model.ssextensions);
  10372. // Load Meta Data Extension if available
  10373. // #Signavio
  10374. if (requestMeta === true) {
  10375. var metaDataExtension = this.getExtensionForMetaData();
  10376. if (metaDataExtension) {
  10377. this.loadSSExtension(metaDataExtension);
  10378. }
  10379. }
  10380. var shapes = this.getCanvas().addShapeObjects(model.childShapes, this.handleEvents.bind(this));
  10381. if(model.properties) {
  10382. for(key in model.properties) {
  10383. var value = model.properties[key];
  10384. var prop = this.getCanvas().getStencil().property("oryx-"+key);
  10385. if (!(typeof value === "string") && (!prop || !prop.isList())) {
  10386. value = Ext.encode(value);
  10387. }
  10388. this.getCanvas().setProperty("oryx-" + key, value);
  10389. }
  10390. }
  10391. this.getCanvas().updateSize();
  10392. // Force to update the selection
  10393. this.selection = [null];
  10394. this.setSelection([]);
  10395. return shapes;
  10396. },
  10397. /**
  10398. * Return the namespace of the extension which
  10399. * provided all the self defined meta data
  10400. * @return {String} Returns null if no extension is defined, otherwise the namespace
  10401. *
  10402. */
  10403. getExtensionForMetaData: function(){
  10404. if (!this.ss_extensions_def||!(this.ss_extensions_def.extensions instanceof Array)){
  10405. return null;
  10406. }
  10407. var stencilsets = this.getStencilSets();
  10408. var extension = this.ss_extensions_def.extensions.find(function(ex){
  10409. return !!stencilsets[ex["extends"]] && ex.namespace.endsWith("/meta#");
  10410. });
  10411. return extension ? extension.namespace || null : null;
  10412. },
  10413. /**
  10414. * Calls ORYX.Editor.prototype.ss_extension_namespace for each element
  10415. * @param {Array} ss_extension_namespaces An array of stencil set extension namespaces.
  10416. */
  10417. loadSSExtensions: function(ss_extension_namespaces){
  10418. if(!ss_extension_namespaces) return;
  10419. ss_extension_namespaces.each(function(ss_extension_namespace){
  10420. this.loadSSExtension(ss_extension_namespace);
  10421. }.bind(this));
  10422. },
  10423. /**
  10424. * Loads a stencil set extension.
  10425. * The stencil set extensions definiton file must already
  10426. * be loaded when the editor is initialized.
  10427. */
  10428. loadSSExtension: function(ss_extension_namespace) {
  10429. if (this.ss_extensions_def) {
  10430. var extension = this.ss_extensions_def.extensions.find(function(ex){
  10431. return (ex.namespace == ss_extension_namespace);
  10432. });
  10433. if (!extension) {
  10434. return;
  10435. }
  10436. var stencilset = this.getStencilSets()[extension["extends"]];
  10437. if (!stencilset) {
  10438. return;
  10439. }
  10440. // Check if absolute or relative url
  10441. if ((extension["definition"]||"").startsWith("/")){
  10442. stencilset.addExtension(extension["definition"])
  10443. } else {
  10444. stencilset.addExtension(ORYX.CONFIG.SS_EXTENSIONS_FOLDER + extension["definition"])
  10445. }
  10446. //stencilset.addExtension("/oryx/build/stencilsets/extensions/" + extension["definition"])
  10447. this.getRules().initializeRules(stencilset);
  10448. this._getPluginFacade().raiseEvent({
  10449. type: ORYX.CONFIG.EVENT_STENCIL_SET_LOADED
  10450. });
  10451. }
  10452. },
  10453. disableEvent: function(eventType){
  10454. if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
  10455. this._keydownEnabled = false;
  10456. }
  10457. if(eventType == ORYX.CONFIG.EVENT_KEYUP) {
  10458. this._keyupEnabled = false;
  10459. }
  10460. if(this.DOMEventListeners.keys().member(eventType)) {
  10461. var value = this.DOMEventListeners.remove(eventType);
  10462. this.DOMEventListeners['disable_' + eventType] = value;
  10463. }
  10464. },
  10465. enableEvent: function(eventType){
  10466. if(eventType == ORYX.CONFIG.EVENT_KEYDOWN) {
  10467. this._keydownEnabled = true;
  10468. }
  10469. if(eventType == ORYX.CONFIG.EVENT_KEYUP) {
  10470. this._keyupEnabled = true;
  10471. }
  10472. if(this.DOMEventListeners.keys().member("disable_" + eventType)) {
  10473. var value = this.DOMEventListeners.remove("disable_" + eventType);
  10474. this.DOMEventListeners[eventType] = value;
  10475. }
  10476. },
  10477. /**
  10478. * Methods for the PluginFacade
  10479. */
  10480. registerOnEvent: function(eventType, callback) {
  10481. if(!(this.DOMEventListeners.keys().member(eventType))) {
  10482. this.DOMEventListeners[eventType] = [];
  10483. }
  10484. this.DOMEventListeners[eventType].push(callback);
  10485. },
  10486. unregisterOnEvent: function(eventType, callback) {
  10487. if(this.DOMEventListeners.keys().member(eventType)) {
  10488. this.DOMEventListeners[eventType] = this.DOMEventListeners[eventType].without(callback);
  10489. } else {
  10490. // Event is not supported
  10491. // TODO: Error Handling
  10492. }
  10493. },
  10494. getSelection: function() {
  10495. return this.selection || [];
  10496. },
  10497. getStencilSets: function() {
  10498. return ORYX.Core.StencilSet.stencilSets(this.id);
  10499. },
  10500. getRules: function() {
  10501. return ORYX.Core.StencilSet.rules(this.id);
  10502. },
  10503. loadStencilSet: function(source) {
  10504. try {
  10505. ORYX.Core.StencilSet.loadStencilSet(source, this.id);
  10506. this.handleEvents({type:ORYX.CONFIG.EVENT_STENCIL_SET_LOADED});
  10507. } catch (e) {
  10508. ORYX.Log.warn("Requesting stencil set file failed. (" + e + ")");
  10509. }
  10510. },
  10511. offer: function(pluginData) {
  10512. if(!this.pluginsData.member(pluginData)){
  10513. this.pluginsData.push(pluginData);
  10514. }
  10515. },
  10516. /**
  10517. * It creates an new event or adds the callback, if already existing,
  10518. * for the key combination that the plugin passes in keyCodes attribute
  10519. * of the offer method.
  10520. *
  10521. * The new key down event fits the schema:
  10522. * key.event[.metactrl][.alt][.shift].'thekeyCode'
  10523. */
  10524. registerPluginsOnKeyEvents: function() {
  10525. this.pluginsData.each(function(pluginData) {
  10526. if(pluginData.keyCodes) {
  10527. pluginData.keyCodes.each(function(keyComb) {
  10528. var eventName = "key.event";
  10529. /* Include key action */
  10530. eventName += '.' + keyComb.keyAction;
  10531. if(keyComb.metaKeys) {
  10532. /* Register on ctrl or apple meta key as meta key */
  10533. if(keyComb.metaKeys.
  10534. indexOf(ORYX.CONFIG.META_KEY_META_CTRL) > -1) {
  10535. eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL;
  10536. }
  10537. /* Register on alt key as meta key */
  10538. if(keyComb.metaKeys.
  10539. indexOf(ORYX.CONFIG.META_KEY_ALT) > -1) {
  10540. eventName += '.' + ORYX.CONFIG.META_KEY_ALT;
  10541. }
  10542. /* Register on shift key as meta key */
  10543. if(keyComb.metaKeys.
  10544. indexOf(ORYX.CONFIG.META_KEY_SHIFT) > -1) {
  10545. eventName += '.' + ORYX.CONFIG.META_KEY_SHIFT;
  10546. }
  10547. }
  10548. /* Register on the actual key */
  10549. if(keyComb.keyCode) {
  10550. eventName += '.' + keyComb.keyCode;
  10551. }
  10552. /* Register the event */
  10553. ORYX.Log.debug("Register Plugin on Key Event: %0", eventName);
  10554. if (pluginData.toggle === true && pluginData.buttonInstance) {
  10555. this.registerOnEvent(eventName, function(){
  10556. pluginData.buttonInstance.toggle(!pluginData.buttonInstance.pressed); // Toggle
  10557. pluginData.functionality.call(pluginData, pluginData.buttonInstance, pluginData.buttonInstance.pressed); // Call function
  10558. });
  10559. } else {
  10560. this.registerOnEvent(eventName, pluginData.functionality)
  10561. }
  10562. }.bind(this));
  10563. }
  10564. }.bind(this));
  10565. },
  10566. isEqual: function(a,b){
  10567. return a === b || (a.length === b.length && a.all(function(r){ return b.include(r) }))
  10568. },
  10569. isDirty: function(a){
  10570. return a.any(function(shape){ return shape.isPropertyChanged() })
  10571. },
  10572. setSelection: function(elements, subSelectionElement, force) {
  10573. if (!elements) { elements = []; }
  10574. if (!(elements instanceof Array)) { elements = [elements]; }
  10575. elements = elements.findAll(function(n){ return n && n instanceof ORYX.Core.Shape });
  10576. if (elements[0] instanceof ORYX.Core.Canvas) {
  10577. elements = [];
  10578. }
  10579. if (!force && this.isEqual(this.selection, elements) && !this.isDirty(elements)){
  10580. return;
  10581. }
  10582. this.selection = elements;
  10583. this._subSelection = subSelectionElement;
  10584. this.handleEvents({type:ORYX.CONFIG.EVENT_SELECTION_CHANGED, elements:elements, subSelection: subSelectionElement, force: !!force})
  10585. },
  10586. updateSelection: function() {
  10587. this.setSelection(this.selection, this._subSelection, true);
  10588. /*var s = this.selection;
  10589. this.setSelection();
  10590. this.setSelection(s);*/
  10591. },
  10592. getCanvas: function() {
  10593. return this._canvas;
  10594. },
  10595. /**
  10596. * option = {
  10597. * type: string,
  10598. * position: {x:int, y:int},
  10599. * connectingType: uiObj-Class
  10600. * connectedShape: uiObj
  10601. * draggin: bool
  10602. * namespace: url
  10603. * parent: ORYX.Core.AbstractShape
  10604. * template: a template shape that the newly created inherits properties from.
  10605. * }
  10606. */
  10607. createShape: function(option) {
  10608. if(option && option.serialize && option.serialize instanceof Array){
  10609. var type = option.serialize.find(function(obj){return (obj.prefix+"-"+obj.name) == "oryx-type"});
  10610. var stencil = ORYX.Core.StencilSet.stencil(type.value);
  10611. if(stencil.type() == 'node'){
  10612. var newShapeObject = new ORYX.Core.Node({'eventHandlerCallback':this.handleEvents.bind(this)}, stencil);
  10613. } else {
  10614. var newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, stencil);
  10615. }
  10616. this.getCanvas().add(newShapeObject);
  10617. newShapeObject.deserialize(option.serialize);
  10618. return newShapeObject;
  10619. }
  10620. // If there is no argument, throw an exception
  10621. if(!option || !option.type || !option.namespace) { throw "To create a new shape you have to give an argument with type and namespace";}
  10622. var canvas = this.getCanvas();
  10623. var newShapeObject;
  10624. // Get the shape type
  10625. var shapetype = option.type;
  10626. // Get the stencil set
  10627. var sset = ORYX.Core.StencilSet.stencilSet(option.namespace);
  10628. // Create an New Shape, dependents on an Edge or a Node
  10629. if(sset.stencil(shapetype).type() == "node") {
  10630. newShapeObject = new ORYX.Core.Node({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(shapetype))
  10631. } else {
  10632. newShapeObject = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(shapetype))
  10633. }
  10634. // when there is a template, inherit the properties.
  10635. if(option.template) {
  10636. newShapeObject._jsonStencil.properties = option.template._jsonStencil.properties;
  10637. newShapeObject.postProcessProperties();
  10638. }
  10639. // Add to the canvas
  10640. if(option.parent && newShapeObject instanceof ORYX.Core.Node) {
  10641. option.parent.add(newShapeObject);
  10642. } else {
  10643. canvas.add(newShapeObject);
  10644. }
  10645. // Set the position
  10646. var point = option.position ? option.position : {x:100, y:200};
  10647. var con;
  10648. // If there is create a shape and in the argument there is given an ConnectingType and is instance of an edge
  10649. if(option.connectingType && option.connectedShape && !(newShapeObject instanceof ORYX.Core.Edge)) {
  10650. // there will be create a new Edge
  10651. con = new ORYX.Core.Edge({'eventHandlerCallback':this.handleEvents.bind(this)}, sset.stencil(option.connectingType));
  10652. // And both endings dockers will be referenced to the both shapes
  10653. con.dockers.first().setDockedShape(option.connectedShape);
  10654. var magnet = option.connectedShape.getDefaultMagnet()
  10655. var cPoint = magnet ? magnet.bounds.center() : option.connectedShape.bounds.midPoint();
  10656. con.dockers.first().setReferencePoint( cPoint );
  10657. con.dockers.last().setDockedShape(newShapeObject);
  10658. con.dockers.last().setReferencePoint(newShapeObject.getDefaultMagnet().bounds.center());
  10659. // The Edge will be added to the canvas and be updated
  10660. canvas.add(con);
  10661. //con.update();
  10662. }
  10663. // Move the new Shape to the position
  10664. if(newShapeObject instanceof ORYX.Core.Edge && option.connectedShape) {
  10665. newShapeObject.dockers.first().setDockedShape(option.connectedShape);
  10666. if( option.connectedShape instanceof ORYX.Core.Node ){
  10667. newShapeObject.dockers.first().setReferencePoint(option.connectedShape.getDefaultMagnet().bounds.center());
  10668. newShapeObject.dockers.last().bounds.centerMoveTo(point);
  10669. } else {
  10670. newShapeObject.dockers.first().setReferencePoint(option.connectedShape.bounds.midPoint());
  10671. }
  10672. } else {
  10673. var b = newShapeObject.bounds
  10674. if( newShapeObject instanceof ORYX.Core.Node && newShapeObject.dockers.length == 1){
  10675. b = newShapeObject.dockers.first().bounds
  10676. }
  10677. b.centerMoveTo(point);
  10678. var upL = b.upperLeft();
  10679. b.moveBy( -Math.min(upL.x, 0) , -Math.min(upL.y, 0) )
  10680. var lwR = b.lowerRight();
  10681. b.moveBy( -Math.max(lwR.x-canvas.bounds.width(), 0) , -Math.max(lwR.y-canvas.bounds.height(), 0) )
  10682. }
  10683. // Update the shape
  10684. if (newShapeObject instanceof ORYX.Core.Edge) {
  10685. newShapeObject._update(false);
  10686. }
  10687. // And refresh the selection
  10688. if(!(newShapeObject instanceof ORYX.Core.Edge)&&!(option.dontUpdateSelection)) {
  10689. this.setSelection([newShapeObject]);
  10690. }
  10691. if(con && con.alignDockers) {
  10692. con.alignDockers();
  10693. }
  10694. if(newShapeObject.alignDockers) {
  10695. newShapeObject.alignDockers();
  10696. }
  10697. return newShapeObject;
  10698. },
  10699. deleteShape: function(shape) {
  10700. if (!shape || !shape.parent){ return }
  10701. //remove shape from parent
  10702. // this also removes it from DOM
  10703. shape.parent.remove(shape);
  10704. //delete references to outgoing edges
  10705. shape.getOutgoingShapes().each(function(os) {
  10706. var docker = os.getDockers().first();
  10707. if(docker && docker.getDockedShape() == shape) {
  10708. docker.setDockedShape(undefined);
  10709. }
  10710. });
  10711. //delete references to incoming edges
  10712. shape.getIncomingShapes().each(function(is) {
  10713. var docker = is.getDockers().last();
  10714. if(docker && docker.getDockedShape() == shape) {
  10715. docker.setDockedShape(undefined);
  10716. }
  10717. });
  10718. //delete references of the shape's dockers
  10719. shape.getDockers().each(function(docker) {
  10720. docker.setDockedShape(undefined);
  10721. });
  10722. },
  10723. /**
  10724. * Returns an object with meta data about the model.
  10725. * Like name, description, ...
  10726. *
  10727. * Empty object with the current backend.
  10728. *
  10729. * @return {Object} Meta data about the model
  10730. */
  10731. getModelMetaData: function() {
  10732. return this.modelMetaData;
  10733. },
  10734. /* Event-Handler Methods */
  10735. /**
  10736. * Helper method to execute an event immediately. The event is not
  10737. * scheduled in the _eventsQueue. Needed to handle Layout-Callbacks.
  10738. */
  10739. _executeEventImmediately: function(eventObj) {
  10740. if(this.DOMEventListeners.keys().member(eventObj.event.type)) {
  10741. this.DOMEventListeners[eventObj.event.type].each((function(value) {
  10742. value(eventObj.event, eventObj.arg);
  10743. }).bind(this));
  10744. }
  10745. },
  10746. _executeEvents: function() {
  10747. this._queueRunning = true;
  10748. while(this._eventsQueue.length > 0) {
  10749. var val = this._eventsQueue.shift();
  10750. this._executeEventImmediately(val);
  10751. }
  10752. this._queueRunning = false;
  10753. },
  10754. /**
  10755. * Leitet die Events an die Editor-Spezifischen Event-Methoden weiter
  10756. * @param {Object} event Event , welches gefeuert wurde
  10757. * @param {Object} uiObj Target-UiObj
  10758. */
  10759. handleEvents: function(event, uiObj) {
  10760. ORYX.Log.trace("Dispatching event type %0 on %1", event.type, uiObj);
  10761. switch(event.type) {
  10762. case ORYX.CONFIG.EVENT_MOUSEDOWN:
  10763. this._handleMouseDown(event, uiObj);
  10764. break;
  10765. case ORYX.CONFIG.EVENT_MOUSEMOVE:
  10766. this._handleMouseMove(event, uiObj);
  10767. break;
  10768. case ORYX.CONFIG.EVENT_MOUSEUP:
  10769. this._handleMouseUp(event, uiObj);
  10770. break;
  10771. case ORYX.CONFIG.EVENT_MOUSEOVER:
  10772. this._handleMouseHover(event, uiObj);
  10773. break;
  10774. case ORYX.CONFIG.EVENT_MOUSEOUT:
  10775. this._handleMouseOut(event, uiObj);
  10776. break;
  10777. }
  10778. /* Force execution if necessary. Used while handle Layout-Callbacks. */
  10779. if(event.forceExecution) {
  10780. this._executeEventImmediately({event: event, arg: uiObj});
  10781. } else {
  10782. this._eventsQueue.push({event: event, arg: uiObj});
  10783. }
  10784. if(!this._queueRunning) {
  10785. this._executeEvents();
  10786. }
  10787. // TODO: Make this return whether no listener returned false.
  10788. // So that, when one considers bubbling undesireable, it won't happen.
  10789. return false;
  10790. },
  10791. isValidEvent: function(e){
  10792. try {
  10793. var isInput = ["INPUT", "TEXTAREA"].include(e.target.tagName.toUpperCase());
  10794. var gridHasFocus = e.target.className.include("x-grid3-focus") && !e.target.className.include("x-grid3-focus-canvas");
  10795. return !isInput && !gridHasFocus;
  10796. } catch(e){
  10797. return false;
  10798. }
  10799. },
  10800. catchKeyUpEvents: function(event) {
  10801. if(!this._keyupEnabled) {
  10802. return;
  10803. }
  10804. /* assure we have the current event. */
  10805. if (!event)
  10806. event = window.event;
  10807. // Checks if the event comes from some input field
  10808. if (!this.isValidEvent(event)){
  10809. return;
  10810. }
  10811. /* Create key up event type */
  10812. var keyUpEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_UP);
  10813. ORYX.Log.debug("Key Event to handle: %0", keyUpEvent);
  10814. /* forward to dispatching. */
  10815. this.handleEvents({type: keyUpEvent, event:event});
  10816. },
  10817. /**
  10818. * Catches all key down events and forward the appropriated event to
  10819. * dispatching concerning to the pressed keys.
  10820. *
  10821. * @param {Event}
  10822. * The key down event to handle
  10823. */
  10824. catchKeyDownEvents: function(event) {
  10825. if(!this._keydownEnabled) {
  10826. return;
  10827. }
  10828. /* Assure we have the current event. */
  10829. if (!event)
  10830. event = window.event;
  10831. /* Fixed in FF3 */
  10832. // This is a mac-specific fix. The mozilla event object has no knowledge
  10833. // of meta key modifier on osx, however, it is needed for certain
  10834. // shortcuts. This fix adds the metaKey field to the event object, so
  10835. // that all listeners that registered per Oryx plugin facade profit from
  10836. // this. The original bug is filed in
  10837. // https://bugzilla.mozilla.org/show_bug.cgi?id=418334
  10838. //if (this.__currentKey == ORYX.CONFIG.KEY_CODE_META) {
  10839. // event.appleMetaKey = true;
  10840. //}
  10841. //this.__currentKey = pressedKey;
  10842. // Checks if the event comes from some input field
  10843. if (!this.isValidEvent(event)){
  10844. return;
  10845. }
  10846. /* Create key up event type */
  10847. var keyDownEvent = this.createKeyCombEvent(event, ORYX.CONFIG.KEY_ACTION_DOWN);
  10848. ORYX.Log.debug("Key Event to handle: %0", keyDownEvent);
  10849. /* Forward to dispatching. */
  10850. this.handleEvents({type: keyDownEvent,event: event});
  10851. },
  10852. /**
  10853. * Creates the event type name concerning to the pressed keys.
  10854. *
  10855. * @param {Event} keyDownEvent
  10856. * The source keyDownEvent to build up the event name
  10857. */
  10858. createKeyCombEvent: function(keyEvent, keyAction) {
  10859. /* Get the currently pressed key code. */
  10860. var pressedKey = keyEvent.which || keyEvent.keyCode;
  10861. //this.__currentKey = pressedKey;
  10862. /* Event name */
  10863. var eventName = "key.event";
  10864. /* Key action */
  10865. if(keyAction) {
  10866. eventName += "." + keyAction;
  10867. }
  10868. /* Ctrl or apple meta key is pressed */
  10869. if(keyEvent.ctrlKey || keyEvent.metaKey) {
  10870. eventName += "." + ORYX.CONFIG.META_KEY_META_CTRL;
  10871. }
  10872. /* Alt key is pressed */
  10873. if(keyEvent.altKey) {
  10874. eventName += "." + ORYX.CONFIG.META_KEY_ALT;
  10875. }
  10876. /* Alt key is pressed */
  10877. if(keyEvent.shiftKey) {
  10878. eventName += "." + ORYX.CONFIG.META_KEY_SHIFT;
  10879. }
  10880. /* Return the composed event name */
  10881. return eventName + "." + pressedKey;
  10882. },
  10883. _handleMouseDown: function(event, uiObj) {
  10884. // get canvas.
  10885. var canvas = this.getCanvas();
  10886. // Try to get the focus
  10887. canvas.focus()
  10888. // find the shape that is responsible for this element's id.
  10889. var element = event.currentTarget;
  10890. var elementController = uiObj;
  10891. // gather information on selection.
  10892. var currentIsSelectable = (elementController !== null) &&
  10893. (elementController !== undefined) && (elementController.isSelectable);
  10894. var currentIsMovable = (elementController !== null) &&
  10895. (elementController !== undefined) && (elementController.isMovable);
  10896. var modifierKeyPressed = event.shiftKey || event.ctrlKey;
  10897. var noObjectsSelected = this.selection.length === 0;
  10898. var currentIsSelected = this.selection.member(elementController);
  10899. // Rule #1: When there is nothing selected, select the clicked object.
  10900. if(currentIsSelectable && noObjectsSelected) {
  10901. this.setSelection([elementController]);
  10902. ORYX.Log.trace("Rule #1 applied for mouse down on %0", element.id);
  10903. // Rule #3: When at least one element is selected, and there is no
  10904. // control key pressed, and the clicked object is not selected, select
  10905. // the clicked object.
  10906. } else if(currentIsSelectable && !noObjectsSelected &&
  10907. !modifierKeyPressed && !currentIsSelected) {
  10908. this.setSelection([elementController]);
  10909. //var objectType = elementController.readAttributes();
  10910. //alert(objectType[0] + ": " + objectType[1]);
  10911. ORYX.Log.trace("Rule #3 applied for mouse down on %0", element.id);
  10912. // Rule #4: When the control key is pressed, and the current object is
  10913. // not selected, add it to the selection.
  10914. } else if(currentIsSelectable && modifierKeyPressed
  10915. && !currentIsSelected) {
  10916. var newSelection = this.selection.clone();
  10917. newSelection.push(elementController)
  10918. this.setSelection(newSelection)
  10919. ORYX.Log.trace("Rule #4 applied for mouse down on %0", element.id);
  10920. // Rule #6
  10921. } else if(currentIsSelectable && currentIsSelected &&
  10922. modifierKeyPressed) {
  10923. var newSelection = this.selection.clone();
  10924. this.setSelection(newSelection.without(elementController))
  10925. ORYX.Log.trace("Rule #6 applied for mouse down on %0", elementController.id);
  10926. // Rule #5: When there is at least one object selected and no control
  10927. // key pressed, we're dragging.
  10928. /*} else if(currentIsSelectable && !noObjectsSelected
  10929. && !modifierKeyPressed) {
  10930. if(this.log.isTraceEnabled())
  10931. this.log.trace("Rule #5 applied for mouse down on "+element.id);
  10932. */
  10933. // Rule #2: When clicked on something that is neither
  10934. // selectable nor movable, clear the selection, and return.
  10935. } else if (!currentIsSelectable && !currentIsMovable) {
  10936. this.setSelection([]);
  10937. ORYX.Log.trace("Rule #2 applied for mouse down on %0", element.id);
  10938. return;
  10939. // Rule #7: When the current object is not selectable but movable,
  10940. // it is probably a control. Leave the selection unchanged but set
  10941. // the movedObject to the current one and enable Drag. Dockers will
  10942. // be processed in the dragDocker plugin.
  10943. } else if(!currentIsSelectable && currentIsMovable && !(elementController instanceof ORYX.Core.Controls.Docker)) {
  10944. // TODO: If there is any moveable elements, do this in a plugin
  10945. //ORYX.Core.UIEnableDrag(event, elementController);
  10946. ORYX.Log.trace("Rule #7 applied for mouse down on %0", element.id);
  10947. // Rule #8: When the element is selectable and is currently selected and no
  10948. // modifier key is pressed
  10949. } else if(currentIsSelectable && currentIsSelected &&
  10950. !modifierKeyPressed) {
  10951. this._subSelection = this._subSelection != elementController ? elementController : undefined;
  10952. this.setSelection(this.selection, this._subSelection);
  10953. ORYX.Log.trace("Rule #8 applied for mouse down on %0", element.id);
  10954. }
  10955. // prevent event from bubbling, return.
  10956. //Event.stop(event);
  10957. return;
  10958. },
  10959. _handleMouseMove: function(event, uiObj) {
  10960. return;
  10961. },
  10962. _handleMouseUp: function(event, uiObj) {
  10963. // get canvas.
  10964. var canvas = this.getCanvas();
  10965. // find the shape that is responsible for this elemement's id.
  10966. var elementController = uiObj;
  10967. //get event position
  10968. var evPos = this.eventCoordinates(event);
  10969. //Event.stop(event);
  10970. },
  10971. _handleMouseHover: function(event, uiObj) {
  10972. return;
  10973. },
  10974. _handleMouseOut: function(event, uiObj) {
  10975. return;
  10976. },
  10977. /**
  10978. * Calculates the event coordinates to SVG document coordinates.
  10979. * @param {Event} event
  10980. * @return {SVGPoint} The event coordinates in the SVG document
  10981. */
  10982. eventCoordinates: function(event) {
  10983. var canvas = this.getCanvas();
  10984. var svgPoint = canvas.node.ownerSVGElement.createSVGPoint();
  10985. svgPoint.x = event.clientX;
  10986. svgPoint.y = event.clientY;
  10987. var matrix = canvas.node.getScreenCTM();
  10988. return svgPoint.matrixTransform(matrix.inverse());
  10989. }
  10990. };
  10991. ORYX.Editor = Clazz.extend(ORYX.Editor);
  10992. /**
  10993. * Creates a new ORYX.Editor instance by fetching a model from given url and passing it to the constructur
  10994. * @param {String} modelUrl The JSON URL of a model.
  10995. * @param {Object} config Editor config passed to the constructur, merged with the response of the request to modelUrl
  10996. */
  10997. ORYX.Editor.createByUrl = function(modelUrl, config){
  10998. if(!config) config = {};
  10999. new Ajax.Request(modelUrl, {
  11000. method: 'GET',
  11001. onSuccess: function(transport) {
  11002. var editorConfig = Ext.decode(transport.responseText);
  11003. editorConfig = Ext.applyIf(editorConfig, config);
  11004. new ORYX.Editor(editorConfig);
  11005. }.bind(this)
  11006. });
  11007. }
  11008. // TODO Implement namespace awareness on attribute level.
  11009. /**
  11010. * graft() function
  11011. * Originally by Sean M. Burke from interglacial.com, altered for usage with
  11012. * SVG and namespace (xmlns) support. Be sure you understand xmlns before
  11013. * using this funtion, as it creates all grafted elements in the xmlns
  11014. * provided by you and all element's attribures in default xmlns. If you
  11015. * need to graft elements in a certain xmlns and wish to assign attributes
  11016. * in both that and another xmlns, you will need to do stepwise grafting,
  11017. * adding non-default attributes yourself or you'll have to enhance this
  11018. * function. Latter, I would appreciate: martin�apfelfabrik.de
  11019. * @param {Object} namespace The namespace in which
  11020. * elements should be grafted.
  11021. * @param {Object} parent The element that should contain the grafted
  11022. * structure after the function returned.
  11023. * @param {Object} t the crafting structure.
  11024. * @param {Object} doc the document in which grafting is performed.
  11025. */
  11026. ORYX.Editor.graft = function(namespace, parent, t, doc) {
  11027. doc = (doc || (parent && parent.ownerDocument) || document);
  11028. var e;
  11029. if(t === undefined) {
  11030. throw "Can't graft an undefined value";
  11031. } else if(t.constructor == String) {
  11032. e = doc.createTextNode( t );
  11033. } else {
  11034. for(var i = 0; i < t.length; i++) {
  11035. if( i === 0 && t[i].constructor == String ) {
  11036. var snared;
  11037. snared = t[i].match( /^([a-z][a-z0-9]*)\.([^\s\.]+)$/i );
  11038. if( snared ) {
  11039. e = doc.createElementNS(namespace, snared[1] );
  11040. e.setAttributeNS(null, 'class', snared[2] );
  11041. continue;
  11042. }
  11043. snared = t[i].match( /^([a-z][a-z0-9]*)$/i );
  11044. if( snared ) {
  11045. e = doc.createElementNS(namespace, snared[1] ); // but no class
  11046. continue;
  11047. }
  11048. // Otherwise:
  11049. e = doc.createElementNS(namespace, "span" );
  11050. e.setAttribute(null, "class", "namelessFromLOL" );
  11051. }
  11052. if( t[i] === undefined ) {
  11053. throw "Can't graft an undefined value in a list!";
  11054. } else if( t[i].constructor == String || t[i].constructor == Array ) {
  11055. this.graft(namespace, e, t[i], doc );
  11056. } else if( t[i].constructor == Number ) {
  11057. this.graft(namespace, e, t[i].toString(), doc );
  11058. } else if( t[i].constructor == Object ) {
  11059. // hash's properties => element's attributes
  11060. for(var k in t[i]) { e.setAttributeNS(null, k, t[i][k] ); }
  11061. } else {
  11062. }
  11063. }
  11064. }
  11065. if(parent) {
  11066. parent.appendChild( e );
  11067. } else {
  11068. }
  11069. return e; // return the topmost created node
  11070. };
  11071. ORYX.Editor.provideId = function() {
  11072. var res = [], hex = '0123456789ABCDEF';
  11073. for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random()*0x10);
  11074. res[14] = 4;
  11075. res[19] = (res[19] & 0x3) | 0x8;
  11076. for (var i = 0; i < 36; i++) res[i] = hex[res[i]];
  11077. res[8] = res[13] = res[18] = res[23] = '-';
  11078. return "oryx_" + res.join('');
  11079. };
  11080. /**
  11081. * When working with Ext, conditionally the window needs to be resized. To do
  11082. * so, use this class method. Resize is deferred until 100ms, and all subsequent
  11083. * resizeBugFix calls are ignored until the initially requested resize is
  11084. * performed.
  11085. */
  11086. ORYX.Editor.resizeFix = function() {
  11087. if (!ORYX.Editor._resizeFixTimeout) {
  11088. ORYX.Editor._resizeFixTimeout = window.setTimeout(function() {
  11089. window.resizeBy(1,1);
  11090. window.resizeBy(-1,-1);
  11091. ORYX.Editor._resizefixTimeout = null;
  11092. }, 100);
  11093. }
  11094. };
  11095. ORYX.Editor.Cookie = {
  11096. callbacks:[],
  11097. onChange: function( callback, interval ){
  11098. this.callbacks.push(callback);
  11099. this.start( interval )
  11100. },
  11101. start: function( interval ){
  11102. if( this.pe ){
  11103. return;
  11104. }
  11105. var currentString = document.cookie;
  11106. this.pe = new PeriodicalExecuter( function(){
  11107. if( currentString != document.cookie ){
  11108. currentString = document.cookie;
  11109. this.callbacks.each(function(callback){ callback(this.getParams()) }.bind(this));
  11110. }
  11111. }.bind(this), ( interval || 10000 ) / 1000);
  11112. },
  11113. stop: function(){
  11114. if( this.pe ){
  11115. this.pe.stop();
  11116. this.pe = null;
  11117. }
  11118. },
  11119. getParams: function(){
  11120. var res = {};
  11121. var p = document.cookie;
  11122. p.split("; ").each(function(param){ res[param.split("=")[0]] = param.split("=")[1];});
  11123. return res;
  11124. },
  11125. toString: function(){
  11126. return document.cookie;
  11127. }
  11128. };
  11129. /**
  11130. * Workaround for SAFARI/Webkit, because
  11131. * when trying to check SVGSVGElement of instanceof there is
  11132. * raising an error
  11133. *
  11134. */
  11135. ORYX.Editor.SVGClassElementsAreAvailable = true;
  11136. ORYX.Editor.setMissingClasses = function() {
  11137. try {
  11138. SVGElement;
  11139. } catch(e) {
  11140. ORYX.Editor.SVGClassElementsAreAvailable = false;
  11141. SVGSVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg').toString();
  11142. SVGGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g').toString();
  11143. SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path').toString();
  11144. SVGTextElement = document.createElementNS('http://www.w3.org/2000/svg', 'text').toString();
  11145. //SVGMarkerElement = document.createElementNS('http://www.w3.org/2000/svg', 'marker').toString();
  11146. SVGRectElement = document.createElementNS('http://www.w3.org/2000/svg', 'rect').toString();
  11147. SVGImageElement = document.createElementNS('http://www.w3.org/2000/svg', 'image').toString();
  11148. SVGCircleElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle').toString();
  11149. SVGEllipseElement = document.createElementNS('http://www.w3.org/2000/svg', 'ellipse').toString();
  11150. SVGLineElement = document.createElementNS('http://www.w3.org/2000/svg', 'line').toString();
  11151. SVGPolylineElement = document.createElementNS('http://www.w3.org/2000/svg', 'polyline').toString();
  11152. SVGPolygonElement = document.createElementNS('http://www.w3.org/2000/svg', 'polygon').toString();
  11153. }
  11154. }
  11155. ORYX.Editor.checkClassType = function( classInst, classType ) {
  11156. if( ORYX.Editor.SVGClassElementsAreAvailable ){
  11157. return classInst instanceof classType
  11158. } else {
  11159. return classInst == classType
  11160. }
  11161. };
  11162. ORYX.Editor.makeExtModalWindowKeysave = function(facade) {
  11163. Ext.override(Ext.Window,{
  11164. beforeShow : function(){
  11165. delete this.el.lastXY;
  11166. delete this.el.lastLT;
  11167. if(this.x === undefined || this.y === undefined){
  11168. var xy = this.el.getAlignToXY(this.container, 'c-c');
  11169. var pos = this.el.translatePoints(xy[0], xy[1]);
  11170. this.x = this.x === undefined? pos.left : this.x;
  11171. this.y = this.y === undefined? pos.top : this.y;
  11172. }
  11173. this.el.setLeftTop(this.x, this.y);
  11174. if(this.expandOnShow){
  11175. this.expand(false);
  11176. }
  11177. if(this.modal){
  11178. facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  11179. Ext.getBody().addClass("x-body-masked");
  11180. this.mask.setSize(Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true));
  11181. this.mask.show();
  11182. }
  11183. },
  11184. afterHide : function(){
  11185. this.proxy.hide();
  11186. if(this.monitorResize || this.modal || this.constrain || this.constrainHeader){
  11187. Ext.EventManager.removeResizeListener(this.onWindowResize, this);
  11188. }
  11189. if(this.modal){
  11190. this.mask.hide();
  11191. facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  11192. Ext.getBody().removeClass("x-body-masked");
  11193. }
  11194. if(this.keyMap){
  11195. this.keyMap.disable();
  11196. }
  11197. this.fireEvent("hide", this);
  11198. },
  11199. beforeDestroy : function(){
  11200. if(this.modal)
  11201. facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  11202. Ext.destroy(
  11203. this.resizer,
  11204. this.dd,
  11205. this.proxy,
  11206. this.mask
  11207. );
  11208. Ext.Window.superclass.beforeDestroy.call(this);
  11209. }
  11210. });
  11211. }
  11212. /**
  11213. * Copyright (c) 2006
  11214. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  11215. *
  11216. * Permission is hereby granted, free of charge, to any person obtaining a
  11217. * copy of this software and associated documentation files (the "Software"),
  11218. * to deal in the Software without restriction, including without limitation
  11219. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11220. * and/or sell copies of the Software, and to permit persons to whom the
  11221. * Software is furnished to do so, subject to the following conditions:
  11222. *
  11223. * The above copyright notice and this permission notice shall be included in
  11224. * all copies or substantial portions of the Software.
  11225. *
  11226. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11227. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  11228. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  11229. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  11230. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  11231. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  11232. * DEALINGS IN THE SOFTWARE.
  11233. **/
  11234. /**
  11235. * Init namespaces
  11236. */
  11237. if(!ORYX) {var ORYX = {};}
  11238. if(!ORYX.Core) {ORYX.Core = {};}
  11239. new function(){
  11240. ORYX.Core.UIEnableDrag = function(event, uiObj, option) {
  11241. this.uiObj = uiObj;
  11242. var upL = uiObj.bounds.upperLeft();
  11243. var a = uiObj.node.getScreenCTM();
  11244. this.faktorXY= {x: a.a, y: a.d};
  11245. this.scrollNode = uiObj.node.ownerSVGElement.parentNode.parentNode;
  11246. this.offSetPosition = {
  11247. x: Event.pointerX(event) - (upL.x * this.faktorXY.x),
  11248. y: Event.pointerY(event) - (upL.y * this.faktorXY.y)};
  11249. this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop};
  11250. this.dragCallback = ORYX.Core.UIDragCallback.bind(this);
  11251. this.disableCallback = ORYX.Core.UIDisableDrag.bind(this);
  11252. this.movedCallback = option ? option.movedCallback : undefined;
  11253. this.upCallback = option ? option.upCallback : undefined;
  11254. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true);
  11255. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback , false);
  11256. };
  11257. ORYX.Core.UIDragCallback = function(event) {
  11258. var position = {
  11259. x: Event.pointerX(event) - this.offSetPosition.x,
  11260. y: Event.pointerY(event) - this.offSetPosition.y}
  11261. position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
  11262. position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;
  11263. position.x /= this.faktorXY.x;
  11264. position.y /= this.faktorXY.y;
  11265. this.uiObj.bounds.moveTo(position);
  11266. //this.uiObj.update();
  11267. if(this.movedCallback)
  11268. this.movedCallback(event);
  11269. Event.stop(event);
  11270. };
  11271. ORYX.Core.UIDisableDrag = function(event) {
  11272. document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.dragCallback, false);
  11273. document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.disableCallback, true);
  11274. if(this.upCallback)
  11275. this.upCallback(event);
  11276. this.upCallback = undefined;
  11277. this.movedCallback = undefined;
  11278. Event.stop(event);
  11279. };
  11280. /**
  11281. * Implements a command to move docker by an offset.
  11282. *
  11283. * @class ORYX.Core.MoveDockersCommand
  11284. * @param {Object} object An object with the docker id as key and docker and offset as object value
  11285. *
  11286. */
  11287. ORYX.Core.MoveDockersCommand = ORYX.Core.Command.extend({
  11288. construct: function(dockers){
  11289. this.dockers = $H(dockers);
  11290. this.edges = $H({});
  11291. },
  11292. execute: function(){
  11293. if (this.changes) {
  11294. this.executeAgain();
  11295. return;
  11296. } else {
  11297. this.changes = $H({});
  11298. }
  11299. this.dockers.values().each(function(docker){
  11300. var edge = docker.docker.parent;
  11301. if (!edge){ return }
  11302. if (!this.changes[edge.getId()]) {
  11303. this.changes[edge.getId()] = {
  11304. edge : edge,
  11305. oldDockerPositions : edge.dockers.map(function(r){ return r.bounds.center() })
  11306. }
  11307. }
  11308. docker.docker.bounds.moveBy(docker.offset);
  11309. this.edges[edge.getId()] = edge;
  11310. docker.docker.update();
  11311. }.bind(this));
  11312. this.edges.each(function(edge){
  11313. this.updateEdge(edge.value);
  11314. if (this.changes[edge.value.getId()])
  11315. this.changes[edge.value.getId()].dockerPositions = edge.value.dockers.map(function(r){ return r.bounds.center() })
  11316. }.bind(this));
  11317. },
  11318. updateEdge: function(edge){
  11319. edge._update(true);
  11320. [edge.getOutgoingShapes(), edge.getIncomingShapes()].flatten().invoke("_update", [true])
  11321. },
  11322. executeAgain: function(){
  11323. this.changes.values().each(function(change){
  11324. // Reset the dockers
  11325. this.removeAllDocker(change.edge);
  11326. change.dockerPositions.each(function(pos, i){
  11327. if (i==0||i==change.dockerPositions.length-1){ return }
  11328. var docker = change.edge.createDocker(undefined, pos);
  11329. docker.bounds.centerMoveTo(pos);
  11330. docker.update();
  11331. }.bind(this));
  11332. this.updateEdge(change.edge);
  11333. }.bind(this));
  11334. },
  11335. rollback: function(){
  11336. this.changes.values().each(function(change){
  11337. // Reset the dockers
  11338. this.removeAllDocker(change.edge);
  11339. change.oldDockerPositions.each(function(pos, i){
  11340. if (i==0||i==change.oldDockerPositions.length-1){ return }
  11341. var docker = change.edge.createDocker(undefined, pos);
  11342. docker.bounds.centerMoveTo(pos);
  11343. docker.update();
  11344. }.bind(this));
  11345. this.updateEdge(change.edge);
  11346. }.bind(this));
  11347. },
  11348. removeAllDocker: function(edge){
  11349. edge.dockers.slice(1, edge.dockers.length-1).each(function(docker){
  11350. edge.removeDocker(docker);
  11351. })
  11352. }
  11353. });
  11354. }();
  11355. /**
  11356. * Copyright (c) 2006
  11357. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  11358. *
  11359. * Permission is hereby granted, free of charge, to any person obtaining a
  11360. * copy of this software and associated documentation files (the "Software"),
  11361. * to deal in the Software without restriction, including without limitation
  11362. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11363. * and/or sell copies of the Software, and to permit persons to whom the
  11364. * Software is furnished to do so, subject to the following conditions:
  11365. *
  11366. * The above copyright notice and this permission notice shall be included in
  11367. * all copies or substantial portions of the Software.
  11368. *
  11369. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  11370. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  11371. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  11372. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  11373. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  11374. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  11375. * DEALINGS IN THE SOFTWARE.
  11376. **/
  11377. /**
  11378. * Init namespaces
  11379. */
  11380. if(!ORYX) {var ORYX = {};}
  11381. if(!ORYX.Core) {ORYX.Core = {};}
  11382. /**
  11383. * @classDescription Base class for Shapes.
  11384. * @extends ORYX.Core.AbstractShape
  11385. */
  11386. ORYX.Core.Shape = {
  11387. /**
  11388. * Constructor
  11389. */
  11390. construct: function(options, stencil) {
  11391. // call base class constructor
  11392. arguments.callee.$.construct.apply(this, arguments);
  11393. this.dockers = [];
  11394. this.magnets = [];
  11395. this._defaultMagnet;
  11396. this.incoming = [];
  11397. this.outgoing = [];
  11398. this.nodes = [];
  11399. this._dockerChangedCallback = this._dockerChanged.bind(this);
  11400. //Hash map for all labels. Labels are not treated as children of shapes.
  11401. this._labels = new Hash();
  11402. // create SVG node
  11403. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
  11404. null,
  11405. ['g', {id:"svg-" + this.resourceId},
  11406. ['g', {"class": "stencils"},
  11407. ['g', {"class": "me"}],
  11408. ['g', {"class": "children", style:"overflow:hidden"}],
  11409. ['g', {"class": "edge"}]
  11410. ],
  11411. ['g', {"class": "controls"},
  11412. ['g', {"class": "dockers"}],
  11413. ['g', {"class": "magnets"}]
  11414. ]
  11415. ]);
  11416. },
  11417. /**
  11418. * If changed flag is set, refresh method is called.
  11419. */
  11420. update: function() {
  11421. //if(this.isChanged) {
  11422. //this.layout();
  11423. //}
  11424. },
  11425. /**
  11426. * !!!Not called from any sub class!!!
  11427. */
  11428. _update: function() {
  11429. },
  11430. /**
  11431. * Calls the super class refresh method
  11432. * and updates the svg elements that are referenced by a property.
  11433. */
  11434. refresh: function() {
  11435. //call base class refresh method
  11436. arguments.callee.$.refresh.apply(this, arguments);
  11437. if(this.node.ownerDocument) {
  11438. //adjust SVG to properties' values
  11439. var me = this;
  11440. this.propertiesChanged.each((function(propChanged) {
  11441. if(propChanged.value) {
  11442. var prop = this.properties[propChanged.key];
  11443. var property = this.getStencil().property(propChanged.key);
  11444. if (property != undefined) {
  11445. this.propertiesChanged[propChanged.key] = false;
  11446. //handle choice properties
  11447. if(property.type() == ORYX.CONFIG.TYPE_CHOICE) {
  11448. //iterate all references to SVG elements
  11449. property.refToView().each((function(ref) {
  11450. //if property is referencing a label, update the label
  11451. if(ref !== "") {
  11452. var label = this._labels[this.id + ref];
  11453. if (label && property.item(prop)) {
  11454. label.text(property.item(prop).title());
  11455. }
  11456. }
  11457. }).bind(this));
  11458. //if the choice's items are referencing SVG elements
  11459. // show the selected and hide all other referenced SVG
  11460. // elements
  11461. var refreshedSvgElements = new Hash();
  11462. property.items().each((function(item) {
  11463. item.refToView().each((function(itemRef) {
  11464. if(itemRef == "") { return; }
  11465. var svgElem = this.node.ownerDocument.getElementById(this.id + itemRef);
  11466. if(!svgElem) { return; }
  11467. /* Do not refresh the same svg element multiple times */
  11468. if(!refreshedSvgElements[svgElem.id] || prop == item.value()) {
  11469. svgElem.setAttributeNS(null, 'display', ((prop == item.value()) ? 'inherit' : 'none'));
  11470. refreshedSvgElements[svgElem.id] = svgElem;
  11471. }
  11472. // Reload the href if there is an image-tag
  11473. if(ORYX.Editor.checkClassType(svgElem, SVGImageElement)) {
  11474. svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'href', svgElem.getAttributeNS('http://www.w3.org/1999/xlink', 'href'));
  11475. }
  11476. }).bind(this));
  11477. }).bind(this));
  11478. } else { //handle properties that are not of type choice
  11479. //iterate all references to SVG elements
  11480. property.refToView().each((function(ref) {
  11481. //if the property does not reference an SVG element,
  11482. // do nothing
  11483. if(ref === "") { return; }
  11484. var refId = this.id + ref;
  11485. //get the SVG element
  11486. var svgElem = this.node.ownerDocument.getElementById(refId);
  11487. //if the SVG element can not be found
  11488. if(!svgElem || !(svgElem.ownerSVGElement)) {
  11489. //if the referenced SVG element is a SVGAElement, it cannot
  11490. // be found with getElementById (Firefox bug).
  11491. // this is a work around
  11492. if(property.type() === ORYX.CONFIG.TYPE_URL || property.type() === ORYX.CONFIG.TYPE_DIAGRAM_LINK) {
  11493. var svgElems = this.node.ownerDocument.getElementsByTagNameNS('http://www.w3.org/2000/svg', 'a');
  11494. svgElem = $A(svgElems).find(function(elem) {
  11495. return elem.getAttributeNS(null, 'id') === refId;
  11496. });
  11497. if(!svgElem) { return; }
  11498. } else {
  11499. //this.propertiesChanged[propChanged.key] = true;
  11500. return;
  11501. }
  11502. }
  11503. if (property.complexAttributeToView()) {
  11504. var label = this._labels[refId];
  11505. if (label) {
  11506. try {
  11507. propJson = prop.evalJSON();
  11508. var value = propJson[property.complexAttributeToView()]
  11509. label.text(value ? value : prop);
  11510. } catch (e) {
  11511. label.text(prop);
  11512. }
  11513. }
  11514. } else {
  11515. switch (property.type()) {
  11516. case ORYX.CONFIG.TYPE_BOOLEAN:
  11517. if (typeof prop == "string")
  11518. prop = prop === "true"
  11519. svgElem.setAttributeNS(null, 'display', (!(prop === property.inverseBoolean())) ? 'inherit' : 'none');
  11520. break;
  11521. case ORYX.CONFIG.TYPE_COLOR:
  11522. if(property.fill()) {
  11523. if (svgElem.tagName.toLowerCase() === "stop"){
  11524. if (prop){
  11525. if (property.lightness() && property.lightness() !== 1){
  11526. prop = ORYX.Utils.adjustLightness(prop, property.lightness());
  11527. }
  11528. svgElem.setAttributeNS(null, "stop-color", prop);
  11529. // Adjust stop color of the others
  11530. if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient"){
  11531. ORYX.Utils.adjustGradient(svgElem.parentNode, svgElem);
  11532. }
  11533. }
  11534. // If there is no value, set opaque
  11535. if (svgElem.parentNode.tagName.toLowerCase() === "radialgradient"){
  11536. $A(svgElem.parentNode.getElementsByTagName('stop')).each(function(stop){
  11537. stop.setAttributeNS(null, "stop-opacity", prop ? stop.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, 'default-stop-opacity') || 1 : 0);
  11538. }.bind(this))
  11539. }
  11540. } else {
  11541. svgElem.setAttributeNS(null, 'fill', prop);
  11542. }
  11543. }
  11544. if(property.stroke()) {
  11545. svgElem.setAttributeNS(null, 'stroke', prop);
  11546. }
  11547. break;
  11548. case ORYX.CONFIG.TYPE_STRING:
  11549. var label = this._labels[refId];
  11550. if (label) {
  11551. label.text(prop);
  11552. }
  11553. break;
  11554. case ORYX.CONFIG.TYPE_INTEGER:
  11555. var label = this._labels[refId];
  11556. if (label) {
  11557. label.text(prop);
  11558. }
  11559. break;
  11560. case ORYX.CONFIG.TYPE_FLOAT:
  11561. if(property.fillOpacity()) {
  11562. svgElem.setAttributeNS(null, 'fill-opacity', prop);
  11563. }
  11564. if(property.strokeOpacity()) {
  11565. svgElem.setAttributeNS(null, 'stroke-opacity', prop);
  11566. }
  11567. if(!property.fillOpacity() && !property.strokeOpacity()) {
  11568. var label = this._labels[refId];
  11569. if (label) {
  11570. label.text(prop);
  11571. }
  11572. }
  11573. break;
  11574. case ORYX.CONFIG.TYPE_URL:
  11575. case ORYX.CONFIG.TYPE_DIAGRAM_LINK:
  11576. //TODO what is the dafault path?
  11577. var hrefAttr = svgElem.getAttributeNodeNS('http://www.w3.org/1999/xlink', 'xlink:href');
  11578. if(hrefAttr) {
  11579. hrefAttr.textContent = prop;
  11580. } else {
  11581. svgElem.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', prop);
  11582. }
  11583. break;
  11584. }
  11585. }
  11586. }).bind(this));
  11587. }
  11588. }
  11589. }
  11590. }).bind(this));
  11591. //update labels
  11592. this._labels.values().each(function(label) {
  11593. label.update();
  11594. });
  11595. }
  11596. },
  11597. layout: function() {
  11598. //this.getStencil().layout(this)
  11599. var layoutEvents = this.getStencil().layout()
  11600. if (layoutEvents) {
  11601. layoutEvents.each(function(event) {
  11602. // setup additional attributes
  11603. event.shape = this;
  11604. event.forceExecution = true;
  11605. // do layouting
  11606. this._delegateEvent(event);
  11607. }.bind(this))
  11608. }
  11609. },
  11610. /**
  11611. * Returns an array of Label objects.
  11612. */
  11613. getLabels: function() {
  11614. return this._labels.values();
  11615. },
  11616. /**
  11617. * Returns the label for a given ref
  11618. * @return {ORYX.Core.Label} Returns null if there is no label
  11619. */
  11620. getLabel: function(ref){
  11621. if (!ref){
  11622. return null;
  11623. }
  11624. return (this._labels.find(function(o){
  11625. return o.key.endsWith(ref);
  11626. })||{}).value || null;
  11627. },
  11628. /**
  11629. * Hides all related labels
  11630. *
  11631. */
  11632. hideLabels: function(){
  11633. this.getLabels().invoke("hide");
  11634. },
  11635. /**
  11636. * Shows all related labels
  11637. *
  11638. */
  11639. showLabels: function(){
  11640. var labels = this.getLabels();
  11641. labels.invoke("show");
  11642. labels.each(function(label) {
  11643. label.update();
  11644. });
  11645. },
  11646. setOpacity: function(value, animate){
  11647. // 0.0 <= value <= 1.0
  11648. value = Math.max(Math.min((typeof value == "number" ? value : 1.0), 1.0), 0.0);
  11649. //if (animate !== true){
  11650. if (value !== 1.0){
  11651. value = String(value);
  11652. this.node.setAttributeNS(null, "fill-opacity", value)
  11653. this.node.setAttributeNS(null, "stroke-opacity", value)
  11654. } else {
  11655. this.node.removeAttributeNS(null, "fill-opacity");
  11656. this.node.removeAttributeNS(null, "stroke-opacity");
  11657. }
  11658. /*} else {
  11659. var args = {opacity:{to:value}};
  11660. if (!this.isVisible){
  11661. this.show();
  11662. }
  11663. if (this.currentAnim){
  11664. this.currentAnim.stop();
  11665. }
  11666. this.currentAnim = Ext.lib.Anim.run(this.node, args, 0.4, "easeOut", function(){
  11667. if (args.opacity.to === 0.0){
  11668. this.hide();
  11669. } else if (args.opacity.to === 1.0){
  11670. this.node.removeAttributeNS(null, "style");
  11671. }
  11672. delete this.currentAnim;
  11673. }, this)
  11674. }*/
  11675. },
  11676. /**
  11677. * Returns an array of dockers of this object.
  11678. */
  11679. getDockers: function() {
  11680. return this.dockers;
  11681. },
  11682. getMagnets: function() {
  11683. return this.magnets;
  11684. },
  11685. getDefaultMagnet: function() {
  11686. if(this._defaultMagnet) {
  11687. return this._defaultMagnet;
  11688. } else if (this.magnets.length > 0) {
  11689. return this.magnets[0];
  11690. } else {
  11691. return undefined;
  11692. }
  11693. },
  11694. getParentShape: function() {
  11695. return this.parent;
  11696. },
  11697. getIncomingShapes: function(iterator) {
  11698. if(iterator) {
  11699. this.incoming.each(iterator);
  11700. }
  11701. return this.incoming;
  11702. },
  11703. getIncomingNodes: function(iterator) {
  11704. return this.incoming.select(function(incoming){
  11705. var isNode = (incoming instanceof ORYX.Core.Node);
  11706. if(isNode && iterator) iterator(incoming);
  11707. return isNode;
  11708. });
  11709. },
  11710. getOutgoingShapes: function(iterator) {
  11711. if(iterator) {
  11712. this.outgoing.each(iterator);
  11713. }
  11714. return this.outgoing;
  11715. },
  11716. getOutgoingNodes: function(iterator) {
  11717. return this.outgoing.select(function(out){
  11718. var isNode = (out instanceof ORYX.Core.Node);
  11719. if(isNode && iterator) iterator(out);
  11720. return isNode;
  11721. });
  11722. },
  11723. getAllDockedShapes: function(iterator) {
  11724. var result = this.incoming.concat(this.outgoing);
  11725. if(iterator) {
  11726. result.each(iterator);
  11727. }
  11728. return result
  11729. },
  11730. getCanvas: function() {
  11731. if(this.parent instanceof ORYX.Core.Canvas) {
  11732. return this.parent;
  11733. } else if(this.parent instanceof ORYX.Core.Shape) {
  11734. return this.parent.getCanvas();
  11735. } else {
  11736. return undefined;
  11737. }
  11738. },
  11739. /**
  11740. *
  11741. * @param {Object} deep
  11742. * @param {Object} iterator
  11743. */
  11744. getChildNodes: function(deep, iterator) {
  11745. if(!deep && !iterator) {
  11746. return this.nodes.clone();
  11747. } else {
  11748. var result = [];
  11749. this.nodes.each(function(uiObject) {
  11750. if(!uiObject.isVisible){return}
  11751. if(iterator) {
  11752. iterator(uiObject);
  11753. }
  11754. result.push(uiObject);
  11755. if(deep && uiObject instanceof ORYX.Core.Shape) {
  11756. result = result.concat(uiObject.getChildNodes(deep, iterator));
  11757. }
  11758. });
  11759. return result;
  11760. }
  11761. },
  11762. /**
  11763. * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
  11764. * @param {UIObject} uiObject
  11765. * @param {Number} index
  11766. */
  11767. add: function(uiObject, index, silent) {
  11768. //parameter has to be an UIObject, but
  11769. // must not be an Edge.
  11770. if(uiObject instanceof ORYX.Core.UIObject
  11771. && !(uiObject instanceof ORYX.Core.Edge)) {
  11772. if (!(this.children.member(uiObject))) {
  11773. //if uiObject is child of another parent, remove it from that parent.
  11774. if(uiObject.parent) {
  11775. uiObject.parent.remove(uiObject, true);
  11776. }
  11777. //add uiObject to this Shape
  11778. if(index != undefined)
  11779. this.children.splice(index, 0, uiObject);
  11780. else
  11781. this.children.push(uiObject);
  11782. //set parent reference
  11783. uiObject.parent = this;
  11784. //add uiObject.node to this.node depending on the type of uiObject
  11785. var parent;
  11786. if(uiObject instanceof ORYX.Core.Node) {
  11787. parent = this.node.childNodes[0].childNodes[1];
  11788. this.nodes.push(uiObject);
  11789. } else if(uiObject instanceof ORYX.Core.Controls.Control) {
  11790. var ctrls = this.node.childNodes[1];
  11791. if(uiObject instanceof ORYX.Core.Controls.Docker) {
  11792. parent = ctrls.childNodes[0];
  11793. if (this.dockers.length >= 2){
  11794. this.dockers.splice(index!==undefined?Math.min(index, this.dockers.length-1):this.dockers.length-1, 0, uiObject);
  11795. } else {
  11796. this.dockers.push(uiObject);
  11797. }
  11798. } else if(uiObject instanceof ORYX.Core.Controls.Magnet) {
  11799. parent = ctrls.childNodes[1];
  11800. this.magnets.push(uiObject);
  11801. } else {
  11802. parent = ctrls;
  11803. }
  11804. } else { //UIObject
  11805. parent = this.node;
  11806. }
  11807. if(index != undefined && index < parent.childNodes.length)
  11808. uiObject.node = parent.insertBefore(uiObject.node, parent.childNodes[index]);
  11809. else
  11810. uiObject.node = parent.appendChild(uiObject.node);
  11811. this._changed();
  11812. //uiObject.bounds.registerCallback(this._changedCallback);
  11813. if(this.eventHandlerCallback && silent !== true)
  11814. this.eventHandlerCallback({type:ORYX.CONFIG.EVENT_SHAPEADDED,shape:uiObject})
  11815. } else {
  11816. ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object.");
  11817. }
  11818. } else {
  11819. ORYX.Log.warn("add: Parameter is not of type ORYX.Core.UIObject.");
  11820. }
  11821. },
  11822. /**
  11823. * Overrides the UIObject.remove method. Removes uiObject.
  11824. * @param {UIObject} uiObject
  11825. */
  11826. remove: function(uiObject, silent) {
  11827. //if uiObject is a child of this object, remove it.
  11828. if (this.children.member(uiObject)) {
  11829. //remove uiObject from children
  11830. var parent = uiObject.parent;
  11831. this.children = this.children.without(uiObject);
  11832. //delete parent reference of uiObject
  11833. uiObject.parent = undefined;
  11834. //delete uiObject.node from this.node
  11835. if(uiObject instanceof ORYX.Core.Shape) {
  11836. if(uiObject instanceof ORYX.Core.Edge) {
  11837. uiObject.removeMarkers();
  11838. uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node);
  11839. } else {
  11840. uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node);
  11841. this.nodes = this.nodes.without(uiObject);
  11842. }
  11843. } else if(uiObject instanceof ORYX.Core.Controls.Control) {
  11844. if (uiObject instanceof ORYX.Core.Controls.Docker) {
  11845. uiObject.node = this.node.childNodes[1].childNodes[0].removeChild(uiObject.node);
  11846. this.dockers = this.dockers.without(uiObject);
  11847. } else if (uiObject instanceof ORYX.Core.Controls.Magnet) {
  11848. uiObject.node = this.node.childNodes[1].childNodes[1].removeChild(uiObject.node);
  11849. this.magnets = this.magnets.without(uiObject);
  11850. } else {
  11851. uiObject.node = this.node.childNodes[1].removeChild(uiObject.node);
  11852. }
  11853. }
  11854. if(this.eventHandlerCallback && silent !== true)
  11855. this.eventHandlerCallback({type: ORYX.CONFIG.EVENT_SHAPEREMOVED, shape: uiObject, parent: parent});
  11856. this._changed();
  11857. //uiObject.bounds.unregisterCallback(this._changedCallback);
  11858. } else {
  11859. ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object.");
  11860. }
  11861. },
  11862. /**
  11863. * Calculate the Border Intersection Point between two points
  11864. * @param {PointA}
  11865. * @param {PointB}
  11866. */
  11867. getIntersectionPoint: function() {
  11868. var pointAX, pointAY, pointBX, pointBY;
  11869. // Get the the two Points
  11870. switch(arguments.length) {
  11871. case 2:
  11872. pointAX = arguments[0].x;
  11873. pointAY = arguments[0].y;
  11874. pointBX = arguments[1].x;
  11875. pointBY = arguments[1].y;
  11876. break;
  11877. case 4:
  11878. pointAX = arguments[0];
  11879. pointAY = arguments[1];
  11880. pointBX = arguments[2];
  11881. pointBY = arguments[3];
  11882. break;
  11883. default:
  11884. throw "getIntersectionPoints needs two or four arguments";
  11885. }
  11886. // Defined an include and exclude point
  11887. var includePointX, includePointY, excludePointX, excludePointY;
  11888. var bounds = this.absoluteBounds();
  11889. if(this.isPointIncluded(pointAX, pointAY, bounds)){
  11890. includePointX = pointAX;
  11891. includePointY = pointAY;
  11892. } else {
  11893. excludePointX = pointAX;
  11894. excludePointY = pointAY;
  11895. }
  11896. if(this.isPointIncluded(pointBX, pointBY, bounds)){
  11897. includePointX = pointBX;
  11898. includePointY = pointBY;
  11899. } else {
  11900. excludePointX = pointBX;
  11901. excludePointY = pointBY;
  11902. }
  11903. // If there is no inclue or exclude Shape, than return
  11904. if(!includePointX || !includePointY || !excludePointX || !excludePointY) {
  11905. return undefined;
  11906. }
  11907. var midPointX = 0;
  11908. var midPointY = 0;
  11909. var refPointX, refPointY;
  11910. var minDifferent = 1;
  11911. // Get the UpperLeft and LowerRight
  11912. //var ul = bounds.upperLeft();
  11913. //var lr = bounds.lowerRight();
  11914. var i = 0;
  11915. while(true) {
  11916. // Calculate the midpoint of the current to points
  11917. var midPointX = Math.min(includePointX, excludePointX) + ((Math.max(includePointX, excludePointX) - Math.min(includePointX, excludePointX)) / 2.0);
  11918. var midPointY = Math.min(includePointY, excludePointY) + ((Math.max(includePointY, excludePointY) - Math.min(includePointY, excludePointY)) / 2.0);
  11919. // Set the new midpoint by the means of the include of the bounds
  11920. if(this.isPointIncluded(midPointX, midPointY, bounds)){
  11921. includePointX = midPointX;
  11922. includePointY = midPointY;
  11923. } else {
  11924. excludePointX = midPointX;
  11925. excludePointY = midPointY;
  11926. }
  11927. // Calc the length of the line
  11928. var length = Math.sqrt(Math.pow(includePointX - excludePointX, 2) + Math.pow(includePointY - excludePointY, 2))
  11929. // Calc a point one step from the include point
  11930. refPointX = includePointX + ((excludePointX - includePointX) / length),
  11931. refPointY = includePointY + ((excludePointY - includePointY) / length)
  11932. // If the reference point not in the bounds, break
  11933. if(!this.isPointIncluded(refPointX, refPointY, bounds)) {
  11934. break
  11935. }
  11936. }
  11937. // Return the last includepoint
  11938. return {x:refPointX , y:refPointY};
  11939. },
  11940. /**
  11941. * Calculate if the point is inside the Shape
  11942. * @param {PointX}
  11943. * @param {PointY}
  11944. */
  11945. isPointIncluded: function(){
  11946. return false
  11947. },
  11948. /**
  11949. * Returns TRUE if the given node
  11950. * is a child node of the shapes node
  11951. * @param {Element} node
  11952. * @return {Boolean}
  11953. *
  11954. */
  11955. containsNode: function(node){
  11956. var me = this.node.firstChild.firstChild;
  11957. while(node){
  11958. if (node == me){
  11959. return true;
  11960. }
  11961. node = node.parentNode;
  11962. }
  11963. return false
  11964. },
  11965. /**
  11966. * Calculate if the point is over an special offset area
  11967. * @param {Point}
  11968. */
  11969. isPointOverOffset: function(){
  11970. return this.isPointIncluded.apply( this , arguments )
  11971. },
  11972. _dockerChanged: function() {
  11973. },
  11974. /**
  11975. * Create a Docker for this Edge
  11976. *
  11977. */
  11978. createDocker: function(index, position) {
  11979. var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback});
  11980. docker.bounds.registerCallback(this._dockerChangedCallback);
  11981. if(position) {
  11982. docker.bounds.centerMoveTo(position);
  11983. }
  11984. this.add(docker, index);
  11985. return docker
  11986. },
  11987. /**
  11988. * Get the serialized object
  11989. * return Array with hash-entrees (prefix, name, value)
  11990. * Following values will given:
  11991. * Bounds
  11992. * Outgoing Shapes
  11993. * Parent
  11994. */
  11995. serialize: function() {
  11996. var serializedObject = arguments.callee.$.serialize.apply(this);
  11997. // Add the bounds
  11998. serializedObject.push({name: 'bounds', prefix:'oryx', value: this.bounds.serializeForERDF(), type: 'literal'});
  11999. // Add the outgoing shapes
  12000. this.getOutgoingShapes().each((function(followingShape){
  12001. serializedObject.push({name: 'outgoing', prefix:'raziel', value: '#'+ERDF.__stripHashes(followingShape.resourceId), type: 'resource'});
  12002. }).bind(this));
  12003. // Add the parent shape, if the parent not the canvas
  12004. //if(this.parent instanceof ORYX.Core.Shape){
  12005. serializedObject.push({name: 'parent', prefix:'raziel', value: '#'+ERDF.__stripHashes(this.parent.resourceId), type: 'resource'});
  12006. //}
  12007. return serializedObject;
  12008. },
  12009. deserialize: function(serialize, json){
  12010. arguments.callee.$.deserialize.apply(this, arguments);
  12011. // Set the Bounds
  12012. var bounds = serialize.find(function(ser){ return 'oryx-bounds' === (ser.prefix+"-"+ser.name) });
  12013. if (bounds) {
  12014. var b = bounds.value.replace(/,/g, " ").split(" ").without("");
  12015. if (this instanceof ORYX.Core.Edge) {
  12016. if (!this.dockers.first().isChanged)
  12017. this.dockers.first().bounds.centerMoveTo(parseFloat(b[0]), parseFloat(b[1]));
  12018. if (!this.dockers.last().isChanged)
  12019. this.dockers.last().bounds.centerMoveTo(parseFloat(b[2]), parseFloat(b[3]));
  12020. } else {
  12021. this.bounds.set(parseFloat(b[0]), parseFloat(b[1]), parseFloat(b[2]), parseFloat(b[3]));
  12022. }
  12023. }
  12024. if (json && json.labels instanceof Array){
  12025. json.labels.each(function(slabel){
  12026. var label = this.getLabel(slabel.ref);
  12027. if (label){
  12028. label.deserialize(slabel, this);
  12029. }
  12030. }.bind(this))
  12031. }
  12032. },
  12033. toJSON: function(){
  12034. var json = arguments.callee.$.toJSON.apply(this, arguments);
  12035. var labels = [], id = this.id;
  12036. this._labels.each(function(obj){
  12037. var slabel = obj.value.serialize();
  12038. if (slabel){
  12039. slabel.ref = obj.key.replace(id, '');
  12040. labels.push(slabel);
  12041. }
  12042. });
  12043. if (labels.length > 0){
  12044. json.labels = labels;
  12045. }
  12046. return json;
  12047. },
  12048. /**
  12049. * Private methods.
  12050. */
  12051. /**
  12052. * Child classes have to overwrite this method for initializing a loaded
  12053. * SVG representation.
  12054. * @param {SVGDocument} svgDocument
  12055. */
  12056. _init: function(svgDocument) {
  12057. //adjust ids
  12058. this._adjustIds(svgDocument, 0);
  12059. },
  12060. _adjustIds: function(element, idIndex) {
  12061. if(element instanceof Element) {
  12062. var eid = element.getAttributeNS(null, 'id');
  12063. if(eid && eid !== "") {
  12064. element.setAttributeNS(null, 'id', this.id + eid);
  12065. } else {
  12066. element.setAttributeNS(null, 'id', this.id + "_" + this.id + "_" + idIndex);
  12067. idIndex++;
  12068. }
  12069. // Replace URL in fill attribute
  12070. var fill = element.getAttributeNS(null, 'fill');
  12071. if (fill&&fill.include("url(#")){
  12072. fill = fill.replace(/url\(#/g, 'url(#'+this.id);
  12073. element.setAttributeNS(null, 'fill', fill);
  12074. }
  12075. if(element.hasChildNodes()) {
  12076. for(var i = 0; i < element.childNodes.length; i++) {
  12077. idIndex = this._adjustIds(element.childNodes[i], idIndex);
  12078. }
  12079. }
  12080. }
  12081. return idIndex;
  12082. },
  12083. toString: function() { return "ORYX.Core.Shape " + this.getId() }
  12084. };
  12085. ORYX.Core.Shape = ORYX.Core.AbstractShape.extend(ORYX.Core.Shape);/**
  12086. * Copyright (c) 2006
  12087. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  12088. *
  12089. * Permission is hereby granted, free of charge, to any person obtaining a
  12090. * copy of this software and associated documentation files (the "Software"),
  12091. * to deal in the Software without restriction, including without limitation
  12092. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12093. * and/or sell copies of the Software, and to permit persons to whom the
  12094. * Software is furnished to do so, subject to the following conditions:
  12095. *
  12096. * The above copyright notice and this permission notice shall be included in
  12097. * all copies or substantial portions of the Software.
  12098. *
  12099. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12100. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12101. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  12102. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  12103. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  12104. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  12105. * DEALINGS IN THE SOFTWARE.
  12106. **/
  12107. /**
  12108. * Init namespaces
  12109. */
  12110. if(!ORYX) {var ORYX = {};}
  12111. if(!ORYX.Core) {ORYX.Core = {};}
  12112. if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};}
  12113. /**
  12114. * @classDescription Abstract base class for all Controls.
  12115. */
  12116. ORYX.Core.Controls.Control = ORYX.Core.UIObject.extend({
  12117. toString: function() { return "Control " + this.id; }
  12118. });/**
  12119. * Copyright (c) 2006
  12120. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  12121. *
  12122. * Permission is hereby granted, free of charge, to any person obtaining a
  12123. * copy of this software and associated documentation files (the "Software"),
  12124. * to deal in the Software without restriction, including without limitation
  12125. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12126. * and/or sell copies of the Software, and to permit persons to whom the
  12127. * Software is furnished to do so, subject to the following conditions:
  12128. *
  12129. * The above copyright notice and this permission notice shall be included in
  12130. * all copies or substantial portions of the Software.
  12131. *
  12132. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12133. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12134. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  12135. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  12136. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  12137. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  12138. * DEALINGS IN THE SOFTWARE.
  12139. **/
  12140. /**
  12141. * Init namespaces
  12142. */
  12143. if(!ORYX) {var ORYX = {};}
  12144. if(!ORYX.Core) {ORYX.Core = {};}
  12145. if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};}
  12146. /**
  12147. * @classDescription Represents a movable docker that can be bound to a shape. Dockers are used
  12148. * for positioning shape objects.
  12149. * @extends {Control}
  12150. *
  12151. * TODO absoluteXY und absoluteCenterXY von einem Docker liefern falsche Werte!!!
  12152. */
  12153. ORYX.Core.Controls.Docker = ORYX.Core.Controls.Control.extend({
  12154. /**
  12155. * Constructor
  12156. */
  12157. construct: function() {
  12158. arguments.callee.$.construct.apply(this, arguments);
  12159. this.isMovable = true; // Enables movability
  12160. this.bounds.set(0, 0, 16, 16); // Set the bounds
  12161. this.referencePoint = undefined; // Refrenzpoint
  12162. this._dockedShapeBounds = undefined;
  12163. this._dockedShape = undefined;
  12164. this._oldRefPoint1 = undefined;
  12165. this._oldRefPoint2 = undefined;
  12166. //this.anchors = [];
  12167. this.anchorLeft;
  12168. this.anchorRight;
  12169. this.anchorTop;
  12170. this.anchorBottom;
  12171. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
  12172. null,
  12173. ['g']);
  12174. // The DockerNode reprasentation
  12175. this._dockerNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
  12176. this.node,
  12177. ['g', {"pointer-events":"all"},
  12178. ['circle', {cx:"8", cy:"8", r:"8", stroke:"none", fill:"none"}],
  12179. ['circle', {cx:"8", cy:"8", r:"3", stroke:"black", fill:"red", "stroke-width":"1"}]
  12180. ]);
  12181. // The ReferenzNode reprasentation
  12182. this._referencePointNode = ORYX.Editor.graft("http://www.w3.org/2000/svg",
  12183. this.node,
  12184. ['g', {"pointer-events":"none"},
  12185. ['circle', {cx: this.bounds.upperLeft().x, cy: this.bounds.upperLeft().y, r: 3, fill:"red", "fill-opacity":0.4}]]);
  12186. // Hide the Docker
  12187. this.hide();
  12188. //Add to the EventHandler
  12189. this.addEventHandlers(this._dockerNode);
  12190. // Buffer the Update Callback for un-/register on Event-Handler
  12191. this._updateCallback = this._changed.bind(this);
  12192. },
  12193. update: function() {
  12194. // If there have an DockedShape
  12195. if(this._dockedShape) {
  12196. if(this._dockedShapeBounds && this._dockedShape instanceof ORYX.Core.Node) {
  12197. // Calc the delta of width and height of the lastBounds and the current Bounds
  12198. var dswidth = this._dockedShapeBounds.width();
  12199. var dsheight = this._dockedShapeBounds.height();
  12200. if(!dswidth)
  12201. dswidth = 1;
  12202. if(!dsheight)
  12203. dsheight = 1;
  12204. var widthDelta = this._dockedShape.bounds.width() / dswidth;
  12205. var heightDelta = this._dockedShape.bounds.height() / dsheight;
  12206. // If there is an different
  12207. if(widthDelta !== 1.0 || heightDelta !== 1.0) {
  12208. // Set the delta
  12209. this.referencePoint.x *= widthDelta;
  12210. this.referencePoint.y *= heightDelta;
  12211. }
  12212. // Clone these bounds
  12213. this._dockedShapeBounds = this._dockedShape.bounds.clone();
  12214. }
  12215. // Get the first and the last Docker of the parent Shape
  12216. var dockerIndex = this.parent.dockers.indexOf(this)
  12217. var dock1 = this;
  12218. var dock2 = this.parent.dockers.length > 1 ?
  12219. (dockerIndex === 0? // If there is the first element
  12220. this.parent.dockers[dockerIndex + 1]: // then take the next docker
  12221. this.parent.dockers[dockerIndex - 1]): // if not, then take the docker before
  12222. undefined;
  12223. // Calculate the first absolute Refenzpoint
  12224. var absoluteReferenzPoint1 = dock1.getDockedShape() ?
  12225. dock1.getAbsoluteReferencePoint() :
  12226. dock1.bounds.center();
  12227. // Calculate the last absolute Refenzpoint
  12228. var absoluteReferenzPoint2 = dock2 && dock2.getDockedShape() ?
  12229. dock2.getAbsoluteReferencePoint() :
  12230. dock2 ?
  12231. dock2.bounds.center() :
  12232. undefined;
  12233. // If there is no last absolute Referenzpoint
  12234. if(!absoluteReferenzPoint2) {
  12235. // Calculate from the middle of the DockedShape
  12236. var center = this._dockedShape.absoluteCenterXY();
  12237. var minDimension = this._dockedShape.bounds.width() * this._dockedShape.bounds.height();
  12238. absoluteReferenzPoint2 = {
  12239. x: absoluteReferenzPoint1.x + (center.x - absoluteReferenzPoint1.x) * -minDimension,
  12240. y: absoluteReferenzPoint1.y + (center.y - absoluteReferenzPoint1.y) * -minDimension
  12241. }
  12242. }
  12243. var newPoint = undefined;
  12244. /*if (!this._oldRefPoint1 || !this._oldRefPoint2 ||
  12245. absoluteReferenzPoint1.x !== this._oldRefPoint1.x ||
  12246. absoluteReferenzPoint1.y !== this._oldRefPoint1.y ||
  12247. absoluteReferenzPoint2.x !== this._oldRefPoint2.x ||
  12248. absoluteReferenzPoint2.y !== this._oldRefPoint2.y) {*/
  12249. // Get the new point for the Docker, calucalted by the intersection point of the Shape and the two points
  12250. newPoint = this._dockedShape.getIntersectionPoint(absoluteReferenzPoint1, absoluteReferenzPoint2);
  12251. // If there is new point, take the referencepoint as the new point
  12252. if(!newPoint) {
  12253. newPoint = this.getAbsoluteReferencePoint();
  12254. }
  12255. if(this.parent && this.parent.parent) {
  12256. var grandParentPos = this.parent.parent.absoluteXY();
  12257. newPoint.x -= grandParentPos.x;
  12258. newPoint.y -= grandParentPos.y;
  12259. }
  12260. // Set the bounds to the new point
  12261. this.bounds.centerMoveTo(newPoint)
  12262. this._oldRefPoint1 = absoluteReferenzPoint1;
  12263. this._oldRefPoint2 = absoluteReferenzPoint2;
  12264. }
  12265. /*else {
  12266. newPoint = this.bounds.center();
  12267. }*/
  12268. // }
  12269. // Call the super class
  12270. arguments.callee.$.update.apply(this, arguments);
  12271. },
  12272. /**
  12273. * Calls the super class refresh method and updates the view of the docker.
  12274. */
  12275. refresh: function() {
  12276. arguments.callee.$.refresh.apply(this, arguments);
  12277. // Refresh the dockers node
  12278. var p = this.bounds.upperLeft();
  12279. this._dockerNode.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')');
  12280. // Refresh the referencepoints node
  12281. p = Object.clone(this.referencePoint);
  12282. if(p && this._dockedShape){
  12283. var upL
  12284. if(this.parent instanceof ORYX.Core.Edge) {
  12285. upL = this._dockedShape.absoluteXY();
  12286. } else {
  12287. upL = this._dockedShape.bounds.upperLeft();
  12288. }
  12289. p.x += upL.x;
  12290. p.y += upL.y;
  12291. } else {
  12292. p = this.bounds.center();
  12293. }
  12294. this._referencePointNode.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')');
  12295. },
  12296. /**
  12297. * Set the reference point
  12298. * @param {Object} point
  12299. */
  12300. setReferencePoint: function(point) {
  12301. // Set the referencepoint
  12302. if(this.referencePoint !== point &&
  12303. (!this.referencePoint ||
  12304. !point ||
  12305. this.referencePoint.x !== point.x ||
  12306. this.referencePoint.y !== point.y)) {
  12307. this.referencePoint = point;
  12308. this._changed();
  12309. }
  12310. // Update directly, because the referencepoint has no influence of the bounds
  12311. //this.refresh();
  12312. },
  12313. /**
  12314. * Get the absolute referencepoint
  12315. */
  12316. getAbsoluteReferencePoint: function() {
  12317. if(!this.referencePoint || !this._dockedShape) {
  12318. return undefined;
  12319. } else {
  12320. var absUL = this._dockedShape.absoluteXY();
  12321. return {
  12322. x: this.referencePoint.x + absUL.x,
  12323. y: this.referencePoint.y + absUL.y
  12324. }
  12325. }
  12326. },
  12327. /**
  12328. * Set the docked Shape from the docker
  12329. * @param {Object} shape
  12330. */
  12331. setDockedShape: function(shape) {
  12332. // If there is an old docked Shape
  12333. if(this._dockedShape) {
  12334. this._dockedShape.bounds.unregisterCallback(this._updateCallback)
  12335. // Delete the Shapes from the incoming and outgoing array
  12336. // If this Docker the incoming of the Shape
  12337. if(this === this.parent.dockers.first()) {
  12338. this.parent.incoming = this.parent.incoming.without(this._dockedShape);
  12339. this._dockedShape.outgoing = this._dockedShape.outgoing.without(this.parent);
  12340. // If this Docker the outgoing of the Shape
  12341. } else if (this === this.parent.dockers.last()){
  12342. this.parent.outgoing = this.parent.outgoing.without(this._dockedShape);
  12343. this._dockedShape.incoming = this._dockedShape.incoming.without(this.parent);
  12344. }
  12345. }
  12346. // Set the new Shape
  12347. this._dockedShape = shape;
  12348. this._dockedShapeBounds = undefined;
  12349. var referencePoint = undefined;
  12350. // If there is an Shape, register the updateCallback if there are changes in the shape bounds
  12351. if(this._dockedShape) {
  12352. // Add the Shapes to the incoming and outgoing array
  12353. // If this Docker the incoming of the Shape
  12354. if(this === this.parent.dockers.first()) {
  12355. this.parent.incoming.push(shape);
  12356. shape.outgoing.push(this.parent);
  12357. // If this Docker the outgoing of the Shape
  12358. } else if (this === this.parent.dockers.last()){
  12359. this.parent.outgoing.push(shape);
  12360. shape.incoming.push(this.parent);
  12361. }
  12362. // Get the bounds and set the new referencepoint
  12363. var bounds = this.bounds;
  12364. var absUL = shape.absoluteXY();
  12365. /*if(shape.parent){
  12366. var b = shape.parent.bounds.upperLeft();
  12367. absUL.x -= b.x;
  12368. absUL.y -= b.y;
  12369. }*/
  12370. referencePoint = {
  12371. x: bounds.center().x - absUL.x,
  12372. y: bounds.center().y - absUL.y
  12373. }
  12374. this._dockedShapeBounds = this._dockedShape.bounds.clone();
  12375. this._dockedShape.bounds.registerCallback(this._updateCallback);
  12376. // Set the color of the docker as docked
  12377. this.setDockerColor(ORYX.CONFIG.DOCKER_DOCKED_COLOR);
  12378. } else {
  12379. // Set the color of the docker as undocked
  12380. this.setDockerColor(ORYX.CONFIG.DOCKER_UNDOCKED_COLOR);
  12381. }
  12382. // Set the referencepoint
  12383. this.setReferencePoint(referencePoint);
  12384. this._changed();
  12385. //this.update();
  12386. },
  12387. /**
  12388. * Get the docked Shape
  12389. */
  12390. getDockedShape: function() {
  12391. return this._dockedShape;
  12392. },
  12393. /**
  12394. * Returns TRUE if the docker has a docked shape
  12395. */
  12396. isDocked: function() {
  12397. return !!this._dockedShape;
  12398. },
  12399. /**
  12400. * Set the Color of the Docker
  12401. * @param {Object} color
  12402. */
  12403. setDockerColor: function(color) {
  12404. this._dockerNode.lastChild.setAttributeNS(null, "fill", color);
  12405. },
  12406. preventHiding: function(prevent){
  12407. this._preventHiding = Math.max(0, (this._preventHiding||0) + (prevent ? 1 : -1));
  12408. },
  12409. /**
  12410. * Hides this UIObject and all its children.
  12411. */
  12412. hide: function() {
  12413. if (this._preventHiding){
  12414. return false;
  12415. }
  12416. // Hide docker and reference point
  12417. this.node.setAttributeNS(null, 'visibility', 'hidden');
  12418. this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden');
  12419. this.children.each(function(uiObj) {
  12420. uiObj.hide();
  12421. });
  12422. },
  12423. /**
  12424. * Enables visibility of this UIObject and all its children.
  12425. */
  12426. show: function() {
  12427. // Show docker
  12428. this.node.setAttributeNS(null, 'visibility', 'visible');
  12429. // Hide reference point if the connected shape is an edge
  12430. if (this.getDockedShape() instanceof ORYX.Core.Edge){
  12431. this._referencePointNode.setAttributeNS(null, 'visibility', 'hidden');
  12432. } else {
  12433. this._referencePointNode.setAttributeNS(null, 'visibility', 'visible');
  12434. }
  12435. this.children.each(function(uiObj) {
  12436. uiObj.show();
  12437. });
  12438. },
  12439. toString: function() { return "Docker " + this.id }
  12440. });/**
  12441. * Copyright (c) 2006
  12442. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  12443. *
  12444. * Permission is hereby granted, free of charge, to any person obtaining a
  12445. * copy of this software and associated documentation files (the "Software"),
  12446. * to deal in the Software without restriction, including without limitation
  12447. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12448. * and/or sell copies of the Software, and to permit persons to whom the
  12449. * Software is furnished to do so, subject to the following conditions:
  12450. *
  12451. * The above copyright notice and this permission notice shall be included in
  12452. * all copies or substantial portions of the Software.
  12453. *
  12454. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12455. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12456. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  12457. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  12458. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  12459. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  12460. * DEALINGS IN THE SOFTWARE.
  12461. **/
  12462. /**
  12463. * Init namespaces
  12464. */
  12465. if(!ORYX) {var ORYX = {};}
  12466. if(!ORYX.Core) {ORYX.Core = {};}
  12467. if(!ORYX.Core.Controls) {ORYX.Core.Controls = {};}
  12468. /**
  12469. * @classDescription Represents a magnet that is part of another shape and can
  12470. * be attached to dockers. Magnets are used for linking edge objects
  12471. * to other Shape objects.
  12472. * @extends {Control}
  12473. */
  12474. ORYX.Core.Controls.Magnet = ORYX.Core.Controls.Control.extend({
  12475. /**
  12476. * Constructor
  12477. */
  12478. construct: function() {
  12479. arguments.callee.$.construct.apply(this, arguments);
  12480. //this.anchors = [];
  12481. this.anchorLeft;
  12482. this.anchorRight;
  12483. this.anchorTop;
  12484. this.anchorBottom;
  12485. this.bounds.set(0, 0, 16, 16);
  12486. //graft magnet's root node into owner's control group.
  12487. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg",
  12488. null,
  12489. ['g', {"pointer-events":"all"},
  12490. ['circle', {cx:"8", cy:"8", r:"4", stroke:"none", fill:"red", "fill-opacity":"0.3"}],
  12491. ]);
  12492. this.hide();
  12493. },
  12494. update: function() {
  12495. arguments.callee.$.update.apply(this, arguments);
  12496. //this.isChanged = true;
  12497. },
  12498. _update: function() {
  12499. arguments.callee.$.update.apply(this, arguments);
  12500. //this.isChanged = true;
  12501. },
  12502. refresh: function() {
  12503. arguments.callee.$.refresh.apply(this, arguments);
  12504. var p = this.bounds.upperLeft();
  12505. /*if(this.parent) {
  12506. var parentPos = this.parent.bounds.upperLeft();
  12507. p.x += parentPos.x;
  12508. p.y += parentPos.y;
  12509. }*/
  12510. this.node.setAttributeNS(null, 'transform','translate(' + p.x + ', ' + p.y + ')');
  12511. },
  12512. show: function() {
  12513. //this.refresh();
  12514. arguments.callee.$.show.apply(this, arguments);
  12515. },
  12516. toString: function() {
  12517. return "Magnet " + this.id;
  12518. }
  12519. });
  12520. /**
  12521. * Copyright (c) 2006
  12522. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  12523. *
  12524. * Permission is hereby granted, free of charge, to any person obtaining a
  12525. * copy of this software and associated documentation files (the "Software"),
  12526. * to deal in the Software without restriction, including without limitation
  12527. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  12528. * and/or sell copies of the Software, and to permit persons to whom the
  12529. * Software is furnished to do so, subject to the following conditions:
  12530. *
  12531. * The above copyright notice and this permission notice shall be included in
  12532. * all copies or substantial portions of the Software.
  12533. *
  12534. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12535. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  12536. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  12537. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  12538. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  12539. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  12540. * DEALINGS IN THE SOFTWARE.
  12541. **/
  12542. /**
  12543. * Init namespaces
  12544. */
  12545. if (!ORYX) {
  12546. var ORYX = {};
  12547. }
  12548. if (!ORYX.Core) {
  12549. ORYX.Core = {};
  12550. }
  12551. /**
  12552. * @classDescription Abstract base class for all Nodes.
  12553. * @extends ORYX.Core.Shape
  12554. */
  12555. ORYX.Core.Node = {
  12556. /**
  12557. * Constructor
  12558. * @param options {Object} A container for arguments.
  12559. * @param stencil {Stencil}
  12560. */
  12561. construct: function(options, stencil){
  12562. arguments.callee.$.construct.apply(this, arguments);
  12563. this.isSelectable = true;
  12564. this.isMovable = true;
  12565. this._dockerUpdated = false;
  12566. this._oldBounds = new ORYX.Core.Bounds(); //init bounds with undefined values
  12567. this._svgShapes = []; //array of all SVGShape objects of
  12568. // SVG representation
  12569. //TODO vielleicht in shape verschieben?
  12570. this.minimumSize = undefined; // {width:..., height:...}
  12571. this.maximumSize = undefined;
  12572. //TODO vielleicht in shape oder uiobject verschieben?
  12573. // vielleicht sogar isResizable ersetzen?
  12574. this.isHorizontallyResizable = false;
  12575. this.isVerticallyResizable = false;
  12576. this.dataId = undefined;
  12577. this._init(this._stencil.view());
  12578. },
  12579. /**
  12580. * This method checks whether the shape is resized correctly and calls the
  12581. * super class update method.
  12582. */
  12583. _update: function(){
  12584. this.dockers.invoke("update");
  12585. if (this.isChanged) {
  12586. var bounds = this.bounds;
  12587. var oldBounds = this._oldBounds;
  12588. if (this.isResized) {
  12589. var widthDelta = bounds.width() / oldBounds.width();
  12590. var heightDelta = bounds.height() / oldBounds.height();
  12591. //iterate over all relevant svg elements and resize them
  12592. this._svgShapes.each(function(svgShape){
  12593. //adjust width
  12594. if (svgShape.isHorizontallyResizable) {
  12595. svgShape.width = svgShape.oldWidth * widthDelta;
  12596. }
  12597. //adjust height
  12598. if (svgShape.isVerticallyResizable) {
  12599. svgShape.height = svgShape.oldHeight * heightDelta;
  12600. }
  12601. //check, if anchors are set
  12602. var anchorOffset;
  12603. var leftIncluded = svgShape.anchorLeft;
  12604. var rightIncluded = svgShape.anchorRight;
  12605. if (rightIncluded) {
  12606. anchorOffset = oldBounds.width() - (svgShape.oldX + svgShape.oldWidth);
  12607. if (leftIncluded) {
  12608. svgShape.width = bounds.width() - svgShape.x - anchorOffset;
  12609. }
  12610. else {
  12611. svgShape.x = bounds.width() - (anchorOffset + svgShape.width);
  12612. }
  12613. }
  12614. else
  12615. if (!leftIncluded) {
  12616. svgShape.x = widthDelta * svgShape.oldX;
  12617. if (!svgShape.isHorizontallyResizable) {
  12618. svgShape.x = svgShape.x + svgShape.width * widthDelta / 2 - svgShape.width / 2;
  12619. }
  12620. }
  12621. var topIncluded = svgShape.anchorTop;
  12622. var bottomIncluded = svgShape.anchorBottom;
  12623. if (bottomIncluded) {
  12624. anchorOffset = oldBounds.height() - (svgShape.oldY + svgShape.oldHeight);
  12625. if (topIncluded) {
  12626. svgShape.height = bounds.height() - svgShape.y - anchorOffset;
  12627. }
  12628. else {
  12629. // Hack for choreography task layouting
  12630. if (!svgShape._isYLocked) {
  12631. svgShape.y = bounds.height() - (anchorOffset + svgShape.height);
  12632. }
  12633. }
  12634. }
  12635. else
  12636. if (!topIncluded) {
  12637. svgShape.y = heightDelta * svgShape.oldY;
  12638. if (!svgShape.isVerticallyResizable) {
  12639. svgShape.y = svgShape.y + svgShape.height * heightDelta / 2 - svgShape.height / 2;
  12640. }
  12641. }
  12642. });
  12643. //check, if the current bounds is unallowed horizontally or vertically resized
  12644. var p = {
  12645. x: 0,
  12646. y: 0
  12647. };
  12648. if (!this.isHorizontallyResizable && bounds.width() !== oldBounds.width()) {
  12649. p.x = oldBounds.width() - bounds.width();
  12650. }
  12651. if (!this.isVerticallyResizable && bounds.height() !== oldBounds.height()) {
  12652. p.y = oldBounds.height() - bounds.height();
  12653. }
  12654. if (p.x !== 0 || p.y !== 0) {
  12655. bounds.extend(p);
  12656. }
  12657. //check, if the current bounds are between maximum and minimum bounds
  12658. p = {
  12659. x: 0,
  12660. y: 0
  12661. };
  12662. var widthDifference, heightDifference;
  12663. if (this.minimumSize) {
  12664. ORYX.Log.debug("Shape (%0)'s min size: (%1x%2)", this, this.minimumSize.width, this.minimumSize.height);
  12665. widthDifference = this.minimumSize.width - bounds.width();
  12666. if (widthDifference > 0) {
  12667. p.x += widthDifference;
  12668. }
  12669. heightDifference = this.minimumSize.height - bounds.height();
  12670. if (heightDifference > 0) {
  12671. p.y += heightDifference;
  12672. }
  12673. }
  12674. if (this.maximumSize) {
  12675. ORYX.Log.debug("Shape (%0)'s max size: (%1x%2)", this, this.maximumSize.width, this.maximumSize.height);
  12676. widthDifference = bounds.width() - this.maximumSize.width;
  12677. if (widthDifference > 0) {
  12678. p.x -= widthDifference;
  12679. }
  12680. heightDifference = bounds.height() - this.maximumSize.height;
  12681. if (heightDifference > 0) {
  12682. p.y -= heightDifference;
  12683. }
  12684. }
  12685. if (p.x !== 0 || p.y !== 0) {
  12686. bounds.extend(p);
  12687. }
  12688. //update magnets
  12689. var widthDelta = bounds.width() / oldBounds.width();
  12690. var heightDelta = bounds.height() / oldBounds.height();
  12691. var leftIncluded, rightIncluded, topIncluded, bottomIncluded, center, newX, newY;
  12692. this.magnets.each(function(magnet){
  12693. leftIncluded = magnet.anchorLeft;
  12694. rightIncluded = magnet.anchorRight;
  12695. topIncluded = magnet.anchorTop;
  12696. bottomIncluded = magnet.anchorBottom;
  12697. center = magnet.bounds.center();
  12698. if (leftIncluded) {
  12699. newX = center.x;
  12700. }
  12701. else
  12702. if (rightIncluded) {
  12703. newX = bounds.width() - (oldBounds.width() - center.x)
  12704. }
  12705. else {
  12706. newX = center.x * widthDelta;
  12707. }
  12708. if (topIncluded) {
  12709. newY = center.y;
  12710. }
  12711. else
  12712. if (bottomIncluded) {
  12713. newY = bounds.height() - (oldBounds.height() - center.y);
  12714. }
  12715. else {
  12716. newY = center.y * heightDelta;
  12717. }
  12718. if (center.x !== newX || center.y !== newY) {
  12719. magnet.bounds.centerMoveTo(newX, newY);
  12720. }
  12721. });
  12722. //set new position of labels
  12723. this.getLabels().each(function(label){
  12724. // Set the position dependings on it anchor
  12725. if (!label.isAnchorLeft()) {
  12726. if (label.isAnchorRight()) {
  12727. label.setX(bounds.width() - (oldBounds.width() - label.oldX))
  12728. } else {
  12729. label.setX((label.position?label.position.x:label.x) * widthDelta);
  12730. }
  12731. }
  12732. if (!label.isAnchorTop()) {
  12733. if (label.isAnchorBottom()) {
  12734. label.setY(bounds.height() - (oldBounds.height() - label.oldY));
  12735. } else {
  12736. label.setY((label.position?label.position.y:label.y) * heightDelta);
  12737. }
  12738. }
  12739. // If there is an position,
  12740. // set the origin position as well
  12741. if (label.position){
  12742. if (!label.isOriginAnchorLeft()) {
  12743. if (label.isOriginAnchorRight()) {
  12744. label.setOriginX(bounds.width() - (oldBounds.width() - label.oldX))
  12745. } else {
  12746. label.setOriginX(label.x * widthDelta);
  12747. }
  12748. }
  12749. if (!label.isOriginAnchorTop()) {
  12750. if (label.isOriginAnchorBottom()) {
  12751. label.setOriginY(bounds.height() - (oldBounds.height() - label.oldY));
  12752. } else {
  12753. label.setOriginY(label.y * heightDelta);
  12754. }
  12755. }
  12756. }
  12757. });
  12758. //update docker
  12759. var docker = this.dockers[0];
  12760. if (docker) {
  12761. docker.bounds.unregisterCallback(this._dockerChangedCallback);
  12762. if (!this._dockerUpdated) {
  12763. docker.bounds.centerMoveTo(this.bounds.center());
  12764. this._dockerUpdated = false;
  12765. }
  12766. docker.update();
  12767. docker.bounds.registerCallback(this._dockerChangedCallback);
  12768. }
  12769. this.isResized = false;
  12770. }
  12771. this.refresh();
  12772. this.isChanged = false;
  12773. this._oldBounds = this.bounds.clone();
  12774. }
  12775. this.children.each(function(value) {
  12776. if(!(value instanceof ORYX.Core.Controls.Docker)) {
  12777. value._update();
  12778. }
  12779. });
  12780. if (this.dockers.length > 0&&!this.dockers.first().getDockedShape()) {
  12781. this.dockers.each(function(docker){
  12782. docker.bounds.centerMoveTo(this.bounds.center())
  12783. }.bind(this))
  12784. }
  12785. /*this.incoming.each((function(edge) {
  12786. if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node))
  12787. edge._update(true);
  12788. }).bind(this));
  12789. this.outgoing.each((function(edge) {
  12790. if(!(this.dockers[0] && this.dockers[0].getDockedShape() instanceof ORYX.Core.Node))
  12791. edge._update(true);
  12792. }).bind(this)); */
  12793. },
  12794. /**
  12795. * This method repositions and resizes the SVG representation
  12796. * of the shape.
  12797. */
  12798. refresh: function(){
  12799. arguments.callee.$.refresh.apply(this, arguments);
  12800. /** Movement */
  12801. var x = this.bounds.upperLeft().x;
  12802. var y = this.bounds.upperLeft().y;
  12803. //set translation in transform attribute
  12804. /*var attributeTransform = document.createAttributeNS(ORYX.CONFIG.NAMESPACE_SVG, "transform");
  12805. attributeTransform.nodeValue = "translate(" + x + ", " + y + ")";
  12806. this.node.firstChild.setAttributeNode(attributeTransform);*/
  12807. // Move owner element
  12808. this.node.firstChild.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")");
  12809. // Move magnets
  12810. this.node.childNodes[1].childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")");
  12811. /** Resize */
  12812. //iterate over all relevant svg elements and update them
  12813. this._svgShapes.each(function(svgShape){
  12814. svgShape.update();
  12815. });
  12816. },
  12817. _dockerChanged: function(){
  12818. var docker = this.dockers[0];
  12819. //set the bounds of the the association
  12820. this.bounds.centerMoveTo(docker.bounds.center());
  12821. this._dockerUpdated = true;
  12822. //this._update(true);
  12823. },
  12824. /**
  12825. * This method traverses a tree of SVGElements and returns
  12826. * all SVGShape objects. For each basic shape or path element
  12827. * a SVGShape object is initialized.
  12828. *
  12829. * @param svgNode {SVGElement}
  12830. * @return {Array} Array of SVGShape objects
  12831. */
  12832. _initSVGShapes: function(svgNode){
  12833. var svgShapes = [];
  12834. try {
  12835. var svgShape = new ORYX.Core.SVG.SVGShape(svgNode);
  12836. svgShapes.push(svgShape);
  12837. }
  12838. catch (e) {
  12839. //do nothing
  12840. }
  12841. if (svgNode.hasChildNodes()) {
  12842. for (var i = 0; i < svgNode.childNodes.length; i++) {
  12843. svgShapes = svgShapes.concat(this._initSVGShapes(svgNode.childNodes[i]));
  12844. }
  12845. }
  12846. return svgShapes;
  12847. },
  12848. /**
  12849. * Calculate if the point is inside the Shape
  12850. * @param {PointX}
  12851. * @param {PointY}
  12852. * @param {absoluteBounds} optional: for performance
  12853. */
  12854. isPointIncluded: function(pointX, pointY, absoluteBounds){
  12855. // If there is an arguments with the absoluteBounds
  12856. var absBounds = absoluteBounds && absoluteBounds instanceof ORYX.Core.Bounds ? absoluteBounds : this.absoluteBounds();
  12857. if (!absBounds.isIncluded(pointX, pointY)) {
  12858. return false;
  12859. } else {
  12860. }
  12861. //point = Object.clone(point);
  12862. var ul = absBounds.upperLeft();
  12863. var x = pointX - ul.x;
  12864. var y = pointY - ul.y;
  12865. var i=0;
  12866. do {
  12867. var isPointIncluded = this._svgShapes[i++].isPointIncluded( x, y );
  12868. } while( !isPointIncluded && i < this._svgShapes.length)
  12869. return isPointIncluded;
  12870. /*return this._svgShapes.any(function(svgShape){
  12871. return svgShape.isPointIncluded(point);
  12872. });*/
  12873. },
  12874. /**
  12875. * Calculate if the point is over an special offset area
  12876. * @param {Point}
  12877. */
  12878. isPointOverOffset: function( pointX, pointY ){
  12879. var isOverEl = arguments.callee.$.isPointOverOffset.apply( this , arguments );
  12880. if (isOverEl) {
  12881. // If there is an arguments with the absoluteBounds
  12882. var absBounds = this.absoluteBounds();
  12883. absBounds.widen( - ORYX.CONFIG.BORDER_OFFSET );
  12884. if ( !absBounds.isIncluded( pointX, pointY )) {
  12885. return true;
  12886. }
  12887. }
  12888. return false;
  12889. },
  12890. serialize: function(){
  12891. var result = arguments.callee.$.serialize.apply(this);
  12892. // Add the docker's bounds
  12893. // nodes only have at most one docker!
  12894. this.dockers.each((function(docker){
  12895. if (docker.getDockedShape()) {
  12896. var center = docker.referencePoint;
  12897. center = center ? center : docker.bounds.center();
  12898. result.push({
  12899. name: 'docker',
  12900. prefix: 'oryx',
  12901. value: $H(center).values().join(','),
  12902. type: 'literal'
  12903. });
  12904. }
  12905. }).bind(this));
  12906. // Get the spezific serialized object from the stencil
  12907. try {
  12908. //result = this.getStencil().serialize(this, result);
  12909. var serializeEvent = this.getStencil().serialize();
  12910. /*
  12911. * call serialize callback by reference, result should be found
  12912. * in serializeEvent.result
  12913. */
  12914. if(serializeEvent.type) {
  12915. serializeEvent.shape = this;
  12916. serializeEvent.data = result;
  12917. serializeEvent.result = undefined;
  12918. serializeEvent.forceExecution = true;
  12919. this._delegateEvent(serializeEvent);
  12920. if(serializeEvent.result) {
  12921. result = serializeEvent.result;
  12922. }
  12923. }
  12924. }
  12925. catch (e) {
  12926. }
  12927. return result;
  12928. },
  12929. deserialize: function(data){
  12930. arguments.callee.$.deserialize.apply(this, arguments);
  12931. try {
  12932. //data = this.getStencil().deserialize(this, data);
  12933. var deserializeEvent = this.getStencil().deserialize();
  12934. /*
  12935. * call serialize callback by reference, result should be found
  12936. * in serializeEventInfo.result
  12937. */
  12938. if(deserializeEvent.type) {
  12939. deserializeEvent.shape = this;
  12940. deserializeEvent.data = data;
  12941. deserializeEvent.result = undefined;
  12942. deserializeEvent.forceExecution = true;
  12943. this._delegateEvent(deserializeEvent);
  12944. if(deserializeEvent.result) {
  12945. data = deserializeEvent.result;
  12946. }
  12947. }
  12948. }
  12949. catch (e) {
  12950. }
  12951. // Set the outgoing shapes
  12952. var outgoing = data.findAll(function(ser){ return (ser.prefix+"-"+ser.name) == 'raziel-outgoing'});
  12953. outgoing.each((function(obj){
  12954. // TODO: Look at Canvas
  12955. if(!this.parent) {return};
  12956. // Set outgoing Shape
  12957. var next = this.getCanvas().getChildShapeByResourceId(obj.value);
  12958. if(next){
  12959. if(next instanceof ORYX.Core.Edge) {
  12960. //Set the first docker of the next shape
  12961. next.dockers.first().setDockedShape(this);
  12962. next.dockers.first().setReferencePoint(next.dockers.first().bounds.center());
  12963. } else if(next.dockers.length > 0) { //next is a node and next has a docker
  12964. next.dockers.first().setDockedShape(this);
  12965. //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0});
  12966. }
  12967. }
  12968. }).bind(this));
  12969. if (this.dockers.length === 1) {
  12970. var dockerPos;
  12971. dockerPos = data.find(function(entry){
  12972. return (entry.prefix + "-" + entry.name === "oryx-dockers");
  12973. });
  12974. if (dockerPos) {
  12975. var points = dockerPos.value.replace(/,/g, " ").split(" ").without("").without("#");
  12976. if (points.length === 2 && this.dockers[0].getDockedShape()) {
  12977. this.dockers[0].setReferencePoint({
  12978. x: parseFloat(points[0]),
  12979. y: parseFloat(points[1])
  12980. });
  12981. }
  12982. else {
  12983. this.dockers[0].bounds.centerMoveTo(parseFloat(points[0]), parseFloat(points[1]));
  12984. }
  12985. }
  12986. }
  12987. },
  12988. /**
  12989. * This method excepts the SVGDoucment that is the SVG representation
  12990. * of this shape.
  12991. * The bounds of the shape are calculated, the SVG representation's upper left point
  12992. * is moved to 0,0 and it the method sets if this shape is resizable.
  12993. *
  12994. * @param {SVGDocument} svgDocument
  12995. */
  12996. _init: function(svgDocument){
  12997. arguments.callee.$._init.apply(this, arguments);
  12998. var svgNode = svgDocument.getElementsByTagName("g")[0]; //outer most g node
  12999. // set all required attributes
  13000. var attributeTitle = svgDocument.ownerDocument.createAttributeNS(null, "title");
  13001. attributeTitle.nodeValue = this.getStencil().title();
  13002. svgNode.setAttributeNode(attributeTitle);
  13003. var attributeId = svgDocument.ownerDocument.createAttributeNS(null, "id");
  13004. attributeId.nodeValue = this.id;
  13005. svgNode.setAttributeNode(attributeId);
  13006. //
  13007. var stencilTargetNode = this.node.childNodes[0].childNodes[0]; //<g class=me>"
  13008. svgNode = stencilTargetNode.appendChild(svgNode);
  13009. // Add to the EventHandler
  13010. this.addEventHandlers(svgNode.parentNode);
  13011. /**set minimum and maximum size*/
  13012. var minSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "minimumSize");
  13013. if (minSizeAttr) {
  13014. minSizeAttr = minSizeAttr.replace("/,/g", " ");
  13015. var minSizeValues = minSizeAttr.split(" ");
  13016. minSizeValues = minSizeValues.without("");
  13017. if (minSizeValues.length > 1) {
  13018. this.minimumSize = {
  13019. width: parseFloat(minSizeValues[0]),
  13020. height: parseFloat(minSizeValues[1])
  13021. };
  13022. }
  13023. else {
  13024. //set minimumSize to (1,1), so that width and height of the stencil can never be (0,0)
  13025. this.minimumSize = {
  13026. width: 1,
  13027. height: 1
  13028. };
  13029. }
  13030. }
  13031. var maxSizeAttr = svgNode.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "maximumSize");
  13032. if (maxSizeAttr) {
  13033. maxSizeAttr = maxSizeAttr.replace("/,/g", " ");
  13034. var maxSizeValues = maxSizeAttr.split(" ");
  13035. maxSizeValues = maxSizeValues.without("");
  13036. if (maxSizeValues.length > 1) {
  13037. this.maximumSize = {
  13038. width: parseFloat(maxSizeValues[0]),
  13039. height: parseFloat(maxSizeValues[1])
  13040. };
  13041. }
  13042. }
  13043. if (this.minimumSize && this.maximumSize &&
  13044. (this.minimumSize.width > this.maximumSize.width ||
  13045. this.minimumSize.height > this.maximumSize.height)) {
  13046. //TODO wird verschluckt!!!
  13047. throw this + ": Minimum Size must be greater than maxiumSize.";
  13048. }
  13049. /**get current bounds and adjust it to upperLeft == (0,0)*/
  13050. //initialize all SVGShape objects
  13051. this._svgShapes = this._initSVGShapes(svgNode);
  13052. //get upperLeft and lowerRight of stencil
  13053. var upperLeft = {
  13054. x: undefined,
  13055. y: undefined
  13056. };
  13057. var lowerRight = {
  13058. x: undefined,
  13059. y: undefined
  13060. };
  13061. var me = this;
  13062. this._svgShapes.each(function(svgShape){
  13063. upperLeft.x = (upperLeft.x !== undefined) ? Math.min(upperLeft.x, svgShape.x) : svgShape.x;
  13064. upperLeft.y = (upperLeft.y !== undefined) ? Math.min(upperLeft.y, svgShape.y) : svgShape.y;
  13065. lowerRight.x = (lowerRight.x !== undefined) ? Math.max(lowerRight.x, svgShape.x + svgShape.width) : svgShape.x + svgShape.width;
  13066. lowerRight.y = (lowerRight.y !== undefined) ? Math.max(lowerRight.y, svgShape.y + svgShape.height) : svgShape.y + svgShape.height;
  13067. /** set if resizing is enabled */
  13068. //TODO isResizable durch die beiden anderen booleans ersetzen?
  13069. if (svgShape.isHorizontallyResizable) {
  13070. me.isHorizontallyResizable = true;
  13071. me.isResizable = true;
  13072. }
  13073. if (svgShape.isVerticallyResizable) {
  13074. me.isVerticallyResizable = true;
  13075. me.isResizable = true;
  13076. }
  13077. if (svgShape.anchorTop && svgShape.anchorBottom) {
  13078. me.isVerticallyResizable = true;
  13079. me.isResizable = true;
  13080. }
  13081. if (svgShape.anchorLeft && svgShape.anchorRight) {
  13082. me.isHorizontallyResizable = true;
  13083. me.isResizable = true;
  13084. }
  13085. });
  13086. //move all SVGShapes by -upperLeft
  13087. this._svgShapes.each(function(svgShape){
  13088. svgShape.x -= upperLeft.x;
  13089. svgShape.y -= upperLeft.y;
  13090. svgShape.update();
  13091. });
  13092. //set bounds of shape
  13093. //the offsets are also needed for positioning the magnets and the docker
  13094. var offsetX = upperLeft.x;
  13095. var offsetY = upperLeft.y;
  13096. lowerRight.x -= offsetX;
  13097. lowerRight.y -= offsetY;
  13098. upperLeft.x = 0;
  13099. upperLeft.y = 0;
  13100. //prevent that width or height of initial bounds is 0
  13101. if (lowerRight.x === 0) {
  13102. lowerRight.x = 1;
  13103. }
  13104. if (lowerRight.y === 0) {
  13105. lowerRight.y = 1;
  13106. }
  13107. this._oldBounds.set(upperLeft, lowerRight);
  13108. this.bounds.set(upperLeft, lowerRight);
  13109. /**initialize magnets */
  13110. var magnets = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnets");
  13111. if (magnets && magnets.length > 0) {
  13112. magnets = $A(magnets[0].getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "magnet"));
  13113. var me = this;
  13114. magnets.each(function(magnetElem){
  13115. var magnet = new ORYX.Core.Controls.Magnet({
  13116. eventHandlerCallback: me.eventHandlerCallback
  13117. });
  13118. var cx = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx"));
  13119. var cy = parseFloat(magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy"));
  13120. magnet.bounds.centerMoveTo({
  13121. x: cx - offsetX,
  13122. y: cy - offsetY
  13123. });
  13124. //get anchors
  13125. var anchors = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors");
  13126. if (anchors) {
  13127. anchors = anchors.replace("/,/g", " ");
  13128. anchors = anchors.split(" ").without("");
  13129. for(var i = 0; i < anchors.length; i++) {
  13130. switch(anchors[i].toLowerCase()) {
  13131. case "left":
  13132. magnet.anchorLeft = true;
  13133. break;
  13134. case "right":
  13135. magnet.anchorRight = true;
  13136. break;
  13137. case "top":
  13138. magnet.anchorTop = true;
  13139. break;
  13140. case "bottom":
  13141. magnet.anchorBottom = true;
  13142. break;
  13143. }
  13144. }
  13145. }
  13146. me.add(magnet);
  13147. //check, if magnet is default magnet
  13148. if (!this._defaultMagnet) {
  13149. var defaultAttr = magnetElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "default");
  13150. if (defaultAttr && defaultAttr.toLowerCase() === "yes") {
  13151. me._defaultMagnet = magnet;
  13152. }
  13153. }
  13154. });
  13155. }
  13156. else {
  13157. // Add a Magnet in the Center of Shape
  13158. var magnet = new ORYX.Core.Controls.Magnet();
  13159. magnet.bounds.centerMoveTo(this.bounds.width() / 2, this.bounds.height() / 2);
  13160. this.add(magnet);
  13161. }
  13162. /**initialize docker */
  13163. var dockerElem = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_ORYX, "docker");
  13164. if (dockerElem && dockerElem.length > 0) {
  13165. dockerElem = dockerElem[0];
  13166. var docker = this.createDocker();
  13167. var cx = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cx"));
  13168. var cy = parseFloat(dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "cy"));
  13169. docker.bounds.centerMoveTo({
  13170. x: cx - offsetX,
  13171. y: cy - offsetY
  13172. });
  13173. //get anchors
  13174. var anchors = dockerElem.getAttributeNS(ORYX.CONFIG.NAMESPACE_ORYX, "anchors");
  13175. if (anchors) {
  13176. anchors = anchors.replace("/,/g", " ");
  13177. anchors = anchors.split(" ").without("");
  13178. for(var i = 0; i < anchors.length; i++) {
  13179. switch(anchors[i].toLowerCase()) {
  13180. case "left":
  13181. docker.anchorLeft = true;
  13182. break;
  13183. case "right":
  13184. docker.anchorRight = true;
  13185. break;
  13186. case "top":
  13187. docker.anchorTop = true;
  13188. break;
  13189. case "bottom":
  13190. docker.anchorBottom = true;
  13191. break;
  13192. }
  13193. }
  13194. }
  13195. }
  13196. /**initialize labels*/
  13197. var textElems = svgNode.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text');
  13198. $A(textElems).each((function(textElem){
  13199. var label = new ORYX.Core.SVG.Label({
  13200. textElement: textElem,
  13201. shapeId: this.id
  13202. });
  13203. label.x -= offsetX;
  13204. label.y -= offsetY;
  13205. this._labels[label.id] = label;
  13206. label.registerOnChange(this.layout.bind(this));
  13207. }).bind(this));
  13208. },
  13209. /**
  13210. * Override the Method, that a docker is not shown
  13211. *
  13212. */
  13213. createDocker: function() {
  13214. var docker = new ORYX.Core.Controls.Docker({eventHandlerCallback: this.eventHandlerCallback});
  13215. docker.bounds.registerCallback(this._dockerChangedCallback);
  13216. this.dockers.push( docker );
  13217. docker.parent = this;
  13218. docker.bounds.registerCallback(this._changedCallback);
  13219. return docker
  13220. },
  13221. toString: function(){
  13222. return this._stencil.title() + " " + this.id
  13223. }
  13224. };
  13225. ORYX.Core.Node = ORYX.Core.Shape.extend(ORYX.Core.Node);
  13226. /**
  13227. * Copyright (c) 2006
  13228. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  13229. *
  13230. * Permission is hereby granted, free of charge, to any person obtaining a
  13231. * copy of this software and associated documentation files (the "Software"),
  13232. * to deal in the Software without restriction, including without limitation
  13233. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  13234. * and/or sell copies of the Software, and to permit persons to whom the
  13235. * Software is furnished to do so, subject to the following conditions:
  13236. *
  13237. * The above copyright notice and this permission notice shall be included in
  13238. * all copies or substantial portions of the Software.
  13239. *
  13240. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13241. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13242. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  13243. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  13244. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  13245. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  13246. * DEALINGS IN THE SOFTWARE.
  13247. **/
  13248. NAMESPACE_SVG = "http://www.w3.org/2000/svg";
  13249. NAMESPACE_ORYX = "http://www.b3mn.org/oryx";
  13250. /**
  13251. * Init namespaces
  13252. */
  13253. if (!ORYX) {
  13254. var ORYX = {};
  13255. }
  13256. if (!ORYX.Core) {
  13257. ORYX.Core = {};
  13258. }
  13259. /**
  13260. * @classDescription Abstract base class for all connections.
  13261. * @extends {ORYX.Core.Shape}
  13262. * @param options {Object}
  13263. *
  13264. * TODO da die verschiebung der Edge nicht ueber eine
  13265. * translation gemacht wird, die sich auch auf alle kind UIObjects auswirkt,
  13266. * muessen die kinder hier beim verschieben speziell betrachtet werden.
  13267. * Das sollte ueberarbeitet werden.
  13268. *
  13269. */
  13270. ORYX.Core.Edge = {
  13271. /**
  13272. * Constructor
  13273. * @param {Object} options
  13274. * @param {Stencil} stencil
  13275. */
  13276. construct: function(options, stencil){
  13277. arguments.callee.$.construct.apply(this, arguments);
  13278. this.isMovable = true;
  13279. this.isSelectable = true;
  13280. this._dockerUpdated = false;
  13281. this._markers = new Hash(); //a hash map of SVGMarker objects where keys are the marker ids
  13282. this._paths = [];
  13283. this._interactionPaths = [];
  13284. this._dockersByPath = new Hash();
  13285. this._markersByPath = new Hash();
  13286. /* Data structures to store positioning information of attached child nodes */
  13287. this.attachedNodePositionData = new Hash();
  13288. //TODO was muss hier initial erzeugt werden?
  13289. var stencilNode = this.node.childNodes[0].childNodes[0];
  13290. stencilNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", stencilNode, ['g', {
  13291. "pointer-events": "painted"
  13292. }]);
  13293. //Add to the EventHandler
  13294. this.addEventHandlers(stencilNode.parentNode);
  13295. this._oldBounds = this.bounds.clone();
  13296. //load stencil
  13297. this._init(this._stencil.view());
  13298. if (stencil instanceof Array) {
  13299. this.deserialize(stencil);
  13300. }
  13301. },
  13302. _update: function(force){
  13303. if(this._dockerUpdated || this.isChanged || force) {
  13304. this.dockers.invoke("update");
  13305. if (false && (this.bounds.width() === 0 || this.bounds.height() === 0)) {
  13306. var width = this.bounds.width();
  13307. var height = this.bounds.height();
  13308. this.bounds.extend({
  13309. x: width === 0 ? 2 : 0,
  13310. y: height === 0 ? 2 : 0
  13311. });
  13312. this.bounds.moveBy({
  13313. x: width === 0 ? -1 : 0,
  13314. y: height === 0 ? -1 : 0
  13315. });
  13316. }
  13317. // TODO: Bounds muss abhaengig des Eltern-Shapes gesetzt werden
  13318. var upL = this.bounds.upperLeft();
  13319. var oldUpL = this._oldBounds.upperLeft();
  13320. var oldWidth = this._oldBounds.width() === 0 ? this.bounds.width() : this._oldBounds.width();
  13321. var oldHeight = this._oldBounds.height() === 0 ? this.bounds.height() : this._oldBounds.height();
  13322. var diffX = upL.x - oldUpL.x;
  13323. var diffY = upL.y - oldUpL.y;
  13324. var diffWidth = (this.bounds.width() / oldWidth) || 1;
  13325. var diffHeight = (this.bounds.height() / oldHeight) || 1;
  13326. this.dockers.each((function(docker){
  13327. // Unregister on BoundsChangedCallback
  13328. docker.bounds.unregisterCallback(this._dockerChangedCallback);
  13329. // If there is any changes at the edge and is there is not an DockersUpdate
  13330. // set the new bounds to the docker
  13331. if (!this._dockerUpdated) {
  13332. docker.bounds.moveBy(diffX, diffY);
  13333. if (diffWidth !== 1 || diffHeight !== 1) {
  13334. var relX = docker.bounds.upperLeft().x - upL.x;
  13335. var relY = docker.bounds.upperLeft().y - upL.y;
  13336. docker.bounds.moveTo(upL.x + relX * diffWidth, upL.y + relY * diffHeight);
  13337. }
  13338. }
  13339. // Do Docker update and register on DockersBoundChange
  13340. docker.update();
  13341. docker.bounds.registerCallback(this._dockerChangedCallback);
  13342. }).bind(this));
  13343. if (this._dockerUpdated) {
  13344. var a = this.dockers.first().bounds.center();
  13345. var b = this.dockers.first().bounds.center();
  13346. this.dockers.each((function(docker){
  13347. var center = docker.bounds.center();
  13348. a.x = Math.min(a.x, center.x);
  13349. a.y = Math.min(a.y, center.y);
  13350. b.x = Math.max(b.x, center.x);
  13351. b.y = Math.max(b.y, center.y);
  13352. }).bind(this));
  13353. //set the bounds of the the association
  13354. this.bounds.set(Object.clone(a), Object.clone(b));
  13355. }
  13356. upL = this.bounds.upperLeft(); oldUpL = this._oldBounds.upperLeft();
  13357. diffWidth = (this.bounds.width() / (oldWidth||this.bounds.width())); diffHeight = (this.bounds.height() / (oldHeight||this.bounds.height()));
  13358. diffX = upL.x - oldUpL.x; diffY = upL.y - oldUpL.y;
  13359. //reposition labels
  13360. this.getLabels().each(function(label) {
  13361. if (label.getReferencePoint()){
  13362. var ref = label.getReferencePoint();
  13363. var from = ref.segment.from, to = ref.segment.to;
  13364. if (!from || !from.parent || !to || !to.parent) {
  13365. return;
  13366. }
  13367. var fromPosition = from.bounds.center(), toPosition = to.bounds.center();
  13368. if (fromPosition.x === ref.segment.fromPosition.x && fromPosition.y === ref.segment.fromPosition.y &&
  13369. toPosition.x === ref.segment.toPosition.x && toPosition.y === ref.segment.toPosition.y && !ref.dirty){
  13370. return;
  13371. }
  13372. if (!this.parent.initializingShapes) {
  13373. var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection);
  13374. var newIntersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : oldDistance);
  13375. /**
  13376. * Set position
  13377. */
  13378. // Get the orthogonal identity vector of the current segment
  13379. var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition);
  13380. var isHor = Math.abs(oiv.y)===1, isVer = Math.abs(oiv.x)===1;
  13381. oiv.x *= ref.distance; oiv.y *= ref.distance; // vector * distance
  13382. oiv.x += newIntersection.x; oiv.y += newIntersection.y; // vector + the intersection point
  13383. var mx = isHor && ref.orientation && (ref.iorientation||ref.orientation).endsWith("r") ? -label.getWidth() : 0;
  13384. var my = isVer && ref.orientation && (ref.iorientation||ref.orientation).startsWith("l") ? -label.getHeight()+2 : 0;
  13385. label.setX(oiv.x+mx); label.setY(oiv.y+my);
  13386. // Update the reference point
  13387. this.updateReferencePointOfLabel(label, newIntersection, from, to);
  13388. } else {
  13389. var oiv = ORYX.Core.Math.getOrthogonalIdentityVector(fromPosition, toPosition);
  13390. oiv.x *= ref.distance; oiv.y *= ref.distance; // vector * distance
  13391. oiv.x += ref.intersection.x; oiv.y += ref.intersection.y; // vector + the intersection point
  13392. label.setX(oiv.x); label.setY(oiv.y);
  13393. ref.segment.fromPosition = fromPosition; ref.segment.toPosition = toPosition;
  13394. }
  13395. return;
  13396. }
  13397. // Update label position if no reference point is set
  13398. if (label.position && !this.parent.initializingShapes){
  13399. var x = label.position.x + (diffX * (diffWidth||1));
  13400. if (x > this.bounds.lowerRight().x){
  13401. x += this.bounds.width()-(this.bounds.width()/(diffWidth||1));
  13402. }
  13403. var y = label.position.y + (diffY * (diffHeight||1));
  13404. if (y > this.bounds.lowerRight().y){
  13405. y += this.bounds.height()-(this.bounds.height()/(diffHeight||1));
  13406. }
  13407. label.setX(x);label.setY(y);
  13408. return;
  13409. }
  13410. switch (label.getEdgePosition()) {
  13411. case "starttop":
  13412. var angle = this._getAngle(this.dockers[0], this.dockers[1]);
  13413. var pos = this.dockers.first().bounds.center();
  13414. if (angle <= 90 || angle > 270) {
  13415. label.horizontalAlign("left");
  13416. label.verticalAlign("bottom");
  13417. label.x = pos.x + label.getOffsetTop();
  13418. label.y = pos.y - label.getOffsetTop();
  13419. label.rotate(360 - angle, pos);
  13420. } else {
  13421. label.horizontalAlign("right");
  13422. label.verticalAlign("bottom");
  13423. label.x = pos.x - label.getOffsetTop();
  13424. label.y = pos.y - label.getOffsetTop();
  13425. label.rotate(180 - angle, pos);
  13426. }
  13427. break;
  13428. case "startmiddle":
  13429. var angle = this._getAngle(this.dockers[0], this.dockers[1]);
  13430. var pos = this.dockers.first().bounds.center();
  13431. if (angle <= 90 || angle > 270) {
  13432. label.horizontalAlign("left");
  13433. label.verticalAlign("bottom");
  13434. label.x = pos.x + 2;
  13435. label.y = pos.y + 4;
  13436. label.rotate(360 - angle, pos);
  13437. } else {
  13438. label.horizontalAlign("right");
  13439. label.verticalAlign("bottom");
  13440. label.x = pos.x + 1;
  13441. label.y = pos.y + 4;
  13442. label.rotate(180 - angle, pos);
  13443. }
  13444. break;
  13445. case "startbottom":
  13446. var angle = this._getAngle(this.dockers[0], this.dockers[1]);
  13447. var pos = this.dockers.first().bounds.center();
  13448. if (angle <= 90 || angle > 270) {
  13449. label.horizontalAlign("left");
  13450. label.verticalAlign("top");
  13451. label.x = pos.x + label.getOffsetBottom();
  13452. label.y = pos.y + label.getOffsetBottom();
  13453. label.rotate(360 - angle, pos);
  13454. } else {
  13455. label.horizontalAlign("right");
  13456. label.verticalAlign("top");
  13457. label.x = pos.x - label.getOffsetBottom();
  13458. label.y = pos.y + label.getOffsetBottom();
  13459. label.rotate(180 - angle, pos);
  13460. }
  13461. break;
  13462. case "midtop":
  13463. var numOfDockers = this.dockers.length;
  13464. if(numOfDockers%2 == 0) {
  13465. var angle = this._getAngle(this.dockers[numOfDockers/2-1], this.dockers[numOfDockers/2])
  13466. var pos1 = this.dockers[numOfDockers/2-1].bounds.center();
  13467. var pos2 = this.dockers[numOfDockers/2].bounds.center();
  13468. var pos = {x:(pos1.x + pos2.x)/2.0, y:(pos1.y+pos2.y)/2.0};
  13469. label.horizontalAlign("center");
  13470. label.verticalAlign("bottom");
  13471. label.x = pos.x;
  13472. label.y = pos.y - label.getOffsetTop();
  13473. if (angle <= 90 || angle > 270) {
  13474. label.rotate(360 - angle, pos);
  13475. } else {
  13476. label.rotate(180 - angle, pos);
  13477. }
  13478. } else {
  13479. var index = parseInt(numOfDockers/2);
  13480. var angle = this._getAngle(this.dockers[index], this.dockers[index+1])
  13481. var pos = this.dockers[index].bounds.center();
  13482. if (angle <= 90 || angle > 270) {
  13483. label.horizontalAlign("left");
  13484. label.verticalAlign("bottom");
  13485. label.x = pos.x + label.getOffsetTop();
  13486. label.y = pos.y - label.getOffsetTop();
  13487. label.rotate(360 - angle, pos);
  13488. } else {
  13489. label.horizontalAlign("right");
  13490. label.verticalAlign("bottom");
  13491. label.x = pos.x - label.getOffsetTop();
  13492. label.y = pos.y - label.getOffsetTop();
  13493. label.rotate(180 - angle, pos);
  13494. }
  13495. }
  13496. break;
  13497. case "midbottom":
  13498. var numOfDockers = this.dockers.length;
  13499. if(numOfDockers%2 == 0) {
  13500. var angle = this._getAngle(this.dockers[numOfDockers/2-1], this.dockers[numOfDockers/2])
  13501. var pos1 = this.dockers[numOfDockers/2-1].bounds.center();
  13502. var pos2 = this.dockers[numOfDockers/2].bounds.center();
  13503. var pos = {x:(pos1.x + pos2.x)/2.0, y:(pos1.y+pos2.y)/2.0};
  13504. label.horizontalAlign("center");
  13505. label.verticalAlign("top");
  13506. label.x = pos.x;
  13507. label.y = pos.y + label.getOffsetTop();
  13508. if (angle <= 90 || angle > 270) {
  13509. label.rotate(360 - angle, pos);
  13510. } else {
  13511. label.rotate(180 - angle, pos);
  13512. }
  13513. } else {
  13514. var index = parseInt(numOfDockers/2);
  13515. var angle = this._getAngle(this.dockers[index], this.dockers[index+1])
  13516. var pos = this.dockers[index].bounds.center();
  13517. if (angle <= 90 || angle > 270) {
  13518. label.horizontalAlign("left");
  13519. label.verticalAlign("top");
  13520. label.x = pos.x + label.getOffsetBottom();
  13521. label.y = pos.y + label.getOffsetBottom();
  13522. label.rotate(360 - angle, pos);
  13523. } else {
  13524. label.horizontalAlign("right");
  13525. label.verticalAlign("top");
  13526. label.x = pos.x - label.getOffsetBottom();
  13527. label.y = pos.y + label.getOffsetBottom();
  13528. label.rotate(180 - angle, pos);
  13529. }
  13530. }
  13531. break;
  13532. case "endtop":
  13533. var length = this.dockers.length;
  13534. var angle = this._getAngle(this.dockers[length-2], this.dockers[length-1]);
  13535. var pos = this.dockers.last().bounds.center();
  13536. if (angle <= 90 || angle > 270) {
  13537. label.horizontalAlign("right");
  13538. label.verticalAlign("bottom");
  13539. label.x = pos.x - label.getOffsetTop();
  13540. label.y = pos.y - label.getOffsetTop();
  13541. label.rotate(360 - angle, pos);
  13542. } else {
  13543. label.horizontalAlign("left");
  13544. label.verticalAlign("bottom");
  13545. label.x = pos.x + label.getOffsetTop();
  13546. label.y = pos.y - label.getOffsetTop();
  13547. label.rotate(180 - angle, pos);
  13548. }
  13549. break;
  13550. case "endbottom":
  13551. var length = this.dockers.length;
  13552. var angle = this._getAngle(this.dockers[length-2], this.dockers[length-1]);
  13553. var pos = this.dockers.last().bounds.center();
  13554. if (angle <= 90 || angle > 270) {
  13555. label.horizontalAlign("right");
  13556. label.verticalAlign("top");
  13557. label.x = pos.x - label.getOffsetBottom();
  13558. label.y = pos.y + label.getOffsetBottom();
  13559. label.rotate(360 - angle, pos);
  13560. } else {
  13561. label.horizontalAlign("left");
  13562. label.verticalAlign("top");
  13563. label.x = pos.x + label.getOffsetBottom();
  13564. label.y = pos.y + label.getOffsetBottom();
  13565. label.rotate(180 - angle, pos);
  13566. }
  13567. break;
  13568. }
  13569. }.bind(this));
  13570. this.children.each(function(value) {
  13571. if(value instanceof ORYX.Core.Node) {
  13572. this.calculatePositionOfAttachedChildNode.call(this, value);
  13573. }
  13574. }.bind(this));
  13575. this.refreshAttachedNodes();
  13576. this.refresh();
  13577. this.isChanged = false;
  13578. this._dockerUpdated = false;
  13579. this._oldBounds = this.bounds.clone();
  13580. }
  13581. },
  13582. /**
  13583. * Moves a point to the upperLeft of a node's bounds.
  13584. *
  13585. * @param {point} point
  13586. * The point to move
  13587. * @param {ORYX.Core.Bounds} bounds
  13588. * The Bounds of the related noe
  13589. */
  13590. movePointToUpperLeftOfNode: function(point, bounds) {
  13591. point.x -= bounds.width()/2;
  13592. point.y -= bounds.height()/2;
  13593. },
  13594. /**
  13595. * Refreshes the visual representation of edge's attached nodes.
  13596. */
  13597. refreshAttachedNodes: function() {
  13598. this.attachedNodePositionData.values().each(function(nodeData) {
  13599. var startPoint = nodeData.segment.docker1.bounds.center();
  13600. var endPoint = nodeData.segment.docker2.bounds.center();
  13601. this.relativizePoint(startPoint);
  13602. this.relativizePoint(endPoint);
  13603. var newNodePosition = new Object();
  13604. /* Calculate new x-coordinate */
  13605. newNodePosition.x = startPoint.x
  13606. + nodeData.relativDistanceFromDocker1
  13607. * (endPoint.x - startPoint.x);
  13608. /* Calculate new y-coordinate */
  13609. newNodePosition.y = startPoint.y
  13610. + nodeData.relativDistanceFromDocker1
  13611. * (endPoint.y - startPoint.y);
  13612. /* Convert new position to the upper left of the node */
  13613. this.movePointToUpperLeftOfNode(newNodePosition, nodeData.node.bounds);
  13614. /* Move node to its new position */
  13615. nodeData.node.bounds.moveTo(newNodePosition);
  13616. nodeData.node._update();
  13617. }.bind(this));
  13618. },
  13619. /**
  13620. * Calculates the position of an edge's child node. The node is placed on
  13621. * the path of the edge.
  13622. *
  13623. * @param {node}
  13624. * The node to calculate the new position
  13625. * @return {Point}
  13626. * The calculated upper left point of the node's shape.
  13627. */
  13628. calculatePositionOfAttachedChildNode: function(node) {
  13629. /* Initialize position */
  13630. var position = new Object();
  13631. position.x = 0;
  13632. position.y = 0;
  13633. /* Case: Node was just added */
  13634. if(!this.attachedNodePositionData[node.getId()]) {
  13635. this.attachedNodePositionData[node.getId()] = new Object();
  13636. this.attachedNodePositionData[node.getId()]
  13637. .relativDistanceFromDocker1 = 0;
  13638. this.attachedNodePositionData[node.getId()].node = node;
  13639. this.attachedNodePositionData[node.getId()].segment = new Object();
  13640. this.findEdgeSegmentForNode(node);
  13641. }else if(node.isChanged) {
  13642. this.findEdgeSegmentForNode(node);
  13643. }
  13644. },
  13645. /**
  13646. * Finds the appropriate edge segement for a node.
  13647. * The segment is choosen, which has the smallest distance to the node.
  13648. *
  13649. * @param {ORYX.Core.Node} node
  13650. * The concerning node
  13651. */
  13652. findEdgeSegmentForNode: function(node) {
  13653. var length = this.dockers.length;
  13654. var smallestDistance = undefined;
  13655. for(i=1;i<length;i++) {
  13656. var lineP1 = this.dockers[i-1].bounds.center();
  13657. var lineP2 = this.dockers[i].bounds.center();
  13658. this.relativizePoint(lineP1);
  13659. this.relativizePoint(lineP2);
  13660. var nodeCenterPoint = node.bounds.center();
  13661. var distance = ORYX.Core.Math.distancePointLinie(
  13662. lineP1,
  13663. lineP2,
  13664. nodeCenterPoint,
  13665. true);
  13666. if((distance || distance == 0) && ((!smallestDistance && smallestDistance != 0)
  13667. || distance < smallestDistance)) {
  13668. smallestDistance = distance;
  13669. this.attachedNodePositionData[node.getId()].segment.docker1 =
  13670. this.dockers[i-1];
  13671. this.attachedNodePositionData[node.getId()].segment.docker2 =
  13672. this.dockers[i];
  13673. }
  13674. /* Either the distance does not match the segment or the distance
  13675. * between docker1 and docker2 is 0
  13676. *
  13677. * In this case choose the nearest docker as attaching point.
  13678. *
  13679. */
  13680. if(!distance && !smallestDistance && smallestDistance != 0) {
  13681. (ORYX.Core.Math.getDistancePointToPoint(nodeCenterPoint, lineP1)
  13682. < ORYX.Core.Math.getDistancePointToPoint(nodeCenterPoint, lineP2)) ?
  13683. this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 0 :
  13684. this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 = 1;
  13685. this.attachedNodePositionData[node.getId()].segment.docker1 =
  13686. this.dockers[i-1];
  13687. this.attachedNodePositionData[node.getId()].segment.docker2 =
  13688. this.dockers[i];
  13689. }
  13690. }
  13691. /* Calculate position on edge segment for the node */
  13692. if(smallestDistance || smallestDistance == 0) {
  13693. this.attachedNodePositionData[node.getId()].relativDistanceFromDocker1 =
  13694. this.getLineParameterForPosition(
  13695. this.attachedNodePositionData[node.getId()].segment.docker1,
  13696. this.attachedNodePositionData[node.getId()].segment.docker2,
  13697. node);
  13698. }
  13699. },
  13700. /**
  13701. *
  13702. * @param {ORYX.Core.Node|Object} node or position
  13703. * @return {Object} An object with the following attribute: {ORYX.Core.Docker} fromDocker, {ORYX.Core.Docker} toDocker, {X/Y} position, {int} distance
  13704. */
  13705. findSegment: function(node){
  13706. var length = this.dockers.length;
  13707. var result;
  13708. var nodeCenterPoint = node instanceof ORYX.Core.UIObject ? node.bounds.center() : node;
  13709. for (i = 1; i < length; i++) {
  13710. var lineP1 = this.dockers[i - 1].bounds.center();
  13711. var lineP2 = this.dockers[i].bounds.center();
  13712. var distance = ORYX.Core.Math.distancePointLinie(lineP1, lineP2, nodeCenterPoint, true);
  13713. if (typeof distance == "number" && (result === undefined || distance < result.distance)) {
  13714. result = {
  13715. distance: distance,
  13716. fromDocker: this.dockers[i - 1],
  13717. toDocker: this.dockers[i]
  13718. }
  13719. }
  13720. }
  13721. return result;
  13722. },
  13723. /**
  13724. * Returns the value of the scalar to determine the position of the node on
  13725. * line defined by docker1 and docker2.
  13726. *
  13727. * @param {point} docker1
  13728. * The docker that defines the start of the line segment
  13729. * @param {point} docker2
  13730. * The docker that defines the end of the line segment
  13731. * @param {ORYX.Core.Node} node
  13732. * The concerning node
  13733. *
  13734. * @return {float} positionParameter
  13735. * The scalar value to determine the position on the line
  13736. */
  13737. getLineParameterForPosition: function(docker1, docker2, node) {
  13738. var dockerPoint1 = docker1.bounds.center();
  13739. var dockerPoint2 = docker2.bounds.center();
  13740. this.relativizePoint(dockerPoint1);
  13741. this.relativizePoint(dockerPoint2);
  13742. var intersectionPoint = ORYX.Core.Math.getPointOfIntersectionPointLine(
  13743. dockerPoint1,
  13744. dockerPoint2,
  13745. node.bounds.center(), true);
  13746. if(!intersectionPoint) {
  13747. return 0;
  13748. }
  13749. var relativeDistance =
  13750. ORYX.Core.Math.getDistancePointToPoint(intersectionPoint, dockerPoint1) /
  13751. ORYX.Core.Math.getDistancePointToPoint(dockerPoint1, dockerPoint2);
  13752. return relativeDistance;
  13753. },
  13754. /**
  13755. * Makes point relative to the upper left of the edge's bound.
  13756. *
  13757. * @param {point} point
  13758. * The point to relativize
  13759. */
  13760. relativizePoint: function(point) {
  13761. point.x -= this.bounds.upperLeft().x;
  13762. point.y -= this.bounds.upperLeft().y;
  13763. },
  13764. /**
  13765. * Move the first and last docker and calls the refresh method.
  13766. * Attention: This does not calculates intersection point between the
  13767. * edge and the bounded nodes. This only works if only the nodes are
  13768. * moves.
  13769. *
  13770. */
  13771. optimizedUpdate: function(){
  13772. var updateDocker = function(docker){
  13773. if (!docker._dockedShape || !docker._dockedShapeBounds)
  13774. return;
  13775. var off = {
  13776. x: docker._dockedShape.bounds.a.x - docker._dockedShapeBounds.a.x,
  13777. y: docker._dockedShape.bounds.a.y - docker._dockedShapeBounds.a.y
  13778. };
  13779. docker.bounds.moveBy(off);
  13780. docker._dockedShapeBounds.moveBy(off);
  13781. }
  13782. updateDocker(this.dockers.first());
  13783. updateDocker(this.dockers.last());
  13784. this.refresh();
  13785. },
  13786. refresh: function(){
  13787. //call base class refresh method
  13788. arguments.callee.$.refresh.apply(this, arguments);
  13789. //TODO consider points for marker mids
  13790. var lastPoint;
  13791. this._paths.each((function(path, index){
  13792. var dockers = this._dockersByPath[path.id];
  13793. var c = undefined;
  13794. var d = undefined;
  13795. if (lastPoint) {
  13796. d = "M" + lastPoint.x + " " + lastPoint.y;
  13797. }
  13798. else {
  13799. c = dockers[0].bounds.center();
  13800. lastPoint = c;
  13801. d = "M" + c.x + " " + c.y;
  13802. }
  13803. for (var i = 1; i < dockers.length; i++) {
  13804. // for each docker, draw a line to the center
  13805. c = dockers[i].bounds.center();
  13806. d = d + "L" + c.x + " " + c.y + " ";
  13807. lastPoint = c;
  13808. }
  13809. path.setAttributeNS(null, "d", d);
  13810. this._interactionPaths[index].setAttributeNS(null, "d", d);
  13811. }).bind(this));
  13812. /* move child shapes of an edge */
  13813. if(this.getChildNodes().length > 0) {
  13814. var x = this.bounds.upperLeft().x;
  13815. var y = this.bounds.upperLeft().y;
  13816. this.node.firstChild.childNodes[1].setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")");
  13817. }
  13818. },
  13819. /**
  13820. * Calculate the Border Intersection Point between two points
  13821. * @param {PointA}
  13822. * @param {PointB}
  13823. */
  13824. getIntersectionPoint: function(){
  13825. var length = Math.floor(this.dockers.length / 2)
  13826. return ORYX.Core.Math.midPoint(this.dockers[length - 1].bounds.center(), this.dockers[length].bounds.center())
  13827. },
  13828. /**
  13829. * Returns TRUE if the bounds is over the edge
  13830. * @param {Bounds}
  13831. *
  13832. */
  13833. isBoundsIncluded: function(bounds){
  13834. var dockers = this.dockers, size = dockers.length;
  13835. return dockers.any(function(docker, i){
  13836. if (i == size-1){ return false; }
  13837. var a = docker.bounds.center();
  13838. var b = dockers[i+1].bounds.center();
  13839. return ORYX.Core.Math.isRectOverLine(a.x, a.y, b.x, b.y, bounds.a.x, bounds.a.y, bounds.b.x, bounds.b.y);
  13840. });
  13841. },
  13842. /**
  13843. * Calculate if the point is inside the Shape
  13844. * @param {PointX}
  13845. * @param {PointY}
  13846. */
  13847. isPointIncluded: function(pointX, pointY){
  13848. var isbetweenAB = this.absoluteBounds().isIncluded(pointX, pointY,
  13849. ORYX.CONFIG.OFFSET_EDGE_BOUNDS);
  13850. var isPointIncluded = undefined;
  13851. if (isbetweenAB && this.dockers.length > 0) {
  13852. var i = 0;
  13853. var point1, point2;
  13854. do {
  13855. point1 = this.dockers[i].bounds.center();
  13856. point2 = this.dockers[++i].bounds.center();
  13857. isPointIncluded = ORYX.Core.Math.isPointInLine(pointX, pointY,
  13858. point1.x, point1.y,
  13859. point2.x, point2.y,
  13860. ORYX.CONFIG.OFFSET_EDGE_BOUNDS);
  13861. } while (!isPointIncluded && i < this.dockers.length - 1)
  13862. }
  13863. return isPointIncluded;
  13864. },
  13865. /**
  13866. * Calculate if the point is over an special offset area
  13867. * @param {Point}
  13868. */
  13869. isPointOverOffset: function(){
  13870. return false
  13871. },
  13872. /**
  13873. * Returns TRUE if the given node
  13874. * is a child node of the shapes node
  13875. * @param {Element} node
  13876. * @return {Boolean}
  13877. *
  13878. */
  13879. containsNode: function(node){
  13880. if (this._paths.include(node) ||
  13881. this._interactionPaths.include(node)){
  13882. return true;
  13883. }
  13884. return false;
  13885. },
  13886. /**
  13887. * Returns the angle of the line between two dockers
  13888. * (0 - 359.99999999)
  13889. */
  13890. _getAngle: function(docker1, docker2) {
  13891. var p1 = docker1 instanceof ORYX.Core.Controls.Docker ? docker1.absoluteCenterXY() : docker1;
  13892. var p2 = docker2 instanceof ORYX.Core.Controls.Docker ? docker2.absoluteCenterXY() : docker2;
  13893. return ORYX.Core.Math.getAngle(p1, p2);
  13894. },
  13895. alignDockers: function(){
  13896. this._update(true);
  13897. var firstPoint = this.dockers.first().bounds.center();
  13898. var lastPoint = this.dockers.last().bounds.center();
  13899. var deltaX = lastPoint.x - firstPoint.x;
  13900. var deltaY = lastPoint.y - firstPoint.y;
  13901. var numOfDockers = this.dockers.length - 1;
  13902. this.dockers.each((function(docker, index){
  13903. var part = index / numOfDockers;
  13904. docker.bounds.unregisterCallback(this._dockerChangedCallback);
  13905. docker.bounds.moveTo(firstPoint.x + part * deltaX, firstPoint.y + part * deltaY);
  13906. docker.bounds.registerCallback(this._dockerChangedCallback);
  13907. }).bind(this));
  13908. this._dockerChanged();
  13909. },
  13910. add: function(shape){
  13911. arguments.callee.$.add.apply(this, arguments);
  13912. // If the new shape is a Docker which is not contained
  13913. if (shape instanceof ORYX.Core.Controls.Docker && this.dockers.include(shape)){
  13914. // Add it to the dockers list ordered by paths
  13915. var pathArray = this._dockersByPath.values()[0];
  13916. if (pathArray) {
  13917. pathArray.splice(this.dockers.indexOf(shape), 0, shape);
  13918. }
  13919. /* Perform nessary adjustments on the edge's child shapes */
  13920. this.handleChildShapesAfterAddDocker(shape);
  13921. }
  13922. },
  13923. /**
  13924. * Performs nessary adjustments on the edge's child shapes.
  13925. *
  13926. * @param {ORYX.Core.Controls.Docker} docker
  13927. * The added docker
  13928. */
  13929. handleChildShapesAfterAddDocker: function(docker) {
  13930. /* Ensure type of Docker */
  13931. if(!docker instanceof ORYX.Core.Controls.Docker) {return undefined;}
  13932. var index = this.dockers.indexOf(docker);
  13933. if(!(0 < index && index < this.dockers.length - 1)) {
  13934. /* Exception: Expect added docker between first and last node of the edge */
  13935. return undefined;
  13936. }
  13937. /* Get child nodes concerning the segment of the new docker */
  13938. var startDocker = this.dockers[index-1];
  13939. var endDocker = this.dockers[index+1];
  13940. /* Adjust the position of edge's child nodes */
  13941. var segmentElements =
  13942. this.getAttachedNodePositionDataForSegment(startDocker, endDocker);
  13943. var lengthSegmentPart1 = ORYX.Core.Math.getDistancePointToPoint(
  13944. startDocker.bounds.center(),
  13945. docker.bounds.center());
  13946. var lengthSegmentPart2 = ORYX.Core.Math.getDistancePointToPoint(
  13947. endDocker.bounds.center(),
  13948. docker.bounds.center());
  13949. if(!(lengthSegmentPart1 + lengthSegmentPart2)) {return;}
  13950. var relativDockerPosition = lengthSegmentPart1 / (lengthSegmentPart1 + lengthSegmentPart2);
  13951. segmentElements.each(function(nodePositionData) {
  13952. /* Assign child node to the new segment */
  13953. if(nodePositionData.value.relativDistanceFromDocker1 < relativDockerPosition) {
  13954. /* Case: before added Docker */
  13955. nodePositionData.value.segment.docker2 = docker;
  13956. nodePositionData.value.relativDistanceFromDocker1 =
  13957. nodePositionData.value.relativDistanceFromDocker1 / relativDockerPosition;
  13958. } else {
  13959. /* Case: after added Docker */
  13960. nodePositionData.value.segment.docker1 = docker;
  13961. var newFullDistance = 1 - relativDockerPosition;
  13962. var relativPartOfSegment =
  13963. nodePositionData.value.relativDistanceFromDocker1
  13964. - relativDockerPosition;
  13965. nodePositionData.value.relativDistanceFromDocker1 =
  13966. relativPartOfSegment / newFullDistance;
  13967. }
  13968. })
  13969. // Update all labels reference points
  13970. this.getLabels().each(function(label){
  13971. var ref = label.getReferencePoint();
  13972. if (!ref) {
  13973. return;
  13974. }
  13975. var index = this.dockers.indexOf(docker);
  13976. if (index >= ref.segment.fromIndex && index <= ref.segment.toIndex){
  13977. var segment = this.findSegment(ref.intersection);
  13978. if (!segment){
  13979. // Choose whether the first of the last segment
  13980. segment.fromDocker = ref.segment.fromIndex >= (this.dockers.length/2) ? this.dockers[0] : this.dockers[this.dockers.length-2];
  13981. segment.toDocker = this.dockers[this.dockers.indexOf(from)+1]; // The next one if the to docker
  13982. }
  13983. var fromPosition = segment.fromDocker.bounds.center(), toPosition = segment.toDocker.bounds.center();
  13984. var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine(
  13985. fromPosition, // P1 - Center of the first docker
  13986. toPosition, // P2 - Center of the second docker
  13987. ref.intersection, // P3 - Center of the label
  13988. true);
  13989. //var oldDistance = ORYX.Core.Math.getDistanceBetweenTwoPoints(ref.segment.fromPosition, ref.segment.toPosition, ref.intersection);
  13990. //intersection = ORYX.Core.Math.getPointBetweenTwoPoints(fromPosition, toPosition, isNaN(oldDistance) ? 0.5 : (lengthOld*oldDistance)/lengthNew);
  13991. // Update the reference point
  13992. this.updateReferencePointOfLabel(label, intersection, segment.fromDocker, segment.toDocker, true);
  13993. }
  13994. }.bind(this));
  13995. /* Update attached nodes visual representation */
  13996. this.refreshAttachedNodes();
  13997. },
  13998. /**
  13999. * Returns elements from {@link attachedNodePositiondata} that match the
  14000. * segement defined by startDocker and endDocker.
  14001. *
  14002. * @param {ORYX.Core.Controls.Docker} startDocker
  14003. * The docker defining the begin of the segment.
  14004. * @param {ORYX.Core.Controls.Docker} endDocker
  14005. * The docker defining the begin of the segment.
  14006. *
  14007. * @return {Hash} attachedNodePositionData
  14008. * Child elements matching the segment
  14009. */
  14010. getAttachedNodePositionDataForSegment: function(startDocker, endDocker) {
  14011. /* Ensure that the segment is defined correctly */
  14012. if(!((startDocker instanceof ORYX.Core.Controls.Docker)
  14013. && (endDocker instanceof ORYX.Core.Controls.Docker))) {
  14014. return [];
  14015. }
  14016. /* Get elements of the segment */
  14017. var elementsOfSegment =
  14018. this.attachedNodePositionData.findAll(function(nodePositionData) {
  14019. return nodePositionData.value.segment.docker1 === startDocker &&
  14020. nodePositionData.value.segment.docker2 === endDocker;
  14021. });
  14022. /* Return a Hash in each case */
  14023. if(!elementsOfSegment) {return [];}
  14024. return elementsOfSegment;
  14025. },
  14026. /**
  14027. * Removes an edge's child shape
  14028. */
  14029. remove: function(shape) {
  14030. arguments.callee.$.remove.apply(this, arguments);
  14031. if(this.attachedNodePositionData[shape.getId()]) {
  14032. delete this.attachedNodePositionData[shape.getId()];
  14033. }
  14034. /* Adjust child shapes if neccessary */
  14035. if(shape instanceof ORYX.Core.Controls.Docker) {
  14036. this.handleChildShapesAfterRemoveDocker(shape);
  14037. }
  14038. },
  14039. updateReferencePointOfLabel: function(label, intersection, from, to, dirty){
  14040. if (!label.getReferencePoint() || !label.isVisible) {
  14041. return;
  14042. }
  14043. var ref = label.getReferencePoint();
  14044. //
  14045. if (ref.orientation && ref.orientation !== "ce"){
  14046. var angle = this._getAngle(from, to);
  14047. if (ref.distance >= 0){
  14048. if(angle == 0){
  14049. label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left");
  14050. label.verticalAlign("bottom");
  14051. } else if (angle > 0 && angle < 90){
  14052. label.horizontalAlign("right");
  14053. label.verticalAlign("bottom");
  14054. } else if (angle == 90){
  14055. label.horizontalAlign("right");
  14056. label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top");
  14057. } else if (angle > 90 && angle < 180){
  14058. label.horizontalAlign("right");
  14059. label.verticalAlign("top");
  14060. } else if (angle == 180){
  14061. label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left");
  14062. label.verticalAlign("top");
  14063. } else if (angle > 180 && angle < 270){
  14064. label.horizontalAlign("left");
  14065. label.verticalAlign("top");
  14066. } else if (angle == 270){
  14067. label.horizontalAlign("left");
  14068. label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top");
  14069. } else if (angle > 270 && angle <= 360){
  14070. label.horizontalAlign("left");
  14071. label.verticalAlign("bottom");
  14072. }
  14073. } else {
  14074. if(angle == 0){
  14075. label.horizontalAlign("left");//ref.orientation == "ur" ? "right" : "left");
  14076. label.verticalAlign("top");
  14077. } else if (angle > 0 && angle < 90){
  14078. label.horizontalAlign("left");
  14079. label.verticalAlign("top");
  14080. } else if (angle == 90){
  14081. label.horizontalAlign("left");
  14082. label.verticalAlign("top");//ref.orientation == "ll" ? "bottom" : "top");
  14083. } else if (angle > 90 && angle < 180){
  14084. label.horizontalAlign("left");
  14085. label.verticalAlign("bottom");
  14086. } else if (angle == 180){
  14087. label.horizontalAlign("left");//ref.orientation == "lr" ? "right" : "left");
  14088. label.verticalAlign("bottom");
  14089. } else if (angle > 180 && angle < 270){
  14090. label.horizontalAlign("right");
  14091. label.verticalAlign("bottom");
  14092. } else if (angle == 270){
  14093. label.horizontalAlign("right");
  14094. label.verticalAlign("top");//ref.orientation == "lr" ? "bottom" : "top");
  14095. } else if (angle > 270 && angle <= 360){
  14096. label.horizontalAlign("right");
  14097. label.verticalAlign("top");
  14098. }
  14099. }
  14100. ref.iorientation = ref.iorientation || ref.orientation;
  14101. ref.orientation = (label.verticalAlign()=="top"?"u":"l") + (label.horizontalAlign()=="left"?"l":"r");
  14102. }
  14103. label.setReferencePoint(Ext.apply({},{
  14104. intersection: intersection,
  14105. segment: {
  14106. from: from,
  14107. fromIndex: this.dockers.indexOf(from),
  14108. fromPosition: from.bounds.center(),
  14109. to: to,
  14110. toIndex: this.dockers.indexOf(to),
  14111. toPosition: to.bounds.center()
  14112. },
  14113. dirty: dirty || false
  14114. },ref))
  14115. },
  14116. /**
  14117. * Adjusts the child shapes of an edges after a docker was removed.
  14118. *
  14119. * @param{ORYX.Core.Controls.Docker} docker
  14120. * The removed docker.
  14121. */
  14122. handleChildShapesAfterRemoveDocker: function(docker) {
  14123. /* Ensure docker type */
  14124. if(!(docker instanceof ORYX.Core.Controls.Docker)) {return;}
  14125. this.attachedNodePositionData.each(function(nodePositionData) {
  14126. if(nodePositionData.value.segment.docker1 === docker) {
  14127. /* The new start of the segment is the predecessor of docker2. */
  14128. var index = this.dockers.indexOf(nodePositionData.value.segment.docker2);
  14129. if(index == -1) {return;}
  14130. nodePositionData.value.segment.docker1 = this.dockers[index - 1];
  14131. }
  14132. else if(nodePositionData.value.segment.docker2 === docker) {
  14133. /* The new end of the segment is the successor of docker1. */
  14134. var index = this.dockers.indexOf(nodePositionData.value.segment.docker1);
  14135. if(index == -1) {return;}
  14136. nodePositionData.value.segment.docker2 = this.dockers[index + 1];
  14137. }
  14138. }.bind(this));
  14139. // Update all labels reference points
  14140. this.getLabels().each(function(label){
  14141. var ref = label.getReferencePoint();
  14142. if (!ref) {
  14143. return;
  14144. }
  14145. var from = ref.segment.from;
  14146. var to = ref.segment.to;
  14147. if (from !== docker && to !== docker){
  14148. return;
  14149. }
  14150. var segment = this.findSegment(ref.intersection);
  14151. if (!segment){
  14152. from = segment.fromDocker;
  14153. to = segment.toDocker;
  14154. } else {
  14155. from = from === docker ? this.dockers[this.dockers.indexOf(to)-1] : from;
  14156. to = this.dockers[this.dockers.indexOf(from)+1];
  14157. }
  14158. var intersection = ORYX.Core.Math.getPointOfIntersectionPointLine(from.bounds.center(), to.bounds.center(), ref.intersection, true);
  14159. // Update the reference point
  14160. this.updateReferencePointOfLabel(label, intersection, from, to, true);
  14161. }.bind(this));
  14162. /* Update attached nodes visual representation */
  14163. this.refreshAttachedNodes();
  14164. },
  14165. /**
  14166. *@deprecated Use the .createDocker() Method and set the point via the bounds
  14167. */
  14168. addDocker: function(position, exDocker){
  14169. var lastDocker;
  14170. var result;
  14171. this._dockersByPath.any((function(pair){
  14172. return pair.value.any((function(docker, index){
  14173. if (!lastDocker) {
  14174. lastDocker = docker;
  14175. return false;
  14176. }
  14177. else {
  14178. var point1 = lastDocker.bounds.center();
  14179. var point2 = docker.bounds.center();
  14180. if (ORYX.Core.Math.isPointInLine(position.x, position.y, point1.x, point1.y, point2.x, point2.y, 10)) {
  14181. var path = this._paths.find(function(path){
  14182. return path.id === pair.key;
  14183. });
  14184. if (path) {
  14185. var allowAttr = path.getAttributeNS(NAMESPACE_ORYX, 'allowDockers');
  14186. if (allowAttr && allowAttr.toLowerCase() === "no") {
  14187. return true;
  14188. }
  14189. }
  14190. var newDocker = (exDocker) ? exDocker : this.createDocker(this.dockers.indexOf(lastDocker) + 1, position);
  14191. newDocker.bounds.centerMoveTo(position);
  14192. if(exDocker)
  14193. this.add(newDocker, this.dockers.indexOf(lastDocker) + 1);
  14194. // Remove new Docker from 'to add' dockers
  14195. //pair.value = pair.value.without(newDocker);
  14196. //pair.value.splice(this.dockers.indexOf(lastDocker) + 1, 0, newDocker);
  14197. // Remove the Docker from the Docker list and add the Docker to the new position
  14198. //this.dockers = this.dockers.without(newDocker);
  14199. //this.dockers.splice(this.dockers.indexOf(lastDocker) + 1, 0, newDocker);
  14200. //this._update(true);
  14201. result = newDocker;
  14202. return true;
  14203. }
  14204. else {
  14205. lastDocker = docker;
  14206. return false;
  14207. }
  14208. }
  14209. }).bind(this));
  14210. }).bind(this));
  14211. return result;
  14212. },
  14213. removeDocker: function(docker){
  14214. if (this.dockers.length > 2 && !(this.dockers.first() === docker)) {
  14215. this._dockersByPath.any((function(pair){
  14216. if (pair.value.member(docker)) {
  14217. if (docker === pair.value.last()) {
  14218. return true;
  14219. }
  14220. else {
  14221. this.remove(docker);
  14222. this._dockersByPath[pair.key] = pair.value.without(docker);
  14223. this.isChanged = true;
  14224. this._dockerChanged();
  14225. return true;
  14226. }
  14227. }
  14228. return false;
  14229. }).bind(this));
  14230. }
  14231. },
  14232. /**
  14233. * Removes all dockers from the edge which are on
  14234. * the line between two dockers
  14235. * @return {Object} Removed dockers in an indicied array
  14236. * (key is the removed position of the docker, value is docker themselve)
  14237. */
  14238. removeUnusedDockers:function(){
  14239. var marked = $H({});
  14240. this.dockers.each(function(docker, i){
  14241. if (i==0||i==this.dockers.length-1){ return }
  14242. var previous = this.dockers[i-1];
  14243. /* Do not consider already removed dockers */
  14244. if(marked.values().indexOf(previous) != -1 && this.dockers[i-2]) {
  14245. previous = this.dockers[i-2];
  14246. }
  14247. var next = this.dockers[i+1];
  14248. var cp = previous.getDockedShape() && previous.referencePoint ? previous.getAbsoluteReferencePoint() : previous.bounds.center();
  14249. var cn = next.getDockedShape() && next.referencePoint ? next.getAbsoluteReferencePoint() : next.bounds.center();
  14250. var cd = docker.bounds.center();
  14251. if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 1)){
  14252. marked[i] = docker;
  14253. }
  14254. }.bind(this))
  14255. marked.each(function(docker){
  14256. this.removeDocker(docker.value);
  14257. }.bind(this))
  14258. if (marked.values().length > 0){
  14259. this._update(true);
  14260. }
  14261. return marked;
  14262. },
  14263. /**
  14264. * Initializes the Edge after loading the SVG representation of the edge.
  14265. * @param {SVGDocument} svgDocument
  14266. */
  14267. _init: function(svgDocument){
  14268. arguments.callee.$._init.apply(this, arguments);
  14269. var minPointX, minPointY, maxPointX, maxPointY;
  14270. //init markers
  14271. var defs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "defs");
  14272. if (defs.length > 0) {
  14273. defs = defs[0];
  14274. var markerElements = $A(defs.getElementsByTagNameNS(NAMESPACE_SVG, "marker"));
  14275. var marker;
  14276. var me = this;
  14277. markerElements.each(function(markerElement){
  14278. try {
  14279. marker = new ORYX.Core.SVG.SVGMarker(markerElement.cloneNode(true));
  14280. me._markers[marker.id] = marker;
  14281. var textElements = $A(marker.element.getElementsByTagNameNS(NAMESPACE_SVG, "text"));
  14282. var label;
  14283. textElements.each(function(textElement){
  14284. label = new ORYX.Core.SVG.Label({
  14285. textElement: textElement,
  14286. shapeId: this.id
  14287. });
  14288. me._labels[label.id] = label;
  14289. });
  14290. }
  14291. catch (e) {
  14292. }
  14293. });
  14294. }
  14295. var gs = svgDocument.getElementsByTagNameNS(NAMESPACE_SVG, "g");
  14296. if (gs.length <= 0) {
  14297. throw "Edge: No g element found.";
  14298. }
  14299. var g = gs[0];
  14300. g.setAttributeNS(null, "id", null);
  14301. var isFirst = true;
  14302. $A(g.childNodes).each((function(path, index){
  14303. if (ORYX.Editor.checkClassType(path, SVGPathElement)) {
  14304. path = path.cloneNode(false);
  14305. var pathId = this.id + "_" + index;
  14306. path.setAttributeNS(null, "id", pathId);
  14307. this._paths.push(path);
  14308. //check, if markers are set and update the id
  14309. var markersByThisPath = [];
  14310. var markerUrl = path.getAttributeNS(null, "marker-start");
  14311. if (markerUrl && markerUrl !== "") {
  14312. markerUrl = markerUrl.strip();
  14313. markerUrl = markerUrl.replace(/^url\(#/, '');
  14314. var markerStartId = this.id.concat(markerUrl.replace(/\)$/, ''));
  14315. path.setAttributeNS(null, "marker-start", "url(#" + markerStartId + ")");
  14316. markersByThisPath.push(this._markers[markerStartId]);
  14317. }
  14318. markerUrl = path.getAttributeNS(null, "marker-mid");
  14319. if (markerUrl && markerUrl !== "") {
  14320. markerUrl = markerUrl.strip();
  14321. markerUrl = markerUrl.replace(/^url\(#/, '');
  14322. var markerMidId = this.id.concat(markerUrl.replace(/\)$/, ''));
  14323. path.setAttributeNS(null, "marker-mid", "url(#" + markerMidId + ")");
  14324. markersByThisPath.push(this._markers[markerMidId]);
  14325. }
  14326. markerUrl = path.getAttributeNS(null, "marker-end");
  14327. if (markerUrl && markerUrl !== "") {
  14328. markerUrl = markerUrl.strip();
  14329. markerUrl = markerUrl.replace(/^url\(#/, '');
  14330. var markerEndId = this.id.concat(markerUrl.replace(/\)$/, ''));
  14331. path.setAttributeNS(null, "marker-end", "url(#" + markerEndId + ")");
  14332. markersByThisPath.push(this._markers[markerEndId]);
  14333. }
  14334. this._markersByPath[pathId] = markersByThisPath;
  14335. //init dockers
  14336. var parser = new PathParser();
  14337. var handler = new ORYX.Core.SVG.PointsPathHandler();
  14338. parser.setHandler(handler);
  14339. parser.parsePath(path);
  14340. if (handler.points.length < 4) {
  14341. throw "Edge: Path has to have two or more points specified.";
  14342. }
  14343. this._dockersByPath[pathId] = [];
  14344. for (var i = 0; i < handler.points.length; i += 2) {
  14345. //handler.points.each((function(point, pIndex){
  14346. var x = handler.points[i];
  14347. var y = handler.points[i+1];
  14348. if (isFirst || i > 0) {
  14349. var docker = new ORYX.Core.Controls.Docker({
  14350. eventHandlerCallback: this.eventHandlerCallback
  14351. });
  14352. docker.bounds.centerMoveTo(x,y);
  14353. docker.bounds.registerCallback(this._dockerChangedCallback);
  14354. this.add(docker, this.dockers.length);
  14355. //this._dockersByPath[pathId].push(docker);
  14356. //calculate minPoint and maxPoint
  14357. if (minPointX) {
  14358. minPointX = Math.min(x, minPointX);
  14359. minPointY = Math.min(y, minPointY);
  14360. }
  14361. else {
  14362. minPointX = x;
  14363. minPointY = y;
  14364. }
  14365. if (maxPointX) {
  14366. maxPointX = Math.max(x, maxPointX);
  14367. maxPointY = Math.max(y, maxPointY);
  14368. }
  14369. else {
  14370. maxPointX = x;
  14371. maxPointY = y;
  14372. }
  14373. }
  14374. //}).bind(this));
  14375. }
  14376. isFirst = false;
  14377. }
  14378. }).bind(this));
  14379. this.bounds.set(minPointX, minPointY, maxPointX, maxPointY);
  14380. if (false&&(this.bounds.width() === 0 || this.bounds.height() === 0)) {
  14381. var width = this.bounds.width();
  14382. var height = this.bounds.height();
  14383. this.bounds.extend({
  14384. x: width === 0 ? 2 : 0,
  14385. y: height === 0 ? 2 : 0
  14386. });
  14387. this.bounds.moveBy({
  14388. x: width === 0 ? -1 : 0,
  14389. y: height === 0 ? -1 : 0
  14390. });
  14391. }
  14392. this._oldBounds = this.bounds.clone();
  14393. //add paths to this.node
  14394. this._paths.reverse();
  14395. var paths = [];
  14396. this._paths.each((function(path){
  14397. paths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(path));
  14398. }).bind(this));
  14399. this._paths = paths;
  14400. //init interaction path
  14401. this._paths.each((function(path){
  14402. var iPath = path.cloneNode(false);
  14403. iPath.setAttributeNS(null, "id", undefined);
  14404. iPath.setAttributeNS(null, "stroke-width", 10);
  14405. iPath.setAttributeNS(null, "visibility", "hidden");
  14406. iPath.setAttributeNS(null, "stroke-dasharray", null);
  14407. iPath.setAttributeNS(null, "stroke", "black");
  14408. iPath.setAttributeNS(null, "fill", "none");
  14409. iPath.setAttributeNS(null, "title", this.getStencil().title());
  14410. this._interactionPaths.push(this.node.childNodes[0].childNodes[0].childNodes[0].appendChild(iPath));
  14411. }).bind(this));
  14412. this._paths.reverse();
  14413. this._interactionPaths.reverse();
  14414. /**initialize labels*/
  14415. var textElems = svgDocument.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text');
  14416. $A(textElems).each((function(textElem){
  14417. var label = new ORYX.Core.SVG.Label({
  14418. textElement: textElem,
  14419. shapeId: this.id
  14420. });
  14421. this.node.childNodes[0].childNodes[0].appendChild(label.node);
  14422. this._labels[label.id] = label;
  14423. label.registerOnChange(this.layout.bind(this));
  14424. }).bind(this));
  14425. this.propertiesChanged.each(function(pair){
  14426. pair.value = true;
  14427. });
  14428. //this._update(true);
  14429. },
  14430. /**
  14431. * Adds all necessary markers of this Edge to the SVG document.
  14432. * Has to be called, while this.node is part of DOM.
  14433. */
  14434. addMarkers: function(defs){
  14435. this._markers.each(function(marker){
  14436. if (!defs.ownerDocument.getElementById(marker.value.id)) {
  14437. marker.value.element = defs.appendChild(marker.value.element);
  14438. }
  14439. });
  14440. },
  14441. /**
  14442. * Removes all necessary markers of this Edge from the SVG document.
  14443. * Has to be called, while this.node is part of DOM.
  14444. */
  14445. removeMarkers: function(){
  14446. var svgElement = this.node.ownerSVGElement;
  14447. if (svgElement) {
  14448. var defs = svgElement.getElementsByTagNameNS(NAMESPACE_SVG, "defs");
  14449. if (defs.length > 0) {
  14450. defs = defs[0];
  14451. this._markers.each(function(marker){
  14452. var foundMarker = defs.ownerDocument.getElementById(marker.value.id);
  14453. if (foundMarker) {
  14454. marker.value.element = defs.removeChild(marker.value.element);
  14455. }
  14456. });
  14457. }
  14458. }
  14459. },
  14460. /**
  14461. * Calls when a docker has changed
  14462. */
  14463. _dockerChanged: function(){
  14464. //this._update(true);
  14465. this._dockerUpdated = true;
  14466. },
  14467. serialize: function(){
  14468. var result = arguments.callee.$.serialize.apply(this);
  14469. //add dockers triple
  14470. var value = "";
  14471. this._dockersByPath.each((function(pair){
  14472. pair.value.each(function(docker){
  14473. var position = docker.getDockedShape() && docker.referencePoint ? docker.referencePoint : docker.bounds.center();
  14474. value = value.concat(position.x + " " + position.y + " ");
  14475. });
  14476. value += " # ";
  14477. }).bind(this));
  14478. result.push({
  14479. name: 'dockers',
  14480. prefix: 'oryx',
  14481. value: value,
  14482. type: 'literal'
  14483. });
  14484. //add parent triple dependant on the dockedShapes
  14485. //TODO change this when canvas becomes a resource
  14486. /* var source = this.dockers.first().getDockedShape();
  14487. var target = this.dockers.last().getDockedShape();
  14488. var sharedParent;
  14489. if (source && target) {
  14490. //get shared parent
  14491. while (source.parent) {
  14492. source = source.parent;
  14493. if (source instanceof ORYX.Core.Canvas) {
  14494. sharedParent = source;
  14495. break;
  14496. }
  14497. else {
  14498. var targetParent = target.parent;
  14499. var found;
  14500. while (targetParent) {
  14501. if (source === targetParent) {
  14502. sharedParent = source;
  14503. found = true;
  14504. break;
  14505. }
  14506. else {
  14507. targetParent = targetParent.parent;
  14508. }
  14509. }
  14510. if (found) {
  14511. break;
  14512. }
  14513. }
  14514. }
  14515. }
  14516. else
  14517. if (source) {
  14518. sharedParent = source.parent;
  14519. }
  14520. else
  14521. if (target) {
  14522. sharedParent = target.parent;
  14523. }
  14524. */
  14525. //if (sharedParent) {
  14526. /* result.push({
  14527. name: 'parent',
  14528. prefix: 'raziel',
  14529. //value: '#' + ERDF.__stripHashes(sharedParent.resourceId),
  14530. value: '#' + ERDF.__stripHashes(this.getCanvas().resourceId),
  14531. type: 'resource'
  14532. });*/
  14533. //}
  14534. //serialize target and source
  14535. var lastDocker = this.dockers.last();
  14536. var target = lastDocker.getDockedShape();
  14537. if(target) {
  14538. result.push({
  14539. name: 'target',
  14540. prefix: 'raziel',
  14541. value: '#' + ERDF.__stripHashes(target.resourceId),
  14542. type: 'resource'
  14543. });
  14544. }
  14545. try {
  14546. //result = this.getStencil().serialize(this, result);
  14547. var serializeEvent = this.getStencil().serialize();
  14548. /*
  14549. * call serialize callback by reference, result should be found
  14550. * in serializeEvent.result
  14551. */
  14552. if(serializeEvent.type) {
  14553. serializeEvent.shape = this;
  14554. serializeEvent.data = result;
  14555. serializeEvent.result = undefined;
  14556. serializeEvent.forceExecution = true;
  14557. this._delegateEvent(serializeEvent);
  14558. if(serializeEvent.result) {
  14559. result = serializeEvent.result;
  14560. }
  14561. }
  14562. }
  14563. catch (e) {
  14564. }
  14565. return result;
  14566. },
  14567. deserialize: function(data){
  14568. try {
  14569. //data = this.getStencil().deserialize(this, data);
  14570. var deserializeEvent = this.getStencil().deserialize();
  14571. /*
  14572. * call serialize callback by reference, result should be found
  14573. * in serializeEventInfo.result
  14574. */
  14575. if(deserializeEvent.type) {
  14576. deserializeEvent.shape = this;
  14577. deserializeEvent.data = data;
  14578. deserializeEvent.result = undefined;
  14579. deserializeEvent.forceExecution = true;
  14580. this._delegateEvent(deserializeEvent);
  14581. if(deserializeEvent.result) {
  14582. data = deserializeEvent.result;
  14583. }
  14584. }
  14585. }
  14586. catch (e) {
  14587. }
  14588. // Set the outgoing shapes
  14589. var target = data.find(function(ser) {return (ser.prefix+"-"+ser.name) == 'raziel-target'});
  14590. var targetShape;
  14591. if(target) {
  14592. targetShape = this.getCanvas().getChildShapeByResourceId(target.value);
  14593. }
  14594. var outgoing = data.findAll(function(ser){ return (ser.prefix+"-"+ser.name) == 'raziel-outgoing'});
  14595. outgoing.each((function(obj){
  14596. // TODO: Look at Canvas
  14597. if(!this.parent) {return};
  14598. // Set outgoing Shape
  14599. var next = this.getCanvas().getChildShapeByResourceId(obj.value);
  14600. if(next){
  14601. if(next == targetShape) {
  14602. // If this is an edge, set the last docker to the next shape
  14603. this.dockers.last().setDockedShape(next);
  14604. this.dockers.last().setReferencePoint({x: next.bounds.width() / 2.0, y: next.bounds.height() / 2.0});
  14605. } else if(next instanceof ORYX.Core.Edge) {
  14606. //Set the first docker of the next shape
  14607. next.dockers.first().setDockedShape(this);
  14608. //next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0});
  14609. } /*else if(next.dockers.length > 0) { //next is a node and next has a docker
  14610. next.dockers.first().setDockedShape(this);
  14611. next.dockers.first().setReferencePoint({x: this.bounds.width() / 2.0, y: this.bounds.height() / 2.0});
  14612. }*/
  14613. }
  14614. }).bind(this));
  14615. var oryxDockers = data.find(function(obj){
  14616. return (obj.prefix === "oryx" &&
  14617. obj.name === "dockers");
  14618. });
  14619. if (oryxDockers) {
  14620. var dataByPath = oryxDockers.value.split("#").without("").without(" ");
  14621. dataByPath.each((function(data, index){
  14622. var values = data.replace(/,/g, " ").split(" ").without("");
  14623. //for each docker two values must be defined
  14624. if (values.length % 2 === 0) {
  14625. var path = this._paths[index];
  14626. if (path) {
  14627. if (index === 0) {
  14628. while (this._dockersByPath[path.id].length > 2) {
  14629. this.removeDocker(this._dockersByPath[path.id][1]);
  14630. }
  14631. }
  14632. else {
  14633. while (this._dockersByPath[path.id].length > 1) {
  14634. this.removeDocker(this._dockersByPath[path.id][0]);
  14635. }
  14636. }
  14637. var dockersByPath = this._dockersByPath[path.id];
  14638. if (index === 0) {
  14639. //set position of first docker
  14640. var x = parseFloat(values.shift());
  14641. var y = parseFloat(values.shift());
  14642. if (dockersByPath.first().getDockedShape()) {
  14643. dockersByPath.first().setReferencePoint({
  14644. x: x,
  14645. y: y
  14646. });
  14647. }
  14648. else {
  14649. dockersByPath.first().bounds.centerMoveTo(x, y);
  14650. }
  14651. }
  14652. //set position of last docker
  14653. y = parseFloat(values.pop());
  14654. x = parseFloat(values.pop());
  14655. if (dockersByPath.last().getDockedShape()) {
  14656. dockersByPath.last().setReferencePoint({
  14657. x: x,
  14658. y: y
  14659. });
  14660. } else {
  14661. dockersByPath.last().bounds.centerMoveTo(x, y);
  14662. }
  14663. //add additional dockers
  14664. for (var i = 0; i < values.length; i++) {
  14665. x = parseFloat(values[i]);
  14666. y = parseFloat(values[++i]);
  14667. var newDocker = this.createDocker();
  14668. newDocker.bounds.centerMoveTo(x, y);
  14669. //this.dockers = this.dockers.without(newDocker);
  14670. //this.dockers.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker);
  14671. //dockersByPath.splice(this.dockers.indexOf(dockersByPath.last()), 0, newDocker);
  14672. }
  14673. }
  14674. }
  14675. }).bind(this));
  14676. } else {
  14677. this.alignDockers();
  14678. }
  14679. arguments.callee.$.deserialize.apply(this, arguments);
  14680. this._changed();
  14681. },
  14682. toString: function(){
  14683. return this.getStencil().title() + " " + this.id;
  14684. },
  14685. /**
  14686. * @return {ORYX.Core.Shape} Returns last docked shape or null.
  14687. */
  14688. getTarget: function(){
  14689. return this.dockers.last() ? this.dockers.last().getDockedShape() : null;
  14690. },
  14691. /**
  14692. * @return {ORYX.Core.Shape} Returns the first docked shape or null
  14693. */
  14694. getSource: function() {
  14695. return this.dockers.first() ? this.dockers.first().getDockedShape() : null;
  14696. },
  14697. /**
  14698. * Checks whether the edge is at least docked to one shape.
  14699. *
  14700. * @return {boolean} True if edge is docked
  14701. */
  14702. isDocked: function() {
  14703. var isDocked = false;
  14704. this.dockers.each(function(docker) {
  14705. if(docker.isDocked()) {
  14706. isDocked = true;
  14707. throw $break;
  14708. }
  14709. });
  14710. return isDocked;
  14711. },
  14712. /**
  14713. * Calls {@link ORYX.Core.AbstractShape#toJSON} and add a some stencil set information.
  14714. */
  14715. toJSON: function() {
  14716. var json = arguments.callee.$.toJSON.apply(this, arguments);
  14717. if(this.getTarget()) {
  14718. json.target = {
  14719. resourceId: this.getTarget().resourceId
  14720. };
  14721. }
  14722. return json;
  14723. }
  14724. };
  14725. ORYX.Core.Edge = ORYX.Core.Shape.extend(ORYX.Core.Edge);
  14726. /**
  14727. * Copyright (c) 2009
  14728. * Willi Tscheschner
  14729. *
  14730. * Permission is hereby granted, free of charge, to any person obtaining a
  14731. * copy of this software and associated documentation files (the "Software"),
  14732. * to deal in the Software without restriction, including without limitation
  14733. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  14734. * and/or sell copies of the Software, and to permit persons to whom the
  14735. * Software is furnished to do so, subject to the following conditions:
  14736. *
  14737. * The above copyright notice and this permission notice shall be included in
  14738. * all copies or substantial portions of the Software.
  14739. *
  14740. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14741. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14742. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14743. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  14744. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  14745. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  14746. * DEALINGS IN THE SOFTWARE.
  14747. **/
  14748. if(!ORYX){ var ORYX = {} }
  14749. if(!ORYX.Plugins){ ORYX.Plugins = {} }
  14750. /**
  14751. This abstract plugin class can be used to build plugins on.
  14752. It provides some more basic functionality like registering events (on*-handlers)...
  14753. @example
  14754. ORYX.Plugins.MyPlugin = ORYX.Plugins.AbstractPlugin.extend({
  14755. construct: function() {
  14756. // Call super class constructor
  14757. arguments.callee.$.construct.apply(this, arguments);
  14758. [...]
  14759. },
  14760. [...]
  14761. });
  14762. @class ORYX.Plugins.AbstractPlugin
  14763. @constructor Creates a new instance
  14764. @author Willi Tscheschner
  14765. */
  14766. ORYX.Plugins.AbstractPlugin = Clazz.extend({
  14767. /**
  14768. * The facade which offer editor-specific functionality
  14769. * @type Facade
  14770. * @memberOf ORYX.Plugins.AbstractPlugin.prototype
  14771. */
  14772. facade: null,
  14773. construct: function( facade ){
  14774. this.facade = facade;
  14775. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.onLoaded.bind(this));
  14776. },
  14777. /**
  14778. Overwrite to handle load event. TODO: Document params!!!
  14779. @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14780. */
  14781. onLoaded: function(){},
  14782. /**
  14783. Overwrite to handle selection changed event. TODO: Document params!!!
  14784. @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14785. */
  14786. onSelectionChanged: function(){},
  14787. /**
  14788. Show overlay on given shape.
  14789. @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14790. @example
  14791. showOverlay(
  14792. myShape,
  14793. { stroke: "green" },
  14794. ORYX.Editor.graft("http://www.w3.org/2000/svg", null, ['path', {
  14795. "title": "Click the element to execute it!",
  14796. "stroke-width": 2.0,
  14797. "stroke": "black",
  14798. "d": "M0,-5 L5,0 L0,5 Z",
  14799. "line-captions": "round"
  14800. }])
  14801. )
  14802. @param {Oryx.XXX.Shape[]} shapes One shape or array of shapes the overlay should be put on
  14803. @param {Oryx.XXX.Attributes} attributes some attributes...
  14804. @param {Oryx.svg.node} svgNode The svg node which should be used as overlay
  14805. @param {String} [svgNode="NW"] The svg node position where the overlay should be placed
  14806. */
  14807. showOverlay: function(shapes, attributes, svgNode, svgNodePosition ){
  14808. if( !(shapes instanceof Array) ){
  14809. shapes = [shapes]
  14810. }
  14811. // Define Shapes
  14812. shapes = shapes.map(function(shape){
  14813. var el = shape;
  14814. if( typeof shape == "string" ){
  14815. el = this.facade.getCanvas().getChildShapeByResourceId( shape );
  14816. el = el || this.facade.getCanvas().getChildById( shape, true );
  14817. }
  14818. return el;
  14819. }.bind(this)).compact();
  14820. // Define unified id
  14821. if( !this.overlayID ){
  14822. this.overlayID = this.type + ORYX.Editor.provideId();
  14823. }
  14824. this.facade.raiseEvent({
  14825. type : ORYX.CONFIG.EVENT_OVERLAY_SHOW,
  14826. id : this.overlayID,
  14827. shapes : shapes,
  14828. attributes : attributes,
  14829. node : svgNode,
  14830. nodePosition: svgNodePosition || "NW"
  14831. });
  14832. },
  14833. /**
  14834. Hide current overlay.
  14835. @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14836. */
  14837. hideOverlay: function(){
  14838. this.facade.raiseEvent({
  14839. type : ORYX.CONFIG.EVENT_OVERLAY_HIDE,
  14840. id : this.overlayID
  14841. });
  14842. },
  14843. /**
  14844. Does a transformation with the given xslt stylesheet.
  14845. @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14846. @param {String} data The data (e.g. eRDF) which should be transformed
  14847. @param {String} stylesheet URL of a stylesheet which should be used for transforming data.
  14848. */
  14849. doTransform: function( data, stylesheet ) {
  14850. if( !stylesheet || !data ){
  14851. return ""
  14852. }
  14853. var parser = new DOMParser();
  14854. var parsedData = parser.parseFromString(data, "text/xml");
  14855. source=stylesheet;
  14856. new Ajax.Request(source, {
  14857. asynchronous: false,
  14858. method: 'get',
  14859. onSuccess: function(transport){
  14860. xsl = transport.responseText
  14861. }.bind(this),
  14862. onFailure: (function(transport){
  14863. ORYX.Log.error("XSL load failed" + transport);
  14864. }).bind(this)
  14865. });
  14866. var xsltProcessor = new XSLTProcessor();
  14867. var domParser = new DOMParser();
  14868. var xslObject = domParser.parseFromString(xsl, "text/xml");
  14869. xsltProcessor.importStylesheet(xslObject);
  14870. try {
  14871. var newData = xsltProcessor.transformToFragment(parsedData, document);
  14872. var serializedData = (new XMLSerializer()).serializeToString(newData);
  14873. /* Firefox 2 to 3 problem?! */
  14874. serializedData = !serializedData.startsWith("<?xml") ? "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + serializedData : serializedData;
  14875. return serializedData;
  14876. }catch (error) {
  14877. return -1;
  14878. }
  14879. },
  14880. /**
  14881. * Opens a new window that shows the given XML content.
  14882. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14883. * @param {Object} content The XML content to be shown.
  14884. * @example
  14885. * openDownloadWindow( "my.xml", "<exampleXML />" );
  14886. */
  14887. openXMLWindow: function(content) {
  14888. var win = window.open(
  14889. 'data:application/xml,' + encodeURIComponent(
  14890. content
  14891. ),
  14892. '_blank', "resizable=yes,width=600,height=600,toolbar=0,scrollbars=yes"
  14893. );
  14894. },
  14895. /**
  14896. * Opens a download window for downloading the given content.
  14897. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14898. * @param {String} filename The content's file name
  14899. * @param {String} content The content to download
  14900. */
  14901. openDownloadWindow: function(filename, content) {
  14902. var win = window.open("");
  14903. if (win != null) {
  14904. win.document.open();
  14905. win.document.write("<html><body>");
  14906. var submitForm = win.document.createElement("form");
  14907. win.document.body.appendChild(submitForm);
  14908. var createHiddenElement = function(name, value) {
  14909. var newElement = document.createElement("input");
  14910. newElement.name=name;
  14911. newElement.type="hidden";
  14912. newElement.value = value;
  14913. return newElement
  14914. }
  14915. submitForm.appendChild( createHiddenElement("download", content) );
  14916. submitForm.appendChild( createHiddenElement("file", filename) );
  14917. submitForm.method = "POST";
  14918. win.document.write("</body></html>");
  14919. win.document.close();
  14920. submitForm.action= ORYX.PATH + "/download";
  14921. submitForm.submit();
  14922. }
  14923. },
  14924. /**
  14925. * Serializes DOM.
  14926. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14927. * @type {String} Serialized DOM
  14928. */
  14929. getSerializedDOM: function(){
  14930. // Force to set all resource IDs
  14931. var serializedDOM = DataManager.serializeDOM( this.facade );
  14932. //add namespaces
  14933. serializedDOM = '<?xml version="1.0" encoding="utf-8"?>' +
  14934. '<html xmlns="http://www.w3.org/1999/xhtml" ' +
  14935. 'xmlns:b3mn="http://b3mn.org/2007/b3mn" ' +
  14936. 'xmlns:ext="http://b3mn.org/2007/ext" ' +
  14937. 'xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" ' +
  14938. 'xmlns:atom="http://b3mn.org/2007/atom+xhtml">' +
  14939. '<head profile="http://purl.org/NET/erdf/profile">' +
  14940. '<link rel="schema.dc" href="http://purl.org/dc/elements/1.1/" />' +
  14941. '<link rel="schema.dcTerms" href="http://purl.org/dc/terms/ " />' +
  14942. '<link rel="schema.b3mn" href="http://b3mn.org" />' +
  14943. '<link rel="schema.oryx" href="http://oryx-editor.org/" />' +
  14944. '<link rel="schema.raziel" href="http://raziel.org/" />' +
  14945. '<base href="' +
  14946. location.href.split("?")[0] +
  14947. '" />' +
  14948. '</head><body>' +
  14949. serializedDOM +
  14950. '</body></html>';
  14951. return serializedDOM;
  14952. },
  14953. /**
  14954. * Sets the editor in read only mode: Edges/ dockers cannot be moved anymore,
  14955. * shapes cannot be selected anymore.
  14956. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14957. */
  14958. enableReadOnlyMode: function(){
  14959. //Edges cannot be moved anymore
  14960. this.facade.disableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN);
  14961. // Stop the user from editing the diagram while the plugin is active
  14962. this._stopSelectionChange = function(){
  14963. if(this.facade.getSelection().length > 0) {
  14964. this.facade.setSelection([]);
  14965. }
  14966. };
  14967. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this));
  14968. },
  14969. /**
  14970. * Disables read only mode, see @see
  14971. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14972. * @see ORYX.Plugins.AbstractPlugin.prototype.enableReadOnlyMode
  14973. */
  14974. disableReadOnlyMode: function(){
  14975. // Edges can be moved now again
  14976. this.facade.enableEvent(ORYX.CONFIG.EVENT_MOUSEDOWN);
  14977. if (this._stopSelectionChange) {
  14978. this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_SELECTION_CHANGED, this._stopSelectionChange.bind(this));
  14979. this._stopSelectionChange = undefined;
  14980. }
  14981. },
  14982. /**
  14983. * Extracts RDF from DOM.
  14984. * @methodOf ORYX.Plugins.AbstractPlugin.prototype
  14985. * @type {String} Extracted RFD. Null if there are transformation errors.
  14986. */
  14987. getRDFFromDOM: function(){
  14988. //convert to RDF
  14989. try {
  14990. var xsl = "";
  14991. source=ORYX.PATH + "lib/extract-rdf.xsl";
  14992. new Ajax.Request(source, {
  14993. asynchronous: false,
  14994. method: 'get',
  14995. onSuccess: function(transport){
  14996. xsl = transport.responseText
  14997. }.bind(this),
  14998. onFailure: (function(transport){
  14999. ORYX.Log.error("XSL load failed" + transport);
  15000. }).bind(this)
  15001. });
  15002. /*
  15003. var parser = new DOMParser();
  15004. var parsedDOM = parser.parseFromString(this.getSerializedDOM(), "text/xml");
  15005. var xsltPath = ORYX.PATH + "lib/extract-rdf.xsl";
  15006. var xsltProcessor = new XSLTProcessor();
  15007. var xslRef = document.implementation.createDocument("", "", null);
  15008. xslRef.async = false;
  15009. xslRef.load(xsltPath);
  15010. xsltProcessor.importStylesheet(xslRef);
  15011. try {
  15012. var rdf = xsltProcessor.transformToDocument(parsedDOM);
  15013. return (new XMLSerializer()).serializeToString(rdf);
  15014. } catch (error) {
  15015. Ext.Msg.alert("Oryx", error);
  15016. return null;
  15017. }*/
  15018. var domParser = new DOMParser();
  15019. var xmlObject = domParser.parseFromString(this.getSerializedDOM(), "text/xml");
  15020. var xslObject = domParser.parseFromString(xsl, "text/xml");
  15021. var xsltProcessor = new XSLTProcessor();
  15022. xsltProcessor.importStylesheet(xslObject);
  15023. var result = xsltProcessor.transformToFragment(xmlObject, document);
  15024. var serializer = new XMLSerializer();
  15025. return serializer.serializeToString(result);
  15026. }catch(e){
  15027. Ext.Msg.alert("Oryx", error);
  15028. return "";
  15029. }
  15030. },
  15031. /**
  15032. * Checks if a certain stencil set is loaded right now.
  15033. *
  15034. */
  15035. isStencilSetExtensionLoaded: function(stencilSetExtensionNamespace) {
  15036. return this.facade.getStencilSets().values().any(
  15037. function(ss){
  15038. return ss.extensions().keys().any(
  15039. function(extensionKey) {
  15040. return extensionKey == stencilSetExtensionNamespace;
  15041. }.bind(this)
  15042. );
  15043. }.bind(this)
  15044. );
  15045. },
  15046. /**
  15047. * Raises an event so that registered layouters does
  15048. * have the posiblility to layout the given shapes
  15049. * For further reading, have a look into the AbstractLayouter
  15050. * class
  15051. * @param {Object} shapes
  15052. */
  15053. doLayout: function(shapes){
  15054. // Raises a do layout event
  15055. this.facade.raiseEvent({
  15056. type : ORYX.CONFIG.EVENT_LAYOUT,
  15057. shapes : shapes
  15058. });
  15059. },
  15060. /**
  15061. * Does a primitive layouting with the incoming/outgoing
  15062. * edges (set the dockers to the right position) and if
  15063. * necessary, it will be called the real layouting
  15064. * @param {ORYX.Core.Node} node
  15065. * @param {Array} edges
  15066. */
  15067. layoutEdges : function(node, allEdges, offset){
  15068. if (!this.facade.isExecutingCommands()){ return }
  15069. var Command = ORYX.Core.Command.extend({
  15070. construct: function(edges, node, offset, plugin){
  15071. this.edges = edges;
  15072. this.node = node;
  15073. this.plugin = plugin;
  15074. this.offset = offset;
  15075. // Get the new absolute center
  15076. var center = node.absoluteXY();
  15077. this.ulo = {x: center.x - offset.x, y:center.y - offset.y};
  15078. },
  15079. execute: function(){
  15080. if (this.changes){
  15081. this.executeAgain();
  15082. return;
  15083. } else {
  15084. this.changes = [];
  15085. this.edges.each(function(edge){
  15086. this.changes.push({
  15087. edge: edge,
  15088. oldDockerPositions: edge.dockers.map(function(r){ return r.bounds.center() })
  15089. })
  15090. }.bind(this));
  15091. }
  15092. // Find all edges, which are related to the node and
  15093. // have more than two dockers
  15094. this.edges
  15095. // Find all edges with more than two dockers
  15096. .findAll(function(r){ return r.dockers.length > 2 }.bind(this))
  15097. // For every edge, check second and one before last docker
  15098. // if there are horizontal/vertical on the same level
  15099. // and if so, align the the bounds
  15100. .each(function(edge){
  15101. if (edge.dockers.first().getDockedShape() === this.node){
  15102. var second = edge.dockers[1];
  15103. if (this.align(second.bounds, edge.dockers.first())){ second.update(); }
  15104. } else if (edge.dockers.last().getDockedShape() === this.node) {
  15105. var beforeLast = edge.dockers[edge.dockers.length-2];
  15106. if (this.align(beforeLast.bounds, edge.dockers.last())){ beforeLast.update(); }
  15107. }
  15108. edge._update(true);
  15109. edge.removeUnusedDockers();
  15110. if (this.isBendPointIncluded(edge)){
  15111. this.plugin.doLayout(edge);
  15112. return;
  15113. }
  15114. }.bind(this));
  15115. // Find all edges, which have only to dockers
  15116. // and is located horizontal/vertical.
  15117. // Do layout with those edges
  15118. this.edges
  15119. // Find all edges with exactly two dockers
  15120. .each(function(edge){
  15121. if (edge.dockers.length == 2){
  15122. var p1 = edge.dockers.first().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center();
  15123. var p2 = edge.dockers.last().getAbsoluteReferencePoint() || edge.dockers.first().bounds.center();
  15124. // Find all horizontal/vertical edges
  15125. if (Math.abs(-Math.abs(p1.x - p2.x) + Math.abs(this.offset.x)) < 2 || Math.abs(-Math.abs(p1.y - p2.y) + Math.abs(this.offset.y)) < 2){
  15126. this.plugin.doLayout(edge);
  15127. }
  15128. }
  15129. }.bind(this));
  15130. this.edges.each(function(edge, i){
  15131. this.changes[i].dockerPositions = edge.dockers.map(function(r){ return r.bounds.center() });
  15132. }.bind(this));
  15133. },
  15134. /**
  15135. * Align the bounds if the center is
  15136. * the same than the old center
  15137. * @params {Object} bounds
  15138. * @params {Object} bounds2
  15139. */
  15140. align: function(bounds, refDocker){
  15141. var abRef = refDocker.getAbsoluteReferencePoint() || refDocker.bounds.center();
  15142. var xdif = bounds.center().x-abRef.x;
  15143. var ydif = bounds.center().y-abRef.y;
  15144. if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3 && this.offset.xs === undefined){
  15145. bounds.moveBy({x:-xdif, y:0})
  15146. }
  15147. if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3 && this.offset.ys === undefined){
  15148. bounds.moveBy({y:-ydif, x:0})
  15149. }
  15150. if (this.offset.xs !== undefined || this.offset.ys !== undefined){
  15151. var absPXY = refDocker.getDockedShape().absoluteXY();
  15152. xdif = bounds.center().x-(absPXY.x+((abRef.x-absPXY.x)/this.offset.xs));
  15153. ydif = bounds.center().y-(absPXY.y+((abRef.y-absPXY.y)/this.offset.ys));
  15154. if (Math.abs(-Math.abs(xdif) + Math.abs(this.offset.x)) < 3){
  15155. bounds.moveBy({x:-(bounds.center().x-abRef.x), y:0})
  15156. }
  15157. if (Math.abs(-Math.abs(ydif) + Math.abs(this.offset.y)) < 3){
  15158. bounds.moveBy({y:-(bounds.center().y-abRef.y), x:0})
  15159. }
  15160. }
  15161. },
  15162. /**
  15163. * Returns a TRUE if there are bend point which overlay the shape
  15164. */
  15165. isBendPointIncluded: function(edge){
  15166. // Get absolute bounds
  15167. var ab = edge.dockers.first().getDockedShape();
  15168. var bb = edge.dockers.last().getDockedShape();
  15169. if (ab) {
  15170. ab = ab.absoluteBounds();
  15171. ab.widen(5);
  15172. }
  15173. if (bb) {
  15174. bb = bb.absoluteBounds();
  15175. bb.widen(20); // Wide with 20 because of the arrow from the edge
  15176. }
  15177. return edge.dockers
  15178. .any(function(docker, i){
  15179. var c = docker.bounds.center();
  15180. // Dont count first and last
  15181. return i != 0 && i != edge.dockers.length-1 &&
  15182. // Check if the point is included to the absolute bounds
  15183. ((ab && ab.isIncluded(c)) || (bb && bb.isIncluded(c)))
  15184. })
  15185. },
  15186. removeAllDocker: function(edge){
  15187. edge.dockers.slice(1, edge.dockers.length-1).each(function(docker){
  15188. edge.removeDocker(docker);
  15189. })
  15190. },
  15191. executeAgain: function(){
  15192. this.changes.each(function(change){
  15193. // Reset the dockers
  15194. this.removeAllDocker(change.edge);
  15195. change.dockerPositions.each(function(pos, i){
  15196. if (i==0||i==change.dockerPositions.length-1){ return }
  15197. var docker = change.edge.createDocker(undefined, pos);
  15198. docker.bounds.centerMoveTo(pos);
  15199. docker.update();
  15200. }.bind(this));
  15201. change.edge._update(true);
  15202. }.bind(this));
  15203. },
  15204. rollback: function(){
  15205. this.changes.each(function(change){
  15206. // Reset the dockers
  15207. this.removeAllDocker(change.edge);
  15208. change.oldDockerPositions.each(function(pos, i){
  15209. if (i==0||i==change.oldDockerPositions.length-1){ return }
  15210. var docker = change.edge.createDocker(undefined, pos);
  15211. docker.bounds.centerMoveTo(pos);
  15212. docker.update();
  15213. }.bind(this));
  15214. change.edge._update(true);
  15215. }.bind(this));
  15216. }
  15217. });
  15218. this.facade.executeCommands([new Command(allEdges, node, offset, this)]);
  15219. }
  15220. });/**
  15221. * Copyright (c) 2009
  15222. * Willi Tscheschner
  15223. *
  15224. * Permission is hereby granted, free of charge, to any person obtaining a
  15225. * copy of this software and associated documentation files (the "Software"),
  15226. * to deal in the Software without restriction, including without limitation
  15227. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15228. * and/or sell copies of the Software, and to permit persons to whom the
  15229. * Software is furnished to do so, subject to the following conditions:
  15230. *
  15231. * The above copyright notice and this permission notice shall be included in
  15232. * all copies or substantial portions of the Software.
  15233. *
  15234. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15235. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15236. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15237. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15238. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  15239. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  15240. * DEALINGS IN THE SOFTWARE.
  15241. **/
  15242. if(!ORYX){ var ORYX = {} }
  15243. if(!ORYX.Plugins){ ORYX.Plugins = {} }
  15244. /**
  15245. This abstract plugin implements the core behaviour of layout
  15246. @class ORYX.Plugins.AbstractLayouter
  15247. @constructor Creates a new instance
  15248. @author Willi Tscheschner
  15249. */
  15250. ORYX.Plugins.AbstractLayouter = ORYX.Plugins.AbstractPlugin.extend({
  15251. /**
  15252. * 'layouted' defined all types of shapes which will be layouted.
  15253. * It can be one value or an array of values. The value
  15254. * can be a Stencil ID (as String) or an class type of either
  15255. * a ORYX.Core.Node or ORYX.Core.Edge
  15256. * @type Array|String|Object
  15257. * @memberOf ORYX.Plugins.AbstractLayouter.prototype
  15258. */
  15259. layouted : [],
  15260. /**
  15261. * Constructor
  15262. * @param {Object} facade
  15263. * @memberOf ORYX.Plugins.AbstractLayouter.prototype
  15264. */
  15265. construct: function( facade ){
  15266. arguments.callee.$.construct.apply(this, arguments);
  15267. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LAYOUT, this._initLayout.bind(this));
  15268. },
  15269. /**
  15270. * Proofs if this shape should be layouted or not
  15271. * @param {Object} shape
  15272. * @memberOf ORYX.Plugins.AbstractLayouter.prototype
  15273. */
  15274. isIncludedInLayout: function(shape){
  15275. if (!(this.layouted instanceof Array)){
  15276. this.layouted = [this.layouted].compact();
  15277. }
  15278. // If there are no elements
  15279. if (this.layouted.length <= 0) {
  15280. // Return TRUE
  15281. return true;
  15282. }
  15283. // Return TRUE if there is any correlation between
  15284. // the 'layouted' attribute and the shape themselve.
  15285. return this.layouted.any(function(s){
  15286. if (typeof s == "string") {
  15287. return shape.getStencil().id().include(s);
  15288. } else {
  15289. return shape instanceof s;
  15290. }
  15291. })
  15292. },
  15293. /**
  15294. * Callback to start the layouting
  15295. * @param {Object} event Layout event
  15296. * @param {Object} shapes Given shapes
  15297. * @memberOf ORYX.Plugins.AbstractLayouter.prototype
  15298. */
  15299. _initLayout: function(event){
  15300. // Get the shapes
  15301. var shapes = [event.shapes].flatten().compact();
  15302. // Find all shapes which should be layouted
  15303. var toLayout = shapes.findAll(function(shape){
  15304. return this.isIncludedInLayout(shape)
  15305. }.bind(this))
  15306. // If there are shapes left
  15307. if (toLayout.length > 0){
  15308. // Do layout
  15309. this.layout(toLayout);
  15310. }
  15311. },
  15312. /**
  15313. * Implementation of layouting a set on shapes
  15314. * @param {Object} shapes Given shapes
  15315. * @memberOf ORYX.Plugins.AbstractLayouter.prototype
  15316. */
  15317. layout: function(shapes){
  15318. throw new Error("Layouter has to implement the layout function.")
  15319. }
  15320. });ImageViewer = Ext.extend(Ext.Window, {
  15321. initComponent: function() {
  15322. this.bodyCfg = {
  15323. tag: 'img',
  15324. src: this.src,
  15325. autoscroll: true,
  15326. fixedcenter : true
  15327. };
  15328. ImageViewer.superclass.initComponent.apply(this, arguments);
  15329. },
  15330. onRender: function() {
  15331. ImageViewer.superclass.onRender.apply(this, arguments);
  15332. this.body.on('load', this.onImageLoad, this, {single: true});
  15333. },
  15334. onImageLoad: function() {
  15335. // var h = this.getFrameHeight(),
  15336. // w = this.getFrameWidth();
  15337. // this.setSize(this.body.dom.offsetWidth + w, this.body.dom.offsetHeight + h);
  15338. },
  15339. setSrc: function(src) {
  15340. this.body.on('load', this.onImageLoad, this, {single: true});
  15341. //this.body.dom.style.width = this.body.dom.style.width = 'auto';
  15342. this.body.dom.src = src;
  15343. },
  15344. initEvents: function() {
  15345. ImageViewer.superclass.initEvents.apply(this, arguments);
  15346. if (this.resizer) {
  15347. this.resizer.preserveRatio = true;
  15348. }
  15349. }
  15350. });if(!Signavio){ var Signavio = {} };
  15351. if (!Signavio.Core) { Signavio.Core = {} };
  15352. Signavio.Core.Version = "1.0";
  15353. /**
  15354. * Copyright (c) 2009
  15355. *
  15356. * Willi Tscheschner
  15357. *
  15358. * Permission is hereby granted, free of charge, to any person obtaining a
  15359. * copy of this software and associated documentation files (the "Software"),
  15360. * to deal in the Software without restriction, including without limitation
  15361. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15362. * and/or sell copies of the Software, and to permit persons to whom the
  15363. * Software is furnished to do so, subject to the following conditions:
  15364. *
  15365. * The above copyright notice and this permission notice shall be included in
  15366. * all copies or substantial portions of the Software.
  15367. *
  15368. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15369. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15370. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15371. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15372. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  15373. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  15374. * DEALINGS IN THE SOFTWARE.
  15375. **/
  15376. if (!Signavio) {
  15377. var Signavio = new Object();
  15378. }
  15379. if (!Signavio.Plugins) {
  15380. Signavio.Plugins = new Object();
  15381. }
  15382. if (!Signavio.Plugins.Utils) {
  15383. Signavio.Plugins.Utils = new Object();
  15384. }
  15385. if (!Signavio.Helper) {
  15386. Signavio.Helper = new Object();
  15387. }
  15388. new function(){
  15389. var mask;
  15390. Signavio.Plugins.Utils.getFFVersion = function(){
  15391. try {
  15392. return Number(window.navigator.userAgent.match("Firefox.([0-9]+[\.][0-9]+)")[1]) || 0 ;
  15393. } catch(e){
  15394. return 0;
  15395. }
  15396. }
  15397. /**
  15398. * Shows an overlay of signavio
  15399. */
  15400. Signavio.Helper.ShowMask = function(force, parent){
  15401. if (!force && ORYX.CONFIG.PREVENT_LOADINGMASK_AT_READY === true){
  15402. return;
  15403. }
  15404. if (mask){
  15405. return;
  15406. }
  15407. var s = "background:white;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%;z-index:100000;"
  15408. var ss = "left:50%;margin-left:-200px;margin-top:-90px;position:absolute;top:50%;display:none;width:391px;"
  15409. var sversion = "color:#ad0f5b;padding-right:10px;font-family:tahoma,arial,san-serif;font-size:12px;";
  15410. var stext = "display:block;position:relative;text-align:right;top:0;width:100%;";
  15411. var stitle = "color:#ad0f5b;font-weight:bold;padding-right:10px;font-family:tahoma,arial,san-serif;font-size:12px;"
  15412. var sloading = "height:16px;width:16px;margin-bottom:-4px;background: transparent url(../libs/ext-2.0.2/resources/images/default/tree/loading.gif) no-repeat center;"
  15413. var simg = "padding-bottom:10px;border-bottom:1px solid #ad0f5b;";
  15414. // Define the parent
  15415. parent = (parent ? Ext.get(parent) : null) || Ext.getBody();
  15416. if (parent !== Ext.getBody()){
  15417. parent.setStyle("position", "relative")
  15418. }
  15419. mask = Ext.get(document.createElement("div"));
  15420. parent.appendChild(mask);
  15421. mask.dom.setAttribute("style", s);
  15422. mask.dom.innerHTML = "<div class='mask-logo' style='"+ss+"'>"+
  15423. "<div>"+
  15424. "<img style='"+simg+"' src='"+ORYX.CONFIG.EXPLORER_PATH+"/src/img/signavio/smoky/logo.png' />"+
  15425. "</div>"+
  15426. "<span class='mask-text' style='"+stext+"'>"+
  15427. "<span class='mask-title' style='"+stitle+"'>Editor</span>"+
  15428. "<span class='mask-version' style='"+sversion+"'>Version "+Signavio.Core.Version+"</span>"+
  15429. "<img style='"+sloading+"' src='"+(ORYX.CONFIG.BLANK_IMAGE||Ext.BLANK_IMAGE_URL)+"'/>"+
  15430. "</span>" +
  15431. "</div>";
  15432. mask.first().show({duration:0.3});
  15433. }
  15434. // When body is loaded, show overlay
  15435. Ext.onReady(Signavio.Helper.ShowMask);
  15436. /**
  15437. * Hides the overlay
  15438. */
  15439. Signavio.Helper.HideMask = function(){
  15440. window.setTimeout(function(){
  15441. if (mask){
  15442. mask.first().hide({duration:0.4, remove:true, block:true});
  15443. mask.hide({duration:0.3, remove:true, block :true});
  15444. delete mask;
  15445. }
  15446. }.bind(this), 2000)
  15447. }
  15448. Signavio.Plugins.Loading = {
  15449. facade: undefined,
  15450. construct: function(facade) {
  15451. this.facade = facade;
  15452. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, Signavio.Helper.HideMask);
  15453. /**
  15454. * Overwrite the toJSON method in the Canvas
  15455. * to set the correct stencilset namespace.
  15456. *
  15457. */
  15458. /*(var me = this;
  15459. new function(){
  15460. // Copy prototype method
  15461. var toJSON = ORYX.Core.Canvas.prototype.toJSON;
  15462. ORYX.Core.Canvas.prototype.toJSON = function(){
  15463. // Call super
  15464. var json = toJSON.call(this);
  15465. // Check for replace stencil set namespace
  15466. json.stencilset.namespace = me.facade.getModelMetaData().model.stencilset.namespace;
  15467. return json;
  15468. }
  15469. }()*/
  15470. }
  15471. }
  15472. Signavio.Plugins.Loading = Clazz.extend(Signavio.Plugins.Loading);
  15473. /**
  15474. * Provides an uniq id
  15475. * @overwrite
  15476. * @return {String}
  15477. *
  15478. */
  15479. ORYX.Editor.provideId = function() {
  15480. var res = [], hex = '0123456789ABCDEF';
  15481. for (var i = 0; i < 36; i++) res[i] = Math.floor(Math.random()*0x10);
  15482. res[14] = 4;
  15483. res[19] = (res[19] & 0x3) | 0x8;
  15484. for (var i = 0; i < 36; i++) res[i] = hex[res[i]];
  15485. res[8] = res[13] = res[18] = res[23] = '-';
  15486. return "sid-" + res.join('');
  15487. };
  15488. }();
  15489. /**
  15490. * Ext specific extension
  15491. *
  15492. *
  15493. *
  15494. */
  15495. new function(){
  15496. /**
  15497. * Implementation of an Ext-LinkButton
  15498. *
  15499. *
  15500. */
  15501. Ext.LinkButton = Ext.extend(Ext.BoxComponent, {
  15502. // On Click Handler
  15503. click: null,
  15504. // Image url
  15505. image: null,
  15506. // Image style (only if an image url is setted)
  15507. imageStyle: null,
  15508. toggle:false,
  15509. toggleStyle:null,
  15510. selected:false,
  15511. href:false,
  15512. el: null,
  15513. // private
  15514. onRender : function(ct, position){
  15515. if( this.el == null ){
  15516. this.el = document.createElement('a');
  15517. if (this.tabIndex)
  15518. this.el.setAttribute("tabindex", this.tabIndex)
  15519. this.el.id = this.getId();
  15520. this.el.className = this.cls||"x-link-button";
  15521. if( !this.disabled )
  15522. this.el.href = this.href ? this.href : "#" + this.text;
  15523. if( !this.disabled ){
  15524. Element.observe( this.el, 'click', this.onClick.bind(this));
  15525. }
  15526. if( this.image ){
  15527. this.el.innerHTML = '<img src="' + this.image + '" title="' + this.text + '"' + ( this.imageStyle ? ' style="' + this.imageStyle + '"/>': '/>')
  15528. } else {
  15529. this.el.innerHTML = this.text ? Ext.util.Format.htmlEncode(this.text) : (this.html || '');
  15530. }
  15531. if(this.forId){
  15532. this.el.setAttribute('htmlFor', this.forId);
  15533. }
  15534. }
  15535. Ext.LinkButton.superclass.onRender.call(this, ct, position);
  15536. },
  15537. onClick: function(e){
  15538. if( this.disabled ){ Event.stop(e); return; }
  15539. // Toggle the button
  15540. if( this.toggle ){
  15541. this.selected = !this.selected;
  15542. if( this.toggleStyle ){
  15543. this._setStyle( this.el.dom, '')
  15544. this.el.dom.setAttribute('style','')
  15545. if( this.selected ){
  15546. this.el.applyStyles( this.toggleStyle )
  15547. } else {
  15548. this.el.applyStyles( this.initialConfig.style )
  15549. }
  15550. }
  15551. }
  15552. if( this.click instanceof Function )
  15553. this.click.apply(this.click, [this, e]);
  15554. Event.stop(e)
  15555. },
  15556. setText: function(t, encode){
  15557. this.text = t;
  15558. if(this.rendered){
  15559. this.el.dom.innerHTML = encode !== false ? Ext.util.Format.htmlEncode(t) : t;
  15560. }
  15561. return this;
  15562. },
  15563. _setStyle: function(node, style){
  15564. if( Ext.isIE ){
  15565. node.style.setAttribute('cssText', style );
  15566. } else {
  15567. node.setAttribute('style', style );
  15568. }
  15569. }
  15570. });
  15571. Ext.reg('linkbutton', Ext.LinkButton);
  15572. }();
  15573. /**
  15574. * Helper Methods
  15575. *
  15576. */
  15577. new function(){
  15578. Signavio.Helper.RecordReader = function(meta){
  15579. meta = meta || {};
  15580. this.rels = meta.rels || this.rels;
  15581. Signavio.Helper.RecordReader.superclass.constructor.call(this, meta, ['rep','href','rel']);
  15582. };
  15583. Ext.extend(Signavio.Helper.RecordReader, Ext.data.JsonReader, {
  15584. rels: ["gitem"],
  15585. read : function(response){
  15586. var json = response.responseText;
  15587. var o = eval("("+json+")");
  15588. if(!o) {
  15589. throw {message: "JsonReader.read: Json object not found"};
  15590. }
  15591. var Record = this.recordType;
  15592. var records = [], total = 0;
  15593. o.each(function(rec){
  15594. if (this.rels.include(rec.rel)) {
  15595. records.push(new Record(rec));
  15596. }
  15597. if (rec.rel == "info" && rec.rep.size){
  15598. total = rec.rep.size;
  15599. }
  15600. }.bind(this))
  15601. return {
  15602. success : true,
  15603. records : records,
  15604. totalRecords : total || records.length
  15605. }
  15606. }
  15607. })
  15608. /**
  15609. * Creates a new record, including 'rel', 'href', and 'rep' attributes
  15610. * @param {String} rel
  15611. * @param {String} href
  15612. * @param {Object} rep
  15613. */
  15614. Signavio.Helper.createRecord = function(rel, href, rep){
  15615. var Rec = Ext.data.Record.create(["rel", "href", "rep"]);
  15616. var record = new Rec({
  15617. rel : rel,
  15618. href: href,
  15619. rep : rep
  15620. });
  15621. return record;
  15622. }
  15623. }()
  15624. /**
  15625. * Copyright (c) 2006
  15626. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  15627. *
  15628. * Permission is hereby granted, free of charge, to any person obtaining a
  15629. * copy of this software and associated documentation files (the "Software"),
  15630. * to deal in the Software without restriction, including without limitation
  15631. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15632. * and/or sell copies of the Software, and to permit persons to whom the
  15633. * Software is furnished to do so, subject to the following conditions:
  15634. *
  15635. * The above copyright notice and this permission notice shall be included in
  15636. * all copies or substantial portions of the Software.
  15637. *
  15638. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15639. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15640. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15641. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15642. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  15643. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  15644. * DEALINGS IN THE SOFTWARE.
  15645. **/
  15646. if(!ORYX.Plugins) {
  15647. ORYX.Plugins = new Object();
  15648. }
  15649. ORYX.Plugins.Toolbar = Clazz.extend({
  15650. facade: undefined,
  15651. plugs: [],
  15652. construct: function(facade, ownPluginData) {
  15653. this.facade = facade;
  15654. this.groupIndex = new Hash();
  15655. ownPluginData.properties.each((function(value){
  15656. if(value.group && value.index != undefined) {
  15657. this.groupIndex[value.group] = value.index
  15658. }
  15659. }).bind(this));
  15660. Ext.QuickTips.init();
  15661. this.buttons = [];
  15662. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_BUTTON_UPDATE, this.onButtonUpdate.bind(this));
  15663. },
  15664. /**
  15665. * Can be used to manipulate the state of a button.
  15666. * @example
  15667. * this.facade.raiseEvent({
  15668. * type: ORYX.CONFIG.EVENT_BUTTON_UPDATE,
  15669. * id: this.buttonId, // have to be generated before and set in the offer method
  15670. * pressed: true
  15671. * });
  15672. * @param {Object} event
  15673. */
  15674. onButtonUpdate: function(event){
  15675. var button = this.buttons.find(function(button){
  15676. return button.id === event.id;
  15677. });
  15678. if(event.pressed !== undefined){
  15679. button.buttonInstance.toggle(event.pressed);
  15680. }
  15681. },
  15682. registryChanged: function(pluginsData) {
  15683. // Sort plugins by group and index
  15684. var newPlugs = pluginsData.sortBy((function(value) {
  15685. return ((this.groupIndex[value.group] != undefined ? this.groupIndex[value.group] : "" ) + value.group + "" + value.index).toLowerCase();
  15686. }).bind(this));
  15687. var plugs = $A(newPlugs).findAll(function(value){
  15688. return !this.plugs.include(value) && (!value.target || value.target === ORYX.Plugins.Toolbar)
  15689. }.bind(this));
  15690. if(plugs.length<1)
  15691. return;
  15692. this.buttons = [];
  15693. ORYX.Log.trace("Creating a toolbar.")
  15694. if(!this.toolbar){
  15695. this.toolbar = new Ext.ux.SlicedToolbar({
  15696. height: 24
  15697. });
  15698. var region = this.facade.addToRegion("north", this.toolbar, "Toolbar");
  15699. }
  15700. var currentGroupsName = this.plugs.last()?this.plugs.last().group:plugs[0].group;
  15701. // Map used to store all drop down buttons of current group
  15702. var currentGroupsDropDownButton = {};
  15703. plugs.each((function(value) {
  15704. if(!value.name) {return}
  15705. this.plugs.push(value);
  15706. // Add seperator if new group begins
  15707. if(currentGroupsName != value.group) {
  15708. this.toolbar.add('-');
  15709. currentGroupsName = value.group;
  15710. currentGroupsDropDownButton = {};
  15711. }
  15712. // If an drop down group icon is provided, a split button should be used
  15713. if(value.dropDownGroupIcon){
  15714. var splitButton = currentGroupsDropDownButton[value.dropDownGroupIcon];
  15715. // Create a new split button if this is the first plugin using it
  15716. if(splitButton === undefined){
  15717. splitButton = currentGroupsDropDownButton[value.dropDownGroupIcon] = new Ext.Toolbar.SplitButton({
  15718. cls: "x-btn-icon", //show icon only
  15719. icon: value.dropDownGroupIcon,
  15720. menu: new Ext.menu.Menu({
  15721. items: [] // items are added later on
  15722. }),
  15723. listeners: {
  15724. click: function(button, event){
  15725. // The "normal" button should behave like the arrow button
  15726. if(!button.menu.isVisible() && !button.ignoreNextClick){
  15727. button.showMenu();
  15728. } else {
  15729. button.hideMenu();
  15730. }
  15731. }
  15732. }
  15733. });
  15734. this.toolbar.add(splitButton);
  15735. }
  15736. // General config button which will be used either to create a normal button
  15737. // or a check button (if toggling is enabled)
  15738. var buttonCfg = {
  15739. icon: value.icon,
  15740. text: value.name,
  15741. itemId: value.id,
  15742. handler: value.toggle ? undefined : value.functionality,
  15743. checkHandler: value.toggle ? value.functionality : undefined,
  15744. listeners: {
  15745. render: function(item){
  15746. // After rendering, a tool tip should be added to component
  15747. if (value.description) {
  15748. new Ext.ToolTip({
  15749. target: item.getEl(),
  15750. title: value.description
  15751. })
  15752. }
  15753. }
  15754. }
  15755. }
  15756. // Create buttons depending on toggle
  15757. if(value.toggle) {
  15758. var button = new Ext.menu.CheckItem(buttonCfg);
  15759. } else {
  15760. var button = new Ext.menu.Item(buttonCfg);
  15761. }
  15762. splitButton.menu.add(button);
  15763. } else if(value.addFill) {
  15764. this.toolbar.addFill();
  15765. } else { // create normal, simple button
  15766. var button = new Ext.Toolbar.Button({
  15767. icon: value.icon, // icons can also be specified inline
  15768. cls: 'x-btn-icon', // Class who shows only the icon
  15769. itemId: value.id,
  15770. tooltip: value.description, // Set the tooltip
  15771. tooltipType: 'title', // Tooltip will be shown as in the html-title attribute
  15772. handler: value.toggle ? null : value.functionality, // Handler for mouse click
  15773. enableToggle: value.toggle, // Option for enabling toggling
  15774. toggleHandler: value.toggle ? value.functionality : null // Handler for toggle (Parameters: button, active)
  15775. });
  15776. this.toolbar.add(button);
  15777. button.getEl().onclick = function() {this.blur()}
  15778. }
  15779. value['buttonInstance'] = button;
  15780. this.buttons.push(value);
  15781. }).bind(this));
  15782. this.enableButtons([]);
  15783. //TODO this should be done when resizing and adding elements!!!!
  15784. this.toolbar.calcSlices();
  15785. window.addEventListener("resize", function(event){this.toolbar.calcSlices()}.bind(this), false);
  15786. window.addEventListener("onresize", function(event){this.toolbar.calcSlices()}.bind(this), false);
  15787. },
  15788. onSelectionChanged: function(event) {
  15789. this.enableButtons(event.elements);
  15790. },
  15791. enableButtons: function(elements) {
  15792. // Show the Buttons
  15793. this.buttons.each((function(value){
  15794. value.buttonInstance.enable();
  15795. // If there is less elements than minShapes
  15796. if(value.minShape && value.minShape > elements.length)
  15797. value.buttonInstance.disable();
  15798. // If there is more elements than minShapes
  15799. if(value.maxShape && value.maxShape < elements.length)
  15800. value.buttonInstance.disable();
  15801. // If the plugin is not enabled
  15802. if(value.isEnabled && !value.isEnabled(value.buttonInstance))
  15803. value.buttonInstance.disable();
  15804. }).bind(this));
  15805. }
  15806. });
  15807. Ext.ns("Ext.ux");
  15808. Ext.ux.SlicedToolbar = Ext.extend(Ext.Toolbar, {
  15809. currentSlice: 0,
  15810. iconStandardWidth: 22, //22 px
  15811. seperatorStandardWidth: 2, //2px, minwidth for Ext.Toolbar.Fill
  15812. toolbarStandardPadding: 2,
  15813. initComponent: function(){
  15814. Ext.apply(this, {
  15815. });
  15816. Ext.ux.SlicedToolbar.superclass.initComponent.apply(this, arguments);
  15817. },
  15818. onRender: function(){
  15819. Ext.ux.SlicedToolbar.superclass.onRender.apply(this, arguments);
  15820. },
  15821. onResize: function(){
  15822. Ext.ux.SlicedToolbar.superclass.onResize.apply(this, arguments);
  15823. },
  15824. calcSlices: function(){
  15825. var slice = 0;
  15826. this.sliceMap = {};
  15827. var sliceWidth = 0;
  15828. var toolbarWidth = this.getEl().getWidth();
  15829. this.items.getRange().each(function(item, index){
  15830. //Remove all next and prev buttons
  15831. if (item.helperItem) {
  15832. item.destroy();
  15833. return;
  15834. }
  15835. var itemWidth = item.getEl().getWidth();
  15836. if(sliceWidth + itemWidth + 5 * this.iconStandardWidth > toolbarWidth){
  15837. var itemIndex = this.items.indexOf(item);
  15838. this.insertSlicingButton("next", slice, itemIndex);
  15839. if (slice !== 0) {
  15840. this.insertSlicingButton("prev", slice, itemIndex);
  15841. }
  15842. this.insertSlicingSeperator(slice, itemIndex);
  15843. slice += 1;
  15844. sliceWidth = 0;
  15845. }
  15846. this.sliceMap[item.id] = slice;
  15847. sliceWidth += itemWidth;
  15848. }.bind(this));
  15849. // Add prev button at the end
  15850. if(slice > 0){
  15851. this.insertSlicingSeperator(slice, this.items.getCount()+1);
  15852. this.insertSlicingButton("prev", slice, this.items.getCount()+1);
  15853. var spacer = new Ext.Toolbar.Spacer();
  15854. this.insertSlicedHelperButton(spacer, slice, this.items.getCount()+1);
  15855. Ext.get(spacer.id).setWidth(this.iconStandardWidth);
  15856. }
  15857. this.maxSlice = slice;
  15858. // Update view
  15859. this.setCurrentSlice(this.currentSlice);
  15860. },
  15861. insertSlicedButton: function(button, slice, index){
  15862. this.insertButton(index, button);
  15863. this.sliceMap[button.id] = slice;
  15864. },
  15865. insertSlicedHelperButton: function(button, slice, index){
  15866. button.helperItem = true;
  15867. this.insertSlicedButton(button, slice, index);
  15868. },
  15869. insertSlicingSeperator: function(slice, index){
  15870. // Align right
  15871. this.insertSlicedHelperButton(new Ext.Toolbar.Fill(), slice, index);
  15872. },
  15873. // type => next or prev
  15874. insertSlicingButton: function(type, slice, index){
  15875. var nextHandler = function(){this.setCurrentSlice(this.currentSlice+1)}.bind(this);
  15876. var prevHandler = function(){this.setCurrentSlice(this.currentSlice-1)}.bind(this);
  15877. var button = new Ext.Toolbar.Button({
  15878. cls: "x-btn-icon",
  15879. icon: ORYX.CONFIG.ROOT_PATH + "images/toolbar_"+type+".png",
  15880. handler: (type === "next") ? nextHandler : prevHandler
  15881. });
  15882. this.insertSlicedHelperButton(button, slice, index);
  15883. },
  15884. setCurrentSlice: function(slice){
  15885. if(slice > this.maxSlice || slice < 0) return;
  15886. this.currentSlice = slice;
  15887. this.items.getRange().each(function(item){
  15888. item.setVisible(slice === this.sliceMap[item.id]);
  15889. }.bind(this));
  15890. }
  15891. });/**
  15892. * Copyright (c) 2009
  15893. * Jan-Felix Schwarz, Willi Tscheschner, Nicolas Peters, Martin Czuchra, Daniel Polak
  15894. *
  15895. * Permission is hereby granted, free of charge, to any person obtaining a
  15896. * copy of this software and associated documentation files (the "Software"),
  15897. * to deal in the Software without restriction, including without limitation
  15898. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15899. * and/or sell copies of the Software, and to permit persons to whom the
  15900. * Software is furnished to do so, subject to the following conditions:
  15901. *
  15902. * The above copyright notice and this permission notice shall be included in
  15903. * all copies or substantial portions of the Software.
  15904. *
  15905. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15906. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15907. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15908. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15909. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  15910. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  15911. * DEALINGS IN THE SOFTWARE.
  15912. **/
  15913. if(!ORYX.Plugins) {
  15914. ORYX.Plugins = new Object();
  15915. }
  15916. ORYX.Plugins.ShapeMenuPlugin = {
  15917. construct: function(facade) {
  15918. this.facade = facade;
  15919. this.alignGroups = new Hash();
  15920. var containerNode = this.facade.getCanvas().getHTMLContainer();
  15921. this.shapeMenu = new ORYX.Plugins.ShapeMenu(containerNode);
  15922. this.currentShapes = [];
  15923. // Register on dragging and resizing events for show/hide of ShapeMenu
  15924. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START, this.hideShapeMenu.bind(this));
  15925. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END, this.showShapeMenu.bind(this));
  15926. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_RESIZE_START, (function(){
  15927. this.hideShapeMenu();
  15928. this.hideMorphMenu();
  15929. }).bind(this));
  15930. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_RESIZE_END, this.showShapeMenu.bind(this));
  15931. // Enable DragZone
  15932. var DragZone = new Ext.dd.DragZone(containerNode.parentNode, {shadow: !Ext.isMac});
  15933. DragZone.afterDragDrop = this.afterDragging.bind(this, DragZone);
  15934. DragZone.beforeDragOver = this.beforeDragOver.bind(this, DragZone);
  15935. // Memory of created Buttons
  15936. this.createdButtons = {};
  15937. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_STENCIL_SET_LOADED, (function(){ this.registryChanged() }).bind(this));
  15938. this.timer = null;
  15939. this.resetElements = true;
  15940. },
  15941. hideShapeMenu: function(event) {
  15942. window.clearTimeout(this.timer);
  15943. this.timer = null;
  15944. this.shapeMenu.hide();
  15945. },
  15946. showShapeMenu: function( dontGenerateNew ) {
  15947. if( !dontGenerateNew || this.resetElements ){
  15948. window.clearTimeout(this.timer);
  15949. this.timer = window.setTimeout(function(){
  15950. // Close all Buttons
  15951. this.shapeMenu.closeAllButtons();
  15952. // Show the Morph Button
  15953. this.showMorphButton(this.currentShapes);
  15954. // Show the Stencil Buttons
  15955. this.showStencilButtons(this.currentShapes);
  15956. // Show the ShapeMenu
  15957. this.shapeMenu.show(this.currentShapes);
  15958. this.resetElements = false;
  15959. }.bind(this), 300)
  15960. } else {
  15961. window.clearTimeout(this.timer);
  15962. this.timer = null;
  15963. // Show the ShapeMenu
  15964. this.shapeMenu.show(this.currentShapes);
  15965. }
  15966. },
  15967. registryChanged: function(pluginsData) {
  15968. if(pluginsData) {
  15969. pluginsData = pluginsData.each(function(value) {value.group = value.group ? value.group : 'unknown'});
  15970. this.pluginsData = pluginsData.sortBy( function(value) {
  15971. return (value.group + "" + value.index);
  15972. });
  15973. }
  15974. this.shapeMenu.removeAllButtons();
  15975. this.shapeMenu.setNumberOfButtonsPerLevel(ORYX.CONFIG.SHAPEMENU_RIGHT, 2);
  15976. this.createdButtons = {};
  15977. this.createMorphMenu();
  15978. if( !this.pluginsData ){
  15979. this.pluginsData = [];
  15980. }
  15981. this.baseMorphStencils = this.facade.getRules().baseMorphs();
  15982. // Checks if the stencil set has morphing attributes
  15983. var isMorphing = this.facade.getRules().containsMorphingRules();
  15984. // Create Buttons for all Stencils of all loaded stencilsets
  15985. var stencilsets = this.facade.getStencilSets();
  15986. stencilsets.values().each((function(stencilSet){
  15987. var nodes = stencilSet.nodes();
  15988. nodes.each((function(stencil) {
  15989. // Create a button for each node
  15990. var option = {type: stencil.id(), namespace: stencil.namespace(), connectingType: true};
  15991. var button = new ORYX.Plugins.ShapeMenuButton({
  15992. callback: this.newShape.bind(this, option),
  15993. icon: stencil.icon(),
  15994. align: ORYX.CONFIG.SHAPEMENU_RIGHT,
  15995. group: 0,
  15996. //dragcallback: this.hideShapeMenu.bind(this),
  15997. msg: stencil.title() + " - " + ORYX.I18N.ShapeMenuPlugin.clickDrag
  15998. });
  15999. // Add button to shape menu
  16000. this.shapeMenu.addButton(button);
  16001. // Add to the created Button Array
  16002. this.createdButtons[stencil.namespace() + stencil.type() + stencil.id()] = button;
  16003. // Drag'n'Drop will enable
  16004. Ext.dd.Registry.register(button.node.lastChild, option);
  16005. }).bind(this));
  16006. var edges = stencilSet.edges();
  16007. edges.each((function(stencil) {
  16008. // Create a button for each edge
  16009. var option = {type: stencil.id(), namespace: stencil.namespace()};
  16010. var button = new ORYX.Plugins.ShapeMenuButton({
  16011. callback: this.newShape.bind(this, option),
  16012. // icon: isMorphing ? ORYX.PATH + "images/edges.png" : stencil.icon(),
  16013. icon: stencil.icon(),
  16014. align: ORYX.CONFIG.SHAPEMENU_RIGHT,
  16015. group: 1,
  16016. //dragcallback: this.hideShapeMenu.bind(this),
  16017. msg: (isMorphing ? ORYX.I18N.Edge : stencil.title()) + " - " + ORYX.I18N.ShapeMenuPlugin.drag
  16018. });
  16019. // Add button to shape menu
  16020. this.shapeMenu.addButton(button);
  16021. // Add to the created Button Array
  16022. this.createdButtons[stencil.namespace() + stencil.type() + stencil.id()] = button;
  16023. // Drag'n'Drop will enable
  16024. Ext.dd.Registry.register(button.node.lastChild, option);
  16025. }).bind(this));
  16026. }).bind(this));
  16027. },
  16028. createMorphMenu: function() {
  16029. this.morphMenu = new Ext.menu.Menu({
  16030. id: 'Oryx_morph_menu',
  16031. items: []
  16032. });
  16033. this.morphMenu.on("mouseover", function() {
  16034. this.morphMenuHovered = true;
  16035. }, this);
  16036. this.morphMenu.on("mouseout", function() {
  16037. this.morphMenuHovered = false;
  16038. }, this);
  16039. // Create the button to show the morph menu
  16040. var button = new ORYX.Plugins.ShapeMenuButton({
  16041. hovercallback: (ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER ? this.showMorphMenu.bind(this) : undefined),
  16042. resetcallback: (ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER ? this.hideMorphMenu.bind(this) : undefined),
  16043. callback: (ORYX.CONFIG.ENABLE_MORPHMENU_BY_HOVER ? undefined : this.toggleMorphMenu.bind(this)),
  16044. icon: ORYX.PATH + 'images/wrench_orange.png',
  16045. align: ORYX.CONFIG.SHAPEMENU_BOTTOM,
  16046. group: 0,
  16047. msg: ORYX.I18N.ShapeMenuPlugin.morphMsg
  16048. });
  16049. this.shapeMenu.setNumberOfButtonsPerLevel(ORYX.CONFIG.SHAPEMENU_BOTTOM, 1)
  16050. this.shapeMenu.addButton(button);
  16051. this.morphMenu.getEl().appendTo(button.node);
  16052. this.morphButton = button;
  16053. },
  16054. showMorphMenu: function() {
  16055. this.morphMenu.show(this.morphButton.node);
  16056. this._morphMenuShown = true;
  16057. },
  16058. hideMorphMenu: function() {
  16059. this.morphMenu.hide();
  16060. this._morphMenuShown = false;
  16061. },
  16062. toggleMorphMenu: function() {
  16063. if(this._morphMenuShown)
  16064. this.hideMorphMenu();
  16065. else
  16066. this.showMorphMenu();
  16067. },
  16068. onSelectionChanged: function(event) {
  16069. var elements = event.elements;
  16070. this.hideShapeMenu();
  16071. this.hideMorphMenu();
  16072. if( this.currentShapes.inspect() !== elements.inspect() ){
  16073. this.currentShapes = elements;
  16074. this.resetElements = true;
  16075. this.showShapeMenu();
  16076. } else {
  16077. this.showShapeMenu(true)
  16078. }
  16079. },
  16080. /**
  16081. * Show button for morphing the selected shape into another stencil
  16082. */
  16083. showMorphButton: function(elements) {
  16084. if(elements.length != 1) return;
  16085. var possibleMorphs = this.facade.getRules().morphStencils({ stencil: elements[0].getStencil() });
  16086. possibleMorphs = possibleMorphs.select(function(morph) {
  16087. if(elements[0].getStencil().type() === "node") {
  16088. //check containment rules
  16089. return this.facade.getRules().canContain({containingShape:elements[0].parent, containedStencil:morph});
  16090. } else {
  16091. //check connect rules
  16092. return this.facade.getRules().canConnect({
  16093. sourceShape: elements[0].dockers.first().getDockedShape(),
  16094. edgeStencil: morph,
  16095. targetShape: elements[0].dockers.last().getDockedShape()
  16096. });
  16097. }
  16098. }.bind(this));
  16099. if(possibleMorphs.size()<=1) return; // if morphing to other stencils is not possible, don't show button
  16100. this.morphMenu.removeAll();
  16101. // populate morph menu with the possible morph stencils ordered by their position
  16102. possibleMorphs = possibleMorphs.sortBy(function(stencil) { return stencil.position(); });
  16103. possibleMorphs.each((function(morph) {
  16104. var menuItem = new Ext.menu.Item({
  16105. text: morph.title(),
  16106. icon: morph.icon(),
  16107. disabled: morph.id()==elements[0].getStencil().id(),
  16108. disabledClass: ORYX.CONFIG.MORPHITEM_DISABLED,
  16109. handler: (function() { this.morphShape(elements[0], morph); }).bind(this)
  16110. });
  16111. this.morphMenu.add(menuItem);
  16112. }).bind(this));
  16113. this.morphButton.prepareToShow();
  16114. },
  16115. /**
  16116. * Show buttons for creating following shapes
  16117. */
  16118. showStencilButtons: function(elements) {
  16119. if(elements.length != 1) return;
  16120. //TODO temporaere nutzung des stencilsets
  16121. var sset = this.facade.getStencilSets()[elements[0].getStencil().namespace()];
  16122. // Get all available edges
  16123. var edges = this.facade.getRules().outgoingEdgeStencils({canvas:this.facade.getCanvas(), sourceShape:elements[0]});
  16124. // And find all targets for each Edge
  16125. var targets = new Array();
  16126. var addedEdges = new Array();
  16127. var isMorphing = this.facade.getRules().containsMorphingRules();
  16128. edges.each((function(edge) {
  16129. if (isMorphing){
  16130. if(this.baseMorphStencils.include(edge)) {
  16131. var shallAppear = true;
  16132. } else {
  16133. // if edge is member of a morph groups where none of the base morphs is in the outgoing edges
  16134. // we want to display the button (but only for the first one)
  16135. var possibleMorphs = this.facade.getRules().morphStencils({ stencil: edge });
  16136. var shallAppear = !possibleMorphs.any((function(morphStencil) {
  16137. if(this.baseMorphStencils.include(morphStencil) && edges.include(morphStencil)) return true;
  16138. return addedEdges.include(morphStencil);
  16139. }).bind(this));
  16140. }
  16141. }
  16142. if(shallAppear || !isMorphing) {
  16143. if(this.createdButtons[edge.namespace() + edge.type() + edge.id()])
  16144. this.createdButtons[edge.namespace() + edge.type() + edge.id()].prepareToShow();
  16145. addedEdges.push(edge);
  16146. }
  16147. // get all targets for this edge
  16148. targets = targets.concat(this.facade.getRules().targetStencils(
  16149. {canvas:this.facade.getCanvas(), sourceShape:elements[0], edgeStencil:edge}));
  16150. }).bind(this));
  16151. targets.uniq();
  16152. var addedTargets = new Array();
  16153. // Iterate all possible target
  16154. targets.each((function(target) {
  16155. if (isMorphing){
  16156. // continue with next target stencil
  16157. if (target.type()==="edge") return;
  16158. // continue when stencil should not shown in the shape menu
  16159. if (!this.facade.getRules().showInShapeMenu(target)) return
  16160. // if target is not a base morph
  16161. if(!this.baseMorphStencils.include(target)) {
  16162. // if target is member of a morph groups where none of the base morphs is in the targets
  16163. // we want to display the button (but only for the first one)
  16164. var possibleMorphs = this.facade.getRules().morphStencils({ stencil: target });
  16165. if(possibleMorphs.size()==0) return; // continue with next target
  16166. var baseMorphInTargets = possibleMorphs.any((function(morphStencil) {
  16167. if(this.baseMorphStencils.include(morphStencil) && targets.include(morphStencil)) return true;
  16168. return addedTargets.include(morphStencil);
  16169. }).bind(this));
  16170. if(baseMorphInTargets) return; // continue with next target
  16171. }
  16172. }
  16173. // if this is reached the button shall appear in the shape menu:
  16174. if(this.createdButtons[target.namespace() + target.type() + target.id()])
  16175. this.createdButtons[target.namespace() + target.type() + target.id()].prepareToShow();
  16176. addedTargets.push(target);
  16177. }).bind(this));
  16178. },
  16179. beforeDragOver: function(dragZone, target, event){
  16180. if (this.shapeMenu.isVisible){
  16181. this.hideShapeMenu();
  16182. }
  16183. var coord = this.facade.eventCoordinates(event.browserEvent);
  16184. var aShapes = this.facade.getCanvas().getAbstractShapesAtPosition(coord);
  16185. if(aShapes.length <= 0) {return false;}
  16186. var el = aShapes.last();
  16187. if(this._lastOverElement == el) {
  16188. return false;
  16189. } else {
  16190. // check containment rules
  16191. var option = Ext.dd.Registry.getHandle(target.DDM.currentTarget);
  16192. // revert to original options if these were modified
  16193. if(option.backupOptions) {
  16194. for(key in option.backupOptions) {
  16195. option[key] = option.backupOptions[key];
  16196. }
  16197. delete option.backupOptions;
  16198. }
  16199. var stencilSet = this.facade.getStencilSets()[option.namespace];
  16200. var stencil = stencilSet.stencil(option.type);
  16201. var candidate = aShapes.last();
  16202. if(stencil.type() === "node") {
  16203. //check containment rules
  16204. var canContain = this.facade.getRules().canContain({containingShape:candidate, containedStencil:stencil});
  16205. // if not canContain, try to find a morph which can be contained
  16206. if(!canContain) {
  16207. var possibleMorphs = this.facade.getRules().morphStencils({stencil: stencil});
  16208. for(var i=0; i<possibleMorphs.size(); i++) {
  16209. canContain = this.facade.getRules().canContain({
  16210. containingShape:candidate,
  16211. containedStencil:possibleMorphs[i]
  16212. });
  16213. if(canContain) {
  16214. option.backupOptions = Object.clone(option);
  16215. option.type = possibleMorphs[i].id();
  16216. option.namespace = possibleMorphs[i].namespace();
  16217. break;
  16218. }
  16219. }
  16220. }
  16221. this._currentReference = canContain ? candidate : undefined;
  16222. } else { //Edge
  16223. var curCan = candidate, orgCan = candidate;
  16224. var canConnect = false;
  16225. while(!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)){
  16226. candidate = curCan;
  16227. //check connection rules
  16228. canConnect = this.facade.getRules().canConnect({
  16229. sourceShape: this.currentShapes.first(),
  16230. edgeStencil: stencil,
  16231. targetShape: curCan
  16232. });
  16233. curCan = curCan.parent;
  16234. }
  16235. // if not canConnect, try to find a morph which can be connected
  16236. if(!canConnect) {
  16237. candidate = orgCan;
  16238. var possibleMorphs = this.facade.getRules().morphStencils({stencil: stencil});
  16239. for(var i=0; i<possibleMorphs.size(); i++) {
  16240. var curCan = candidate;
  16241. var canConnect = false;
  16242. while(!canConnect && curCan && !(curCan instanceof ORYX.Core.Canvas)){
  16243. candidate = curCan;
  16244. //check connection rules
  16245. canConnect = this.facade.getRules().canConnect({
  16246. sourceShape: this.currentShapes.first(),
  16247. edgeStencil: possibleMorphs[i],
  16248. targetShape: curCan
  16249. });
  16250. curCan = curCan.parent;
  16251. }
  16252. if(canConnect) {
  16253. option.backupOptions = Object.clone(option);
  16254. option.type = possibleMorphs[i].id();
  16255. option.namespace = possibleMorphs[i].namespace();
  16256. break;
  16257. } else {
  16258. candidate = orgCan;
  16259. }
  16260. }
  16261. }
  16262. this._currentReference = canConnect ? candidate : undefined;
  16263. }
  16264. this.facade.raiseEvent({
  16265. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  16266. highlightId:'shapeMenu',
  16267. elements: [candidate],
  16268. color: this._currentReference ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR
  16269. });
  16270. var pr = dragZone.getProxy();
  16271. pr.setStatus(this._currentReference ? pr.dropAllowed : pr.dropNotAllowed );
  16272. pr.sync();
  16273. }
  16274. this._lastOverElement = el;
  16275. return false;
  16276. },
  16277. afterDragging: function(dragZone, target, event) {
  16278. if (!(this.currentShapes instanceof Array)||this.currentShapes.length<=0) {
  16279. return;
  16280. }
  16281. var sourceShape = this.currentShapes;
  16282. this._lastOverElement = undefined;
  16283. // Hide the highlighting
  16284. this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'shapeMenu'});
  16285. // Check if drop is allowed
  16286. var proxy = dragZone.getProxy()
  16287. if(proxy.dropStatus == proxy.dropNotAllowed) { return this.facade.updateSelection();}
  16288. // Check if there is a current Parent
  16289. if(!this._currentReference) { return }
  16290. var option = Ext.dd.Registry.getHandle(target.DDM.currentTarget);
  16291. option['parent'] = this._currentReference;
  16292. var xy = event.getXY();
  16293. var pos = {x: xy[0], y: xy[1]};
  16294. var a = this.facade.getCanvas().node.getScreenCTM();
  16295. // Correcting the UpperLeft-Offset
  16296. pos.x -= a.e; pos.y -= a.f;
  16297. // Correcting the Zoom-Faktor
  16298. pos.x /= a.a; pos.y /= a.d;
  16299. // Correcting the ScrollOffset
  16300. pos.x -= document.documentElement.scrollLeft;
  16301. pos.y -= document.documentElement.scrollTop;
  16302. var parentAbs = this._currentReference.absoluteXY();
  16303. pos.x -= parentAbs.x;
  16304. pos.y -= parentAbs.y;
  16305. // If the ctrl key is not pressed,
  16306. // snapp the new shape to the center
  16307. // if it is near to the center of the other shape
  16308. if (!event.ctrlKey){
  16309. // Get the center of the shape
  16310. var cShape = this.currentShapes[0].bounds.center();
  16311. // Snapp +-20 Pixel horizontal to the center
  16312. if (20 > Math.abs(cShape.x - pos.x)){
  16313. pos.x = cShape.x;
  16314. }
  16315. // Snapp +-20 Pixel vertical to the center
  16316. if (20 > Math.abs(cShape.y - pos.y)){
  16317. pos.y = cShape.y;
  16318. }
  16319. }
  16320. option['position'] = pos;
  16321. option['connectedShape'] = this.currentShapes[0];
  16322. if(option['connectingType']) {
  16323. var stencilset = this.facade.getStencilSets()[option.namespace];
  16324. var containedStencil = stencilset.stencil(option.type);
  16325. var args = { sourceShape: this.currentShapes[0], targetStencil: containedStencil };
  16326. option['connectingType'] = this.facade.getRules().connectMorph(args).id();
  16327. }
  16328. if (ORYX.CONFIG.SHAPEMENU_DISABLE_CONNECTED_EDGE===true) {
  16329. delete option['connectingType'];
  16330. }
  16331. var command = new ORYX.Plugins.ShapeMenuPlugin.CreateCommand(Object.clone(option), this._currentReference, pos, this);
  16332. this.facade.executeCommands([command]);
  16333. // Inform about completed Drag
  16334. this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_SHAPE_MENU_CLOSE, source:sourceShape, destination:this.currentShapes});
  16335. // revert to original options if these were modified
  16336. if(option.backupOptions) {
  16337. for(key in option.backupOptions) {
  16338. option[key] = option.backupOptions[key];
  16339. }
  16340. delete option.backupOptions;
  16341. }
  16342. this._currentReference = undefined;
  16343. },
  16344. newShape: function(option, event) {
  16345. var stencilset = this.facade.getStencilSets()[option.namespace];
  16346. var containedStencil = stencilset.stencil(option.type);
  16347. if(this.facade.getRules().canContain({
  16348. containingShape:this.currentShapes.first().parent,
  16349. "containedStencil":containedStencil
  16350. })) {
  16351. option['connectedShape'] = this.currentShapes[0];
  16352. option['parent'] = this.currentShapes.first().parent;
  16353. option['containedStencil'] = containedStencil;
  16354. var args = { sourceShape: this.currentShapes[0], targetStencil: containedStencil };
  16355. var targetStencil = this.facade.getRules().connectMorph(args);
  16356. if (!targetStencil){ return }// Check if there can be a target shape
  16357. option['connectingType'] = targetStencil.id();
  16358. if (ORYX.CONFIG.SHAPEMENU_DISABLE_CONNECTED_EDGE===true) {
  16359. delete option['connectingType'];
  16360. }
  16361. var command = new ORYX.Plugins.ShapeMenuPlugin.CreateCommand(option, undefined, undefined, this);
  16362. this.facade.executeCommands([command]);
  16363. }
  16364. },
  16365. /**
  16366. * Morph a shape to a new stencil
  16367. * {Command implemented}
  16368. * @param {Shape} shape
  16369. * @param {Stencil} stencil
  16370. */
  16371. morphShape: function(shape, stencil) {
  16372. var MorphTo = ORYX.Core.Command.extend({
  16373. construct: function(shape, stencil, facade){
  16374. this.shape = shape;
  16375. this.stencil = stencil;
  16376. this.facade = facade;
  16377. },
  16378. execute: function(){
  16379. var shape = this.shape;
  16380. var stencil = this.stencil;
  16381. var resourceId = shape.resourceId;
  16382. // Serialize all attributes
  16383. var serialized = shape.serialize();
  16384. stencil.properties().each((function(prop) {
  16385. if(prop.readonly()) {
  16386. serialized = serialized.reject(function(serProp) {
  16387. return serProp.name==prop.id();
  16388. });
  16389. }
  16390. }).bind(this));
  16391. // Get shape if already created, otherwise create a new shape
  16392. if (this.newShape){
  16393. newShape = this.newShape;
  16394. this.facade.getCanvas().add(newShape);
  16395. } else {
  16396. newShape = this.facade.createShape({
  16397. type: stencil.id(),
  16398. namespace: stencil.namespace(),
  16399. resourceId: resourceId
  16400. });
  16401. }
  16402. // calculate new bounds using old shape's upperLeft and new shape's width/height
  16403. var boundsObj = serialized.find(function(serProp){
  16404. return (serProp.prefix === "oryx" && serProp.name === "bounds");
  16405. });
  16406. var changedBounds = null;
  16407. if(!this.facade.getRules().preserveBounds(shape.getStencil())) {
  16408. var bounds = boundsObj.value.split(",");
  16409. if (parseInt(bounds[0], 10) > parseInt(bounds[2], 10)) { // if lowerRight comes first, swap array items
  16410. var tmp = bounds[0];
  16411. bounds[0] = bounds[2];
  16412. bounds[2] = tmp;
  16413. tmp = bounds[1];
  16414. bounds[1] = bounds[3];
  16415. bounds[3] = tmp;
  16416. }
  16417. bounds[2] = parseInt(bounds[0], 10) + newShape.bounds.width();
  16418. bounds[3] = parseInt(bounds[1], 10) + newShape.bounds.height();
  16419. boundsObj.value = bounds.join(",");
  16420. } else {
  16421. var height = shape.bounds.height();
  16422. var width = shape.bounds.width();
  16423. // consider the minimum and maximum size of
  16424. // the new shape
  16425. if (newShape.minimumSize) {
  16426. if (shape.bounds.height() < newShape.minimumSize.height) {
  16427. height = newShape.minimumSize.height;
  16428. }
  16429. if (shape.bounds.width() < newShape.minimumSize.width) {
  16430. width = newShape.minimumSize.width;
  16431. }
  16432. }
  16433. if(newShape.maximumSize) {
  16434. if(shape.bounds.height() > newShape.maximumSize.height) {
  16435. height = newShape.maximumSize.height;
  16436. }
  16437. if(shape.bounds.width() > newShape.maximumSize.width) {
  16438. width = newShape.maximumSize.width;
  16439. }
  16440. }
  16441. changedBounds = {
  16442. a : {
  16443. x: shape.bounds.a.x,
  16444. y: shape.bounds.a.y
  16445. },
  16446. b : {
  16447. x: shape.bounds.a.x + width,
  16448. y: shape.bounds.a.y + height
  16449. }
  16450. };
  16451. }
  16452. var oPos = shape.bounds.center();
  16453. if(changedBounds !== null) {
  16454. newShape.bounds.set(changedBounds);
  16455. }
  16456. // Set all related dockers
  16457. this.setRelatedDockers(shape, newShape);
  16458. // store DOM position of old shape
  16459. var parentNode = shape.node.parentNode;
  16460. var nextSibling = shape.node.nextSibling;
  16461. // Delete the old shape
  16462. this.facade.deleteShape(shape);
  16463. // Deserialize the new shape - Set all attributes
  16464. newShape.deserialize(serialized);
  16465. /*
  16466. * Change color to default if unchanged
  16467. * 23.04.2010
  16468. */
  16469. if(shape.getStencil().property("oryx-bgcolor")
  16470. && shape.properties["oryx-bgcolor"]
  16471. && shape.getStencil().property("oryx-bgcolor").value().toUpperCase()== shape.properties["oryx-bgcolor"].toUpperCase()){
  16472. if(newShape.getStencil().property("oryx-bgcolor")){
  16473. newShape.setProperty("oryx-bgcolor", newShape.getStencil().property("oryx-bgcolor").value());
  16474. }
  16475. }
  16476. if(changedBounds !== null) {
  16477. newShape.bounds.set(changedBounds);
  16478. }
  16479. if(newShape.getStencil().type()==="edge" || (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) {
  16480. newShape.bounds.centerMoveTo(oPos);
  16481. }
  16482. if(newShape.getStencil().type()==="node" && (newShape.dockers.length==0 || !newShape.dockers[0].getDockedShape())) {
  16483. this.setRelatedDockers(newShape, newShape);
  16484. }
  16485. // place at the DOM position of the old shape
  16486. if(nextSibling) parentNode.insertBefore(newShape.node, nextSibling);
  16487. else parentNode.appendChild(newShape.node);
  16488. // Set selection
  16489. this.facade.setSelection([newShape]);
  16490. this.facade.getCanvas().update();
  16491. this.facade.updateSelection();
  16492. this.newShape = newShape;
  16493. },
  16494. rollback: function(){
  16495. if (!this.shape || !this.newShape || !this.newShape.parent) {return}
  16496. // Append shape to the parent
  16497. this.newShape.parent.add(this.shape);
  16498. // Set dockers
  16499. this.setRelatedDockers(this.newShape, this.shape);
  16500. // Delete new shape
  16501. this.facade.deleteShape(this.newShape);
  16502. // Set selection
  16503. this.facade.setSelection([this.shape]);
  16504. // Update
  16505. this.facade.getCanvas().update();
  16506. this.facade.updateSelection();
  16507. },
  16508. /**
  16509. * Set all incoming and outgoing edges from the shape to the new shape
  16510. * @param {Shape} shape
  16511. * @param {Shape} newShape
  16512. */
  16513. setRelatedDockers: function(shape, newShape){
  16514. if(shape.getStencil().type()==="node") {
  16515. (shape.incoming||[]).concat(shape.outgoing||[])
  16516. .each(function(i) {
  16517. i.dockers.each(function(docker) {
  16518. if (docker.getDockedShape() == shape) {
  16519. var rPoint = Object.clone(docker.referencePoint);
  16520. // Move reference point per percent
  16521. var rPointNew = {
  16522. x: rPoint.x*newShape.bounds.width()/shape.bounds.width(),
  16523. y: rPoint.y*newShape.bounds.height()/shape.bounds.height()
  16524. };
  16525. docker.setDockedShape(newShape);
  16526. // Set reference point and center to new position
  16527. docker.setReferencePoint(rPointNew);
  16528. if(i instanceof ORYX.Core.Edge) {
  16529. docker.bounds.centerMoveTo(rPointNew);
  16530. } else {
  16531. var absXY = shape.absoluteXY();
  16532. docker.bounds.centerMoveTo({x:rPointNew.x+absXY.x, y:rPointNew.y+absXY.y});
  16533. //docker.bounds.moveBy({x:rPointNew.x-rPoint.x, y:rPointNew.y-rPoint.y});
  16534. }
  16535. }
  16536. });
  16537. });
  16538. // for attached events
  16539. if(shape.dockers.length>0&&shape.dockers.first().getDockedShape()) {
  16540. newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape());
  16541. newShape.dockers.first().setReferencePoint(Object.clone(shape.dockers.first().referencePoint));
  16542. }
  16543. } else { // is edge
  16544. newShape.dockers.first().setDockedShape(shape.dockers.first().getDockedShape());
  16545. newShape.dockers.first().setReferencePoint(shape.dockers.first().referencePoint);
  16546. newShape.dockers.last().setDockedShape(shape.dockers.last().getDockedShape());
  16547. newShape.dockers.last().setReferencePoint(shape.dockers.last().referencePoint);
  16548. }
  16549. }
  16550. });
  16551. // Create and execute command (for undo/redo)
  16552. var command = new MorphTo(shape, stencil, this.facade);
  16553. this.facade.executeCommands([command]);
  16554. }
  16555. }
  16556. ORYX.Plugins.ShapeMenuPlugin = ORYX.Plugins.AbstractPlugin.extend(ORYX.Plugins.ShapeMenuPlugin);
  16557. ORYX.Plugins.ShapeMenu = {
  16558. /***
  16559. * Constructor.
  16560. */
  16561. construct: function(parentNode) {
  16562. this.bounds = undefined;
  16563. this.shapes = undefined;
  16564. this.buttons = [];
  16565. this.isVisible = false;
  16566. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $(parentNode),
  16567. ['div', {id: ORYX.Editor.provideId(), 'class':'Oryx_ShapeMenu'}]);
  16568. this.alignContainers = new Hash();
  16569. this.numberOfButtonsPerLevel = new Hash();
  16570. },
  16571. addButton: function(button) {
  16572. this.buttons.push(button);
  16573. // lazy grafting of the align containers
  16574. if(!this.alignContainers[button.align]) {
  16575. this.alignContainers[button.align] = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.node,
  16576. ['div', {'class':button.align}]);
  16577. this.node.appendChild(this.alignContainers[button.align]);
  16578. // add event listeners for hover effect
  16579. var onBubble = false;
  16580. this.alignContainers[button.align].addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this.hoverAlignContainer.bind(this, button.align), onBubble);
  16581. this.alignContainers[button.align].addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this.resetAlignContainer.bind(this, button.align), onBubble);
  16582. this.alignContainers[button.align].addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.hoverAlignContainer.bind(this, button.align), onBubble);
  16583. }
  16584. this.alignContainers[button.align].appendChild(button.node);
  16585. },
  16586. deleteButton: function(button) {
  16587. this.buttons = this.buttons.without(button);
  16588. this.node.removeChild(button.node);
  16589. },
  16590. removeAllButtons: function() {
  16591. var me = this;
  16592. this.buttons.each(function(value){
  16593. if (value.node&&value.node.parentNode)
  16594. value.node.parentNode.removeChild(value.node);
  16595. });
  16596. this.buttons = [];
  16597. },
  16598. closeAllButtons: function() {
  16599. this.buttons.each(function(value){ value.prepareToHide() });
  16600. this.isVisible = false;
  16601. },
  16602. /**
  16603. * Show the shape menu
  16604. */
  16605. show: function(shapes) {
  16606. //shapes = (shapes||[]).findAll(function(r){ return r && r.node && r.node.parent });
  16607. if(shapes.length <= 0 )
  16608. return
  16609. this.shapes = shapes;
  16610. var newBounds = undefined;
  16611. var tmpBounds = undefined;
  16612. this.shapes.each(function(value) {
  16613. var a = value.node.getScreenCTM();
  16614. var upL = value.absoluteXY();
  16615. a.e = a.a*upL.x;
  16616. a.f = a.d*upL.y;
  16617. tmpBounds = new ORYX.Core.Bounds(a.e, a.f, a.e+a.a*value.bounds.width(), a.f+a.d*value.bounds.height());
  16618. /*if(value instanceof ORYX.Core.Edge) {
  16619. tmpBounds.moveBy(value.bounds.upperLeft())
  16620. }*/
  16621. if(!newBounds)
  16622. newBounds = tmpBounds
  16623. else
  16624. newBounds.include(tmpBounds);
  16625. });
  16626. this.bounds = newBounds;
  16627. //this.bounds.moveBy({x:document.documentElement.scrollLeft, y:document.documentElement.scrollTop});
  16628. var bounds = this.bounds;
  16629. var a = this.bounds.upperLeft();
  16630. var left = 0,
  16631. leftButtonGroup = 0;
  16632. var top = 0,
  16633. topButtonGroup = 0;
  16634. var bottom = 0,
  16635. bottomButtonGroup;
  16636. var right = 0
  16637. rightButtonGroup = 0;
  16638. var size = 22;
  16639. this.getWillShowButtons().sortBy(function(button) {
  16640. return button.group;
  16641. });
  16642. this.getWillShowButtons().each(function(button){
  16643. var numOfButtonsPerLevel = this.getNumberOfButtonsPerLevel(button.align);
  16644. if (button.align == ORYX.CONFIG.SHAPEMENU_LEFT) {
  16645. // vertical levels
  16646. if(button.group!=leftButtonGroup) {
  16647. left = 0;
  16648. leftButtonGroup = button.group;
  16649. }
  16650. var x = Math.floor(left / numOfButtonsPerLevel)
  16651. var y = left % numOfButtonsPerLevel;
  16652. button.setLevel(x);
  16653. button.setPosition(a.x-5 - (x+1)*size,
  16654. a.y+numOfButtonsPerLevel*button.group*size + button.group*0.3*size + y*size);
  16655. //button.setPosition(a.x-22, a.y+left*size);
  16656. left++;
  16657. } else if (button.align == ORYX.CONFIG.SHAPEMENU_TOP) {
  16658. // horizontal levels
  16659. if(button.group!=topButtonGroup) {
  16660. top = 0;
  16661. topButtonGroup = button.group;
  16662. }
  16663. var x = top % numOfButtonsPerLevel;
  16664. var y = Math.floor(top / numOfButtonsPerLevel);
  16665. button.setLevel(y);
  16666. button.setPosition(a.x+numOfButtonsPerLevel*button.group*size + button.group*0.3*size + x*size,
  16667. a.y-5 - (y+1)*size);
  16668. top++;
  16669. } else if (button.align == ORYX.CONFIG.SHAPEMENU_BOTTOM) {
  16670. // horizontal levels
  16671. if(button.group!=bottomButtonGroup) {
  16672. bottom = 0;
  16673. bottomButtonGroup = button.group;
  16674. }
  16675. var x = bottom % numOfButtonsPerLevel;
  16676. var y = Math.floor(bottom / numOfButtonsPerLevel);
  16677. button.setLevel(y);
  16678. button.setPosition(a.x+numOfButtonsPerLevel*button.group*size + button.group*0.3*size + x*size,
  16679. a.y+bounds.height() + 5 + y*size);
  16680. bottom++;
  16681. } else {
  16682. // vertical levels
  16683. if(button.group!=rightButtonGroup) {
  16684. right = 0;
  16685. rightButtonGroup = button.group;
  16686. }
  16687. var x = Math.floor(right / numOfButtonsPerLevel)
  16688. var y = right % numOfButtonsPerLevel;
  16689. button.setLevel(x);
  16690. button.setPosition(a.x+bounds.width() + 5 + x*size,
  16691. a.y+numOfButtonsPerLevel*button.group*size + button.group*0.3*size + y*size - 5);
  16692. right++;
  16693. }
  16694. button.show();
  16695. }.bind(this));
  16696. this.isVisible = true;
  16697. },
  16698. /**
  16699. * Hide the shape menu
  16700. */
  16701. hide: function() {
  16702. this.buttons.each(function(button){
  16703. button.hide();
  16704. });
  16705. this.isVisible = false;
  16706. //this.bounds = undefined;
  16707. //this.shape = undefined;
  16708. },
  16709. hoverAlignContainer: function(align, evt) {
  16710. this.buttons.each(function(button){
  16711. if(button.align == align) button.showOpaque();
  16712. });
  16713. },
  16714. resetAlignContainer: function(align, evt) {
  16715. this.buttons.each(function(button){
  16716. if(button.align == align) button.showTransparent();
  16717. });
  16718. },
  16719. isHover: function() {
  16720. return this.buttons.any(function(value){
  16721. return value.isHover();
  16722. });
  16723. },
  16724. getWillShowButtons: function() {
  16725. return this.buttons.findAll(function(value){return value.willShow});
  16726. },
  16727. /**
  16728. * Returns a set on buttons for that align value
  16729. * @params {String} align
  16730. * @params {String} group
  16731. */
  16732. getButtons: function(align, group){
  16733. return this.getWillShowButtons().findAll(function(b){ return b.align == align && (group === undefined || b.group == group)})
  16734. },
  16735. /**
  16736. * Set the number of buttons to display on each level of the shape menu in the specified align group.
  16737. * Example: setNumberOfButtonsPerLevel(ORYX.CONFIG.SHAPEMENU_RIGHT, 2) causes that the buttons of the right align group
  16738. * will be rendered in 2 rows.
  16739. */
  16740. setNumberOfButtonsPerLevel: function(align, number) {
  16741. this.numberOfButtonsPerLevel[align] = number;
  16742. },
  16743. /**
  16744. * Returns the number of buttons to display on each level of the shape menu in the specified align group.
  16745. * Default value is 1
  16746. */
  16747. getNumberOfButtonsPerLevel: function(align) {
  16748. if(this.numberOfButtonsPerLevel[align])
  16749. return Math.min(this.getButtons(align,0).length, this.numberOfButtonsPerLevel[align]);
  16750. else
  16751. return 1;
  16752. }
  16753. }
  16754. ORYX.Plugins.ShapeMenu = Clazz.extend(ORYX.Plugins.ShapeMenu);
  16755. ORYX.Plugins.ShapeMenuButton = {
  16756. /**
  16757. * Constructor
  16758. * @param option A key map specifying the configuration options:
  16759. * id: (String) The id of the parent DOM element for the new button
  16760. * icon: (String) The url to the icon of the button
  16761. * msg: (String) A tooltip message
  16762. * caption:(String) The caption of the button (attention: button width > 22, only set for single column button layouts)
  16763. * align: (String) The direction in which the button is aligned
  16764. * group: (Integer) The button group in the specified alignment
  16765. * (buttons in the same group will be aligned side by side)
  16766. * callback: (Function) A callback that is executed when the button is clicked
  16767. * dragcallback: (Function) A callback that is executed when the button is dragged
  16768. * hovercallback: (Function) A callback that is executed when the button is hovered
  16769. * resetcallback: (Function) A callback that is executed when the button is reset
  16770. * arguments: (Array) An argument array to pass to the callback functions
  16771. */
  16772. construct: function(option) {
  16773. if(option) {
  16774. this.option = option;
  16775. if(!this.option.arguments)
  16776. this.option.arguments = [];
  16777. } else {
  16778. //TODO error
  16779. }
  16780. this.parentId = this.option.id ? this.option.id : null;
  16781. // graft the button.
  16782. var buttonClassName = this.option.caption ? "Oryx_button_with_caption" : "Oryx_button";
  16783. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $(this.parentId),
  16784. ['div', {'class':buttonClassName}]);
  16785. var imgOptions = {src:this.option.icon};
  16786. if(this.option.msg){
  16787. imgOptions.title = this.option.msg;
  16788. }
  16789. // graft and update icon (not in grafting for ns reasons).
  16790. //TODO Enrich graft()-function to do this in one of the above steps.
  16791. if(this.option.icon)
  16792. ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.node,
  16793. ['img', imgOptions]);
  16794. if(this.option.caption) {
  16795. var captionNode = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.node, ['span']);
  16796. ORYX.Editor.graft("http://www.w3.org/1999/xhtml", captionNode, this.option.caption);
  16797. }
  16798. var onBubble = false;
  16799. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOVER, this.hover.bind(this), onBubble);
  16800. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEOUT, this.reset.bind(this), onBubble);
  16801. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.activate.bind(this), onBubble);
  16802. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.hover.bind(this), onBubble);
  16803. this.node.addEventListener('click', this.trigger.bind(this), onBubble);
  16804. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.move.bind(this), onBubble);
  16805. this.align = this.option.align ? this.option.align : ORYX.CONFIG.SHAPEMENU_RIGHT;
  16806. this.group = this.option.group ? this.option.group : 0;
  16807. this.hide();
  16808. this.dragStart = false;
  16809. this.isVisible = false;
  16810. this.willShow = false;
  16811. this.resetTimer;
  16812. },
  16813. hide: function() {
  16814. this.node.style.display = "none";
  16815. this.isVisible = false;
  16816. },
  16817. show: function() {
  16818. this.node.style.display = "";
  16819. this.node.style.opacity = this.opacity;
  16820. this.isVisible = true;
  16821. },
  16822. showOpaque: function() {
  16823. this.node.style.opacity = 1.0;
  16824. },
  16825. showTransparent: function() {
  16826. this.node.style.opacity = this.opacity;
  16827. },
  16828. prepareToShow: function() {
  16829. this.willShow = true;
  16830. },
  16831. prepareToHide: function() {
  16832. this.willShow = false;
  16833. this.hide();
  16834. },
  16835. setPosition: function(x, y) {
  16836. this.node.style.left = x + "px";
  16837. this.node.style.top = y + "px";
  16838. },
  16839. setLevel: function(level) {
  16840. if(level==0) this.opacity = 0.5;
  16841. else if(level==1) this.opacity = 0.2;
  16842. //else if(level==2) this.opacity = 0.1;
  16843. else this.opacity = 0.0;
  16844. },
  16845. setChildWidth: function(width) {
  16846. this.childNode.style.width = width + "px";
  16847. },
  16848. reset: function(evt) {
  16849. // Delete the timeout for hiding
  16850. window.clearTimeout( this.resetTimer )
  16851. this.resetTimer = window.setTimeout( this.doReset.bind(this), 100)
  16852. if(this.option.resetcallback) {
  16853. this.option.arguments.push(evt);
  16854. var state = this.option.resetcallback.apply(this, this.option.arguments);
  16855. this.option.arguments.remove(evt);
  16856. }
  16857. },
  16858. doReset: function() {
  16859. if(this.node.hasClassName('Oryx_down'))
  16860. this.node.removeClassName('Oryx_down');
  16861. if(this.node.hasClassName('Oryx_hover'))
  16862. this.node.removeClassName('Oryx_hover');
  16863. },
  16864. activate: function(evt) {
  16865. this.node.addClassName('Oryx_down');
  16866. //Event.stop(evt);
  16867. this.dragStart = true;
  16868. },
  16869. isHover: function() {
  16870. return this.node.hasClassName('Oryx_hover') ? true: false;
  16871. },
  16872. hover: function(evt) {
  16873. // Delete the timeout for hiding
  16874. window.clearTimeout( this.resetTimer )
  16875. this.resetTimer = null;
  16876. this.node.addClassName('Oryx_hover');
  16877. this.dragStart = false;
  16878. if(this.option.hovercallback) {
  16879. this.option.arguments.push(evt);
  16880. var state = this.option.hovercallback.apply(this, this.option.arguments);
  16881. this.option.arguments.remove(evt);
  16882. }
  16883. },
  16884. move: function(evt) {
  16885. if(this.dragStart && this.option.dragcallback) {
  16886. this.option.arguments.push(evt);
  16887. var state = this.option.dragcallback.apply(this, this.option.arguments);
  16888. this.option.arguments.remove(evt);
  16889. }
  16890. },
  16891. trigger: function(evt) {
  16892. if(this.option.callback) {
  16893. //Event.stop(evt);
  16894. this.option.arguments.push(evt);
  16895. var state = this.option.callback.apply(this, this.option.arguments);
  16896. this.option.arguments.remove(evt);
  16897. }
  16898. this.dragStart = false;
  16899. },
  16900. toString: function() {
  16901. return "HTML-Button " + this.id;
  16902. }
  16903. }
  16904. ORYX.Plugins.ShapeMenuButton = Clazz.extend(ORYX.Plugins.ShapeMenuButton);
  16905. //create command for undo/redo
  16906. ORYX.Plugins.ShapeMenuPlugin.CreateCommand = ORYX.Core.Command.extend({
  16907. construct: function(option, currentReference, position, plugin){
  16908. this.option = option;
  16909. this.currentReference = currentReference;
  16910. this.position = position;
  16911. this.plugin = plugin;
  16912. this.shape;
  16913. this.edge;
  16914. this.targetRefPos;
  16915. this.sourceRefPos;
  16916. /*
  16917. * clone options parameters
  16918. */
  16919. this.connectedShape = option.connectedShape;
  16920. this.connectingType = option.connectingType;
  16921. this.namespace = option.namespace;
  16922. this.type = option.type;
  16923. this.containedStencil = option.containedStencil;
  16924. this.parent = option.parent;
  16925. this.currentReference = currentReference;
  16926. this.shapeOptions = option.shapeOptions;
  16927. },
  16928. execute: function(){
  16929. var resume = false;
  16930. if (this.shape) {
  16931. if (this.shape instanceof ORYX.Core.Node) {
  16932. this.parent.add(this.shape);
  16933. if (this.edge) {
  16934. this.plugin.facade.getCanvas().add(this.edge);
  16935. this.edge.dockers.first().setDockedShape(this.connectedShape);
  16936. this.edge.dockers.first().setReferencePoint(this.sourceRefPos);
  16937. this.edge.dockers.last().setDockedShape(this.shape);
  16938. this.edge.dockers.last().setReferencePoint(this.targetRefPos);
  16939. }
  16940. this.plugin.facade.setSelection([this.shape]);
  16941. } else if (this.shape instanceof ORYX.Core.Edge) {
  16942. this.plugin.facade.getCanvas().add(this.shape);
  16943. this.shape.dockers.first().setDockedShape(this.connectedShape);
  16944. this.shape.dockers.first().setReferencePoint(this.sourceRefPos);
  16945. }
  16946. resume = true;
  16947. }
  16948. else {
  16949. this.shape = this.plugin.facade.createShape(this.option);
  16950. this.edge = (!(this.shape instanceof ORYX.Core.Edge)) ? this.shape.getIncomingShapes().first() : undefined;
  16951. }
  16952. if (this.currentReference && this.position) {
  16953. if (this.shape instanceof ORYX.Core.Edge) {
  16954. if (!(this.currentReference instanceof ORYX.Core.Canvas)) {
  16955. this.shape.dockers.last().setDockedShape(this.currentReference);
  16956. // @deprecated It now uses simply the midpoint
  16957. var upL = this.currentReference.absoluteXY();
  16958. var refPos = {
  16959. x: this.position.x - upL.x,
  16960. y: this.position.y - upL.y
  16961. };
  16962. this.shape.dockers.last().setReferencePoint(this.currentReference.bounds.midPoint());
  16963. }
  16964. else {
  16965. this.shape.dockers.last().bounds.centerMoveTo(this.position);
  16966. //this.shape.dockers.last().update();
  16967. }
  16968. this.sourceRefPos = this.shape.dockers.first().referencePoint;
  16969. this.targetRefPos = this.shape.dockers.last().referencePoint;
  16970. } else if (this.edge){
  16971. this.sourceRefPos = this.edge.dockers.first().referencePoint;
  16972. this.targetRefPos = this.edge.dockers.last().referencePoint;
  16973. }
  16974. } else {
  16975. var containedStencil = this.containedStencil;
  16976. var connectedShape = this.connectedShape;
  16977. var bc = connectedShape.bounds;
  16978. var bs = this.shape.bounds;
  16979. var pos = bc.center();
  16980. if(containedStencil.defaultAlign()==="north") {
  16981. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2);
  16982. } else if(containedStencil.defaultAlign()==="northeast") {
  16983. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  16984. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  16985. } else if(containedStencil.defaultAlign()==="southeast") {
  16986. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  16987. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  16988. } else if(containedStencil.defaultAlign()==="south") {
  16989. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.height()/2);
  16990. } else if(containedStencil.defaultAlign()==="southwest") {
  16991. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  16992. pos.y += (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  16993. } else if(containedStencil.defaultAlign()==="west") {
  16994. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2);
  16995. } else if(containedStencil.defaultAlign()==="northwest") {
  16996. pos.x -= (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.width()/2);
  16997. pos.y -= (bc.height() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET_CORNER + (bs.height()/2);
  16998. } else {
  16999. pos.x += (bc.width() / 2) + ORYX.CONFIG.SHAPEMENU_CREATE_OFFSET + (bs.width()/2);
  17000. }
  17001. // Move shape to the new position
  17002. this.shape.bounds.centerMoveTo(pos);
  17003. // Move all dockers of a node to the position
  17004. if (this.shape instanceof ORYX.Core.Node){
  17005. (this.shape.dockers||[]).each(function(docker){
  17006. docker.bounds.centerMoveTo(pos);
  17007. })
  17008. }
  17009. //this.shape.update();
  17010. this.position = pos;
  17011. if (this.edge){
  17012. this.sourceRefPos = this.edge.dockers.first().referencePoint;
  17013. this.targetRefPos = this.edge.dockers.last().referencePoint;
  17014. }
  17015. }
  17016. this.plugin.facade.getCanvas().update();
  17017. this.plugin.facade.updateSelection();
  17018. if (!resume) {
  17019. // If there is a connected shape
  17020. if (this.edge){
  17021. // Try to layout it
  17022. this.plugin.doLayout(this.edge);
  17023. } else if (this.shape instanceof ORYX.Core.Edge){
  17024. // Try to layout it
  17025. this.plugin.doLayout(this.shape);
  17026. }
  17027. }
  17028. },
  17029. rollback: function(){
  17030. this.plugin.facade.deleteShape(this.shape);
  17031. if(this.edge) {
  17032. this.plugin.facade.deleteShape(this.edge);
  17033. }
  17034. //this.currentParent.update();
  17035. this.plugin.facade.setSelection(this.plugin.facade.getSelection().without(this.shape, this.edge));
  17036. }
  17037. });/**
  17038. * Copyright (c) 2006
  17039. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  17040. *
  17041. * Permission is hereby granted, free of charge, to any person obtaining a
  17042. * copy of this software and associated documentation files (the "Software"),
  17043. * to deal in the Software without restriction, including without limitation
  17044. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17045. * and/or sell copies of the Software, and to permit persons to whom the
  17046. * Software is furnished to do so, subject to the following conditions:
  17047. *
  17048. * The above copyright notice and this permission notice shall be included in
  17049. * all copies or substantial portions of the Software.
  17050. *
  17051. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17052. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17053. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17054. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17055. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17056. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17057. * DEALINGS IN THE SOFTWARE.
  17058. **/
  17059. if (!ORYX.Plugins) {
  17060. ORYX.Plugins = new Object();
  17061. }
  17062. ORYX.Plugins.ShapeRepository = {
  17063. facade: undefined,
  17064. construct: function(facade) {
  17065. this.facade = facade;
  17066. this._currentParent;
  17067. this._canContain = undefined;
  17068. this._canAttach = undefined;
  17069. this.shapeList = new Ext.tree.TreeNode({
  17070. });
  17071. var panel = new Ext.tree.TreePanel({
  17072. cls:'shaperepository',
  17073. loader: new Ext.tree.TreeLoader(),
  17074. root: this.shapeList,
  17075. autoScroll:true,
  17076. rootVisible: false,
  17077. lines: false,
  17078. anchors: '0, -30'
  17079. });
  17080. var region = this.facade.addToRegion("west", panel, ORYX.I18N.ShapeRepository.title);
  17081. // Create a Drag-Zone for Drag'n'Drop
  17082. var DragZone = new Ext.dd.DragZone(this.shapeList.getUI().getEl(), {shadow: !Ext.isMac});
  17083. DragZone.afterDragDrop = this.drop.bind(this, DragZone);
  17084. DragZone.beforeDragOver = this.beforeDragOver.bind(this, DragZone);
  17085. DragZone.beforeDragEnter = function(){this._lastOverElement = false; return true}.bind(this);
  17086. // Load all Stencilssets
  17087. this.setStencilSets();
  17088. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_STENCIL_SET_LOADED, this.setStencilSets.bind(this));
  17089. },
  17090. /**
  17091. * Load all stencilsets in the shaperepository
  17092. */
  17093. setStencilSets: function() {
  17094. // Remove all childs
  17095. var child = this.shapeList.firstChild;
  17096. while(child) {
  17097. this.shapeList.removeChild(child);
  17098. child = this.shapeList.firstChild;
  17099. }
  17100. ORYX.Log.info("stencilsets " + this.facade.getStencilSets());
  17101. // Go thru all Stencilsets and stencils
  17102. this.facade.getStencilSets().values().each((function(sset) {
  17103. // For each Stencilset create and add a new Tree-Node
  17104. var stencilSetNode;
  17105. var typeTitle = sset.title();
  17106. this.shapeList.appendChild(stencilSetNode = new Ext.tree.TreeNode({
  17107. text:typeTitle, // Stencilset Name
  17108. allowDrag:false,
  17109. allowDrop:false,
  17110. iconCls:'headerShapeRepImg',
  17111. cls:'headerShapeRep',
  17112. singleClickExpand:true}));
  17113. ORYX.Log.info("stencilSetNode " + stencilSetNode.text);
  17114. this.shapeList.appendChild(stencilSetNode);
  17115. stencilSetNode.render();
  17116. stencilSetNode.expand();
  17117. // Get Stencils from Stencilset
  17118. var stencils = sset.stencils(this.facade.getCanvas().getStencil(),
  17119. this.facade.getRules());
  17120. var treeGroups = new Hash();
  17121. // Sort the stencils according to their position and add them to the repository
  17122. stencils = stencils.sortBy(function(value) { return value.position(); } );
  17123. stencils.each((function(value) {
  17124. // Show stencils in no group if there is less than 10 shapes
  17125. //if(stencils.length <= ORYX.CONFIG.MAX_NUM_SHAPES_NO_GROUP) {
  17126. // this.createStencilTreeNode(stencilSetNode, value);
  17127. // return;
  17128. //}
  17129. // Get the groups name
  17130. var groups = value.groups();
  17131. // For each Group-Entree
  17132. groups.each((function(group) {
  17133. // If there is a new group
  17134. if(!treeGroups[group]) {
  17135. // Create a new group
  17136. treeGroups[group] = new Ext.tree.TreeNode({
  17137. text:group, // Group-Name
  17138. allowDrag:false,
  17139. allowDrop:false,
  17140. iconCls:'headerShapeRepImg', // Css-Class for Icon
  17141. cls:'headerShapeRepChild', // CSS-Class for Stencil-Group
  17142. singleClickExpand:true});
  17143. // Add the Group to the ShapeRepository
  17144. stencilSetNode.appendChild(treeGroups[group]);
  17145. treeGroups[group].render();
  17146. }
  17147. // Create the Stencil-Tree-Node
  17148. this.createStencilTreeNode(treeGroups[group], value);
  17149. }).bind(this));
  17150. // If there is no group
  17151. if(groups.length == 0) {
  17152. // Create the Stencil-Tree-Node
  17153. this.createStencilTreeNode(stencilSetNode, value);
  17154. }
  17155. }).bind(this));
  17156. }).bind(this));
  17157. },
  17158. createStencilTreeNode: function(parentTreeNode, stencil) {
  17159. // Create and add the Stencil to the Group
  17160. var newElement = new Ext.tree.TreeNode({
  17161. text: stencil.title(), // Text of the stencil
  17162. icon: stencil.icon(), // Icon of the stencil
  17163. allowDrag: false, // Don't use the Drag and Drop of Ext-Tree
  17164. allowDrop: false,
  17165. iconCls: 'ShapeRepEntreeImg', // CSS-Class for Icon
  17166. cls: 'ShapeRepEntree' // CSS-Class for the Tree-Entree
  17167. });
  17168. parentTreeNode.appendChild(newElement);
  17169. newElement.render();
  17170. var ui = newElement.getUI();
  17171. // Set the tooltip
  17172. ui.elNode.setAttributeNS(null, "title", stencil.description());
  17173. // Register the Stencil on Drag and Drop
  17174. Ext.dd.Registry.register(ui.elNode, {
  17175. node: ui.node,
  17176. handles: [ui.elNode, ui.textNode].concat($A(ui.elNode.childNodes)), // Set the Handles
  17177. isHandle: false,
  17178. type: stencil.id(), // Set Type of stencil
  17179. namespace: stencil.namespace() // Set Namespace of stencil
  17180. });
  17181. },
  17182. drop: function(dragZone, target, event) {
  17183. this._lastOverElement = undefined;
  17184. // Hide the highlighting
  17185. this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'shapeRepo.added'});
  17186. this.facade.raiseEvent({type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'shapeRepo.attached'});
  17187. // Check if drop is allowed
  17188. var proxy = dragZone.getProxy()
  17189. if(proxy.dropStatus == proxy.dropNotAllowed) { return }
  17190. // Check if there is a current Parent
  17191. if(!this._currentParent) { return }
  17192. var option = Ext.dd.Registry.getHandle(target.DDM.currentTarget);
  17193. var xy = event.getXY();
  17194. var pos = {x: xy[0], y: xy[1]};
  17195. var a = this.facade.getCanvas().node.getScreenCTM();
  17196. // Correcting the UpperLeft-Offset
  17197. pos.x -= a.e; pos.y -= a.f;
  17198. // Correcting the Zoom-Faktor
  17199. pos.x /= a.a; pos.y /= a.d;
  17200. // Correting the ScrollOffset
  17201. pos.x -= document.documentElement.scrollLeft;
  17202. pos.y -= document.documentElement.scrollTop;
  17203. // Correct position of parent
  17204. var parentAbs = this._currentParent.absoluteXY();
  17205. pos.x -= parentAbs.x;
  17206. pos.y -= parentAbs.y;
  17207. // Set position
  17208. option['position'] = pos
  17209. // Set parent
  17210. if( this._canAttach && this._currentParent instanceof ORYX.Core.Node ){
  17211. option['parent'] = undefined;
  17212. } else {
  17213. option['parent'] = this._currentParent;
  17214. }
  17215. var commandClass = ORYX.Core.Command.extend({
  17216. construct: function(option, currentParent, canAttach, position, facade){
  17217. this.option = option;
  17218. this.currentParent = currentParent;
  17219. this.canAttach = canAttach;
  17220. this.position = position;
  17221. this.facade = facade;
  17222. this.selection = this.facade.getSelection();
  17223. this.shape;
  17224. this.parent;
  17225. },
  17226. execute: function(){
  17227. if (!this.shape) {
  17228. this.shape = this.facade.createShape(option);
  17229. this.parent = this.shape.parent;
  17230. } else {
  17231. this.parent.add(this.shape);
  17232. }
  17233. if( this.canAttach && this.currentParent instanceof ORYX.Core.Node && this.shape.dockers.length > 0){
  17234. var docker = this.shape.dockers[0];
  17235. if( this.currentParent.parent instanceof ORYX.Core.Node ) {
  17236. this.currentParent.parent.add( docker.parent );
  17237. }
  17238. docker.bounds.centerMoveTo( this.position );
  17239. docker.setDockedShape( this.currentParent );
  17240. //docker.update();
  17241. }
  17242. //this.currentParent.update();
  17243. //this.shape.update();
  17244. this.facade.setSelection([this.shape]);
  17245. this.facade.getCanvas().update();
  17246. this.facade.updateSelection();
  17247. },
  17248. rollback: function(){
  17249. this.facade.deleteShape(this.shape);
  17250. //this.currentParent.update();
  17251. this.facade.setSelection(this.selection.without(this.shape));
  17252. this.facade.getCanvas().update();
  17253. this.facade.updateSelection();
  17254. }
  17255. });
  17256. var position = this.facade.eventCoordinates( event.browserEvent );
  17257. var command = new commandClass(option, this._currentParent, this._canAttach, position, this.facade);
  17258. this.facade.executeCommands([command]);
  17259. this._currentParent = undefined;
  17260. },
  17261. beforeDragOver: function(dragZone, target, event){
  17262. var coord = this.facade.eventCoordinates(event.browserEvent);
  17263. var aShapes = this.facade.getCanvas().getAbstractShapesAtPosition( coord );
  17264. if(aShapes.length <= 0) {
  17265. var pr = dragZone.getProxy();
  17266. pr.setStatus(pr.dropNotAllowed);
  17267. pr.sync();
  17268. return false;
  17269. }
  17270. var el = aShapes.last();
  17271. if(aShapes.lenght == 1 && aShapes[0] instanceof ORYX.Core.Canvas) {
  17272. return false;
  17273. } else {
  17274. // check containment rules
  17275. var option = Ext.dd.Registry.getHandle(target.DDM.currentTarget);
  17276. var stencilSet = this.facade.getStencilSets()[option.namespace];
  17277. var stencil = stencilSet.stencil(option.type);
  17278. if(stencil.type() === "node") {
  17279. var parentCandidate = aShapes.reverse().find(function(candidate) {
  17280. return (candidate instanceof ORYX.Core.Canvas
  17281. || candidate instanceof ORYX.Core.Node
  17282. || candidate instanceof ORYX.Core.Edge);
  17283. });
  17284. if( parentCandidate !== this._lastOverElement){
  17285. this._canAttach = undefined;
  17286. this._canContain = undefined;
  17287. }
  17288. if( parentCandidate ) {
  17289. //check containment rule
  17290. if (!(parentCandidate instanceof ORYX.Core.Canvas) && parentCandidate.isPointOverOffset(coord.x, coord.y) && this._canAttach == undefined) {
  17291. this._canAttach = this.facade.getRules().canConnect({
  17292. sourceShape: parentCandidate,
  17293. edgeStencil: stencil,
  17294. targetStencil: stencil
  17295. });
  17296. if( this._canAttach ){
  17297. // Show Highlight
  17298. this.facade.raiseEvent({
  17299. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  17300. highlightId: "shapeRepo.attached",
  17301. elements: [parentCandidate],
  17302. style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE,
  17303. color: ORYX.CONFIG.SELECTION_VALID_COLOR
  17304. });
  17305. this.facade.raiseEvent({
  17306. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  17307. highlightId: "shapeRepo.added"
  17308. });
  17309. this._canContain = undefined;
  17310. }
  17311. }
  17312. if(!(parentCandidate instanceof ORYX.Core.Canvas) && !parentCandidate.isPointOverOffset(coord.x, coord.y)){
  17313. this._canAttach = this._canAttach == false ? this._canAttach : undefined;
  17314. }
  17315. if( this._canContain == undefined && !this._canAttach) {
  17316. this._canContain = this.facade.getRules().canContain({
  17317. containingShape:parentCandidate,
  17318. containedStencil:stencil
  17319. });
  17320. // Show Highlight
  17321. this.facade.raiseEvent({
  17322. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  17323. highlightId:'shapeRepo.added',
  17324. elements: [parentCandidate],
  17325. color: this._canContain ? ORYX.CONFIG.SELECTION_VALID_COLOR : ORYX.CONFIG.SELECTION_INVALID_COLOR
  17326. });
  17327. this.facade.raiseEvent({
  17328. type: ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  17329. highlightId:"shapeRepo.attached"
  17330. });
  17331. }
  17332. this._currentParent = this._canContain || this._canAttach ? parentCandidate : undefined;
  17333. this._lastOverElement = parentCandidate;
  17334. var pr = dragZone.getProxy();
  17335. pr.setStatus(this._currentParent ? pr.dropAllowed : pr.dropNotAllowed );
  17336. pr.sync();
  17337. }
  17338. } else { //Edge
  17339. this._currentParent = this.facade.getCanvas();
  17340. var pr = dragZone.getProxy();
  17341. pr.setStatus(pr.dropAllowed);
  17342. pr.sync();
  17343. }
  17344. }
  17345. return false
  17346. }
  17347. }
  17348. ORYX.Plugins.ShapeRepository = Clazz.extend(ORYX.Plugins.ShapeRepository);
  17349. /**
  17350. * Copyright (c) 2006
  17351. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  17352. *
  17353. * Permission is hereby granted, free of charge, to any person obtaining a
  17354. * copy of this software and associated documentation files (the "Software"),
  17355. * to deal in the Software without restriction, including without limitation
  17356. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  17357. * and/or sell copies of the Software, and to permit persons to whom the
  17358. * Software is furnished to do so, subject to the following conditions:
  17359. *
  17360. * The above copyright notice and this permission notice shall be included in
  17361. * all copies or substantial portions of the Software.
  17362. *
  17363. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17364. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17365. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17366. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17367. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  17368. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17369. * DEALINGS IN THE SOFTWARE.
  17370. **/
  17371. if(!ORYX.Plugins) {
  17372. ORYX.Plugins = new Object();
  17373. }
  17374. ORYX.Plugins.PropertyWindow = {
  17375. facade: undefined,
  17376. construct: function(facade) {
  17377. // Reference to the Editor-Interface
  17378. this.facade = facade;
  17379. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SHOW_PROPERTYWINDOW, this.init.bind(this));
  17380. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.selectDiagram.bind(this));
  17381. this.init();
  17382. },
  17383. init: function(){
  17384. // The parent div-node of the grid
  17385. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml",
  17386. null,
  17387. ['div']);
  17388. // If the current property in focus is of type 'Date', the date format
  17389. // is stored here.
  17390. this.currentDateFormat;
  17391. // the properties array
  17392. this.popularProperties = [];
  17393. this.properties = [];
  17394. /* The currently selected shapes whos properties will shown */
  17395. this.shapeSelection = new Hash();
  17396. this.shapeSelection.shapes = new Array();
  17397. this.shapeSelection.commonProperties = new Array();
  17398. this.shapeSelection.commonPropertiesValues = new Hash();
  17399. this.updaterFlag = false;
  17400. // creating the column model of the grid.
  17401. this.columnModel = new Ext.grid.ColumnModel([
  17402. {
  17403. //id: 'name',
  17404. header: ORYX.I18N.PropertyWindow.name,
  17405. dataIndex: 'name',
  17406. width: 90,
  17407. sortable: true,
  17408. renderer: this.tooltipRenderer.bind(this)
  17409. }, {
  17410. //id: 'value',
  17411. header: ORYX.I18N.PropertyWindow.value,
  17412. dataIndex: 'value',
  17413. id: 'propertywindow_column_value',
  17414. width: 110,
  17415. editor: new Ext.form.TextField({
  17416. allowBlank: false
  17417. }),
  17418. renderer: this.renderer.bind(this)
  17419. },
  17420. {
  17421. header: "Pop",
  17422. dataIndex: 'popular',
  17423. hidden: true,
  17424. sortable: true
  17425. }
  17426. ]);
  17427. // creating the store for the model.
  17428. this.dataSource = new Ext.data.GroupingStore({
  17429. proxy: new Ext.data.MemoryProxy(this.properties),
  17430. reader: new Ext.data.ArrayReader({}, [
  17431. {name: 'popular'},
  17432. {name: 'name'},
  17433. {name: 'value'},
  17434. {name: 'icons'},
  17435. {name: 'gridProperties'}
  17436. ]),
  17437. sortInfo: {field: 'popular', direction: "ASC"},
  17438. sortData : function(f, direction){
  17439. direction = direction || 'ASC';
  17440. var st = this.fields.get(f).sortType;
  17441. var fn = function(r1, r2){
  17442. var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
  17443. var p1 = r1.data['popular'], p2 = r2.data['popular'];
  17444. return p1 && !p2 ? -1 : (!p1 && p2 ? 1 : (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0)));
  17445. };
  17446. this.data.sort(direction, fn);
  17447. if(this.snapshot && this.snapshot != this.data){
  17448. this.snapshot.sort(direction, fn);
  17449. }
  17450. },
  17451. groupField: 'popular'
  17452. });
  17453. this.dataSource.load();
  17454. this.grid = new Ext.grid.EditorGridPanel({
  17455. clicksToEdit: 1,
  17456. stripeRows: true,
  17457. autoExpandColumn: "propertywindow_column_value",
  17458. width:'auto',
  17459. // the column model
  17460. colModel: this.columnModel,
  17461. enableHdMenu: false,
  17462. view: new Ext.grid.GroupingView({
  17463. forceFit: true,
  17464. groupTextTpl: '{[values.rs.first().data.popular ? ORYX.I18N.PropertyWindow.oftenUsed : ORYX.I18N.PropertyWindow.moreProps]}'
  17465. }),
  17466. // the data store
  17467. store: this.dataSource
  17468. });
  17469. region = this.facade.addToRegion('east', new Ext.Panel({
  17470. width: 220,
  17471. layout: "fit",
  17472. border: false,
  17473. title: 'Properties',
  17474. items: [
  17475. this.grid
  17476. ]
  17477. }), ORYX.I18N.PropertyWindow.title)
  17478. // Register on Events
  17479. this.grid.on('beforeedit', this.beforeEdit, this, true);
  17480. this.grid.on('afteredit', this.afterEdit, this, true);
  17481. this.grid.view.on('refresh', this.hideMoreAttrs, this, true);
  17482. //this.grid.on(ORYX.CONFIG.EVENT_KEYDOWN, this.keyDown, this, true);
  17483. // Renderer the Grid
  17484. this.grid.enableColumnMove = false;
  17485. //this.grid.render();
  17486. // Sort as Default the first column
  17487. //this.dataSource.sort('name');
  17488. },
  17489. // Select the Canvas when the editor is ready
  17490. selectDiagram: function() {
  17491. this.shapeSelection.shapes = [this.facade.getCanvas()];
  17492. this.setPropertyWindowTitle();
  17493. this.identifyCommonProperties();
  17494. this.createProperties();
  17495. },
  17496. specialKeyDown: function(field, event) {
  17497. // If there is a TextArea and the Key is an Enter
  17498. if(field instanceof Ext.form.TextArea && event.button == ORYX.CONFIG.KEY_Code_enter) {
  17499. // Abort the Event
  17500. return false
  17501. }
  17502. },
  17503. tooltipRenderer: function(value, p, record) {
  17504. /* Prepare tooltip */
  17505. p.cellAttr = 'title="' + record.data.gridProperties.tooltip + '"';
  17506. return value;
  17507. },
  17508. renderer: function(value, p, record) {
  17509. this.tooltipRenderer(value, p, record);
  17510. if(value instanceof Date) {
  17511. // TODO: Date-Schema is not generic
  17512. value = value.dateFormat(ORYX.I18N.PropertyWindow.dateFormat);
  17513. } else if(String(value).search("<a href='") < 0) {
  17514. // Shows the Value in the Grid in each Line
  17515. value = String(value).gsub("<", "&lt;");
  17516. value = String(value).gsub(">", "&gt;");
  17517. value = String(value).gsub("%", "&#37;");
  17518. value = String(value).gsub("&", "&amp;");
  17519. if(record.data.gridProperties.type == ORYX.CONFIG.TYPE_COLOR) {
  17520. value = "<div class='prop-background-color' style='background-color:" + value + "' />";
  17521. }
  17522. record.data.icons.each(function(each) {
  17523. if(each.name == value) {
  17524. if(each.icon) {
  17525. value = "<img src='" + each.icon + "' /> " + value;
  17526. }
  17527. }
  17528. });
  17529. }
  17530. return value;
  17531. },
  17532. beforeEdit: function(option) {
  17533. var editorGrid = this.dataSource.getAt(option.row).data.gridProperties.editor;
  17534. var editorRenderer = this.dataSource.getAt(option.row).data.gridProperties.renderer;
  17535. if(editorGrid) {
  17536. // Disable KeyDown
  17537. this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  17538. option.grid.getColumnModel().setEditor(1, editorGrid);
  17539. editorGrid.field.row = option.row;
  17540. // Render the editor to the grid, therefore the editor is also available
  17541. // for the first and last row
  17542. editorGrid.render(this.grid);
  17543. //option.grid.getColumnModel().setRenderer(1, editorRenderer);
  17544. editorGrid.setSize(option.grid.getColumnModel().getColumnWidth(1), editorGrid.height);
  17545. } else {
  17546. return false;
  17547. }
  17548. var key = this.dataSource.getAt(option.row).data.gridProperties.propId;
  17549. this.oldValues = new Hash();
  17550. this.shapeSelection.shapes.each(function(shape){
  17551. this.oldValues[shape.getId()] = shape.properties[key];
  17552. }.bind(this));
  17553. },
  17554. afterEdit: function(option) {
  17555. //Ext1.0: option.grid.getDataSource().commitChanges();
  17556. option.grid.getStore().commitChanges();
  17557. var key = option.record.data.gridProperties.propId;
  17558. var selectedElements = this.shapeSelection.shapes;
  17559. var oldValues = this.oldValues;
  17560. var newValue = option.value;
  17561. var facade = this.facade;
  17562. // Implement the specific command for property change
  17563. var commandClass = ORYX.Core.Command.extend({
  17564. construct: function(){
  17565. this.key = key;
  17566. this.selectedElements = selectedElements;
  17567. this.oldValues = oldValues;
  17568. this.newValue = newValue;
  17569. this.facade = facade;
  17570. },
  17571. execute: function(){
  17572. this.selectedElements.each(function(shape){
  17573. if(!shape.getStencil().property(this.key).readonly()) {
  17574. shape.setProperty(this.key, this.newValue);
  17575. }
  17576. }.bind(this));
  17577. this.facade.setSelection(this.selectedElements);
  17578. this.facade.getCanvas().update();
  17579. this.facade.updateSelection();
  17580. },
  17581. rollback: function(){
  17582. this.selectedElements.each(function(shape){
  17583. shape.setProperty(this.key, this.oldValues[shape.getId()]);
  17584. }.bind(this));
  17585. this.facade.setSelection(this.selectedElements);
  17586. this.facade.getCanvas().update();
  17587. this.facade.updateSelection();
  17588. }
  17589. })
  17590. // Instanciated the class
  17591. var command = new commandClass();
  17592. // Execute the command
  17593. this.facade.executeCommands([command]);
  17594. // extended by Kerstin (start)
  17595. //
  17596. this.facade.raiseEvent({
  17597. type : ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED,
  17598. elements : selectedElements,
  17599. key : key,
  17600. value : option.value
  17601. });
  17602. // extended by Kerstin (end)
  17603. },
  17604. // Changes made in the property window will be shown directly
  17605. editDirectly:function(key, value){
  17606. this.shapeSelection.shapes.each(function(shape){
  17607. if(!shape.getStencil().property(key).readonly()) {
  17608. shape.setProperty(key, value);
  17609. //shape.update();
  17610. }
  17611. }.bind(this));
  17612. /* Propagate changed properties */
  17613. var selectedElements = this.shapeSelection.shapes;
  17614. this.facade.raiseEvent({
  17615. type : ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED,
  17616. elements : selectedElements,
  17617. key : key,
  17618. value : value
  17619. });
  17620. this.facade.getCanvas().update();
  17621. },
  17622. // if a field becomes invalid after editing the shape must be restored to the old value
  17623. updateAfterInvalid : function(key) {
  17624. this.shapeSelection.shapes.each(function(shape) {
  17625. if(!shape.getStencil().property(key).readonly()) {
  17626. shape.setProperty(key, this.oldValues[shape.getId()]);
  17627. shape.update();
  17628. }
  17629. }.bind(this));
  17630. this.facade.getCanvas().update();
  17631. },
  17632. // extended by Kerstin (start)
  17633. dialogClosed: function(data) {
  17634. var row = this.field ? this.field.row : this.row
  17635. this.scope.afterEdit({
  17636. grid:this.scope.grid,
  17637. record:this.scope.grid.getStore().getAt(row),
  17638. //value:this.scope.grid.getStore().getAt(this.row).get("value")
  17639. value: data
  17640. })
  17641. // reopen the text field of the complex list field again
  17642. this.scope.grid.startEditing(row, this.col);
  17643. },
  17644. // extended by Kerstin (end)
  17645. /**
  17646. * Changes the title of the property window panel according to the selected shapes.
  17647. */
  17648. setPropertyWindowTitle: function() {
  17649. if(this.shapeSelection.shapes.length == 1) {
  17650. // add the name of the stencil of the selected shape to the title
  17651. region.setTitle(ORYX.I18N.PropertyWindow.title +' ('+this.shapeSelection.shapes.first().getStencil().title()+')' );
  17652. } else {
  17653. region.setTitle(ORYX.I18N.PropertyWindow.title +' ('
  17654. + this.shapeSelection.shapes.length
  17655. + ' '
  17656. + ORYX.I18N.PropertyWindow.selected
  17657. +')');
  17658. }
  17659. },
  17660. /**
  17661. * Sets this.shapeSelection.commonPropertiesValues.
  17662. * If the value for a common property is not equal for each shape the value
  17663. * is left empty in the property window.
  17664. */
  17665. setCommonPropertiesValues: function() {
  17666. this.shapeSelection.commonPropertiesValues = new Hash();
  17667. this.shapeSelection.commonProperties.each(function(property){
  17668. var key = property.prefix() + "-" + property.id();
  17669. var emptyValue = false;
  17670. var firstShape = this.shapeSelection.shapes.first();
  17671. this.shapeSelection.shapes.each(function(shape){
  17672. if(firstShape.properties[key] != shape.properties[key]) {
  17673. emptyValue = true;
  17674. }
  17675. }.bind(this));
  17676. /* Set property value */
  17677. if(!emptyValue) {
  17678. this.shapeSelection.commonPropertiesValues[key]
  17679. = firstShape.properties[key];
  17680. }
  17681. }.bind(this));
  17682. },
  17683. /**
  17684. * Returns the set of stencils used by the passed shapes.
  17685. */
  17686. getStencilSetOfSelection: function() {
  17687. var stencils = new Hash();
  17688. this.shapeSelection.shapes.each(function(shape) {
  17689. stencils[shape.getStencil().id()] = shape.getStencil();
  17690. })
  17691. return stencils;
  17692. },
  17693. /**
  17694. * Identifies the common Properties of the selected shapes.
  17695. */
  17696. identifyCommonProperties: function() {
  17697. this.shapeSelection.commonProperties.clear();
  17698. /*
  17699. * A common property is a property, that is part of
  17700. * the stencil definition of the first and all other stencils.
  17701. */
  17702. var stencils = this.getStencilSetOfSelection();
  17703. var firstStencil = stencils.values().first();
  17704. var comparingStencils = stencils.values().without(firstStencil);
  17705. if(comparingStencils.length == 0) {
  17706. this.shapeSelection.commonProperties = firstStencil.properties();
  17707. } else {
  17708. var properties = new Hash();
  17709. /* put all properties of on stencil in a Hash */
  17710. firstStencil.properties().each(function(property){
  17711. properties[property.namespace() + '-' + property.id()
  17712. + '-' + property.type()] = property;
  17713. });
  17714. /* Calculate intersection of properties. */
  17715. comparingStencils.each(function(stencil){
  17716. var intersection = new Hash();
  17717. stencil.properties().each(function(property){
  17718. if(properties[property.namespace() + '-' + property.id()
  17719. + '-' + property.type()]){
  17720. intersection[property.namespace() + '-' + property.id()
  17721. + '-' + property.type()] = property;
  17722. }
  17723. });
  17724. properties = intersection;
  17725. });
  17726. this.shapeSelection.commonProperties = properties.values();
  17727. }
  17728. },
  17729. onSelectionChanged: function(event) {
  17730. /* Event to call afterEdit method */
  17731. this.grid.stopEditing();
  17732. /* Selected shapes */
  17733. this.shapeSelection.shapes = event.elements;
  17734. /* Case: nothing selected */
  17735. if(event.elements.length == 0) {
  17736. this.shapeSelection.shapes = [this.facade.getCanvas()];
  17737. }
  17738. /* subselection available */
  17739. if(event.subSelection){
  17740. this.shapeSelection.shapes = [event.subSelection];
  17741. }
  17742. this.setPropertyWindowTitle();
  17743. this.identifyCommonProperties();
  17744. this.setCommonPropertiesValues();
  17745. // Create the Properties
  17746. this.createProperties();
  17747. },
  17748. /**
  17749. * Creates the properties for the ExtJS-Grid from the properties of the
  17750. * selected shapes.
  17751. */
  17752. createProperties: function() {
  17753. this.properties = [];
  17754. this.popularProperties = [];
  17755. if(this.shapeSelection.commonProperties) {
  17756. // add new property lines
  17757. this.shapeSelection.commonProperties.each((function(pair, index) {
  17758. var key = pair.prefix() + "-" + pair.id();
  17759. // Get the property pair
  17760. var name = pair.title();
  17761. var icons = [];
  17762. var attribute = this.shapeSelection.commonPropertiesValues[key];
  17763. var editorGrid = undefined;
  17764. var editorRenderer = null;
  17765. if(!pair.readonly()){
  17766. switch(pair.type()) {
  17767. case ORYX.CONFIG.TYPE_STRING:
  17768. // If the Text is MultiLine
  17769. if(pair.wrapLines()) {
  17770. // Set the Editor as TextArea
  17771. var editorTextArea = new Ext.form.TextArea({alignment: "tl-tl", allowBlank: pair.optional(), msgTarget:'title', maxLength:pair.length()});
  17772. editorTextArea.on('keyup', function(textArea, event) {
  17773. this.editDirectly(key, textArea.getValue());
  17774. }.bind(this));
  17775. editorGrid = new Ext.Editor(editorTextArea);
  17776. } else {
  17777. // If not, set the Editor as InputField
  17778. var editorInput = new Ext.form.TextField({allowBlank: pair.optional(), msgTarget:'title', maxLength:pair.length()});
  17779. editorInput.on('keyup', function(input, event) {
  17780. this.editDirectly(key, input.getValue());
  17781. }.bind(this));
  17782. // reverts the shape if the editor field is invalid
  17783. editorInput.on('blur', function(input) {
  17784. if(!input.isValid(false))
  17785. this.updateAfterInvalid(key);
  17786. }.bind(this));
  17787. editorInput.on("specialkey", function(input, e) {
  17788. if(!input.isValid(false))
  17789. this.updateAfterInvalid(key);
  17790. }.bind(this));
  17791. editorGrid = new Ext.Editor(editorInput);
  17792. }
  17793. break;
  17794. case ORYX.CONFIG.TYPE_BOOLEAN:
  17795. // Set the Editor as a CheckBox
  17796. var editorCheckbox = new Ext.form.Checkbox();
  17797. editorCheckbox.on('check', function(c,checked) {
  17798. this.editDirectly(key, checked);
  17799. }.bind(this));
  17800. editorGrid = new Ext.Editor(editorCheckbox);
  17801. break;
  17802. case ORYX.CONFIG.TYPE_INTEGER:
  17803. // Set as an Editor for Integers
  17804. var numberField = new Ext.form.NumberField({allowBlank: pair.optional(), allowDecimals:false, msgTarget:'title', minValue: pair.min(), maxValue: pair.max()});
  17805. numberField.on('keyup', function(input, event) {
  17806. this.editDirectly(key, input.getValue());
  17807. }.bind(this));
  17808. editorGrid = new Ext.Editor(numberField);
  17809. break;
  17810. case ORYX.CONFIG.TYPE_FLOAT:
  17811. // Set as an Editor for Float
  17812. var numberField = new Ext.form.NumberField({ allowBlank: pair.optional(), allowDecimals:true, msgTarget:'title', minValue: pair.min(), maxValue: pair.max()});
  17813. numberField.on('keyup', function(input, event) {
  17814. this.editDirectly(key, input.getValue());
  17815. }.bind(this));
  17816. editorGrid = new Ext.Editor(numberField);
  17817. break;
  17818. case ORYX.CONFIG.TYPE_COLOR:
  17819. // Set as a ColorPicker
  17820. // Ext1.0 editorGrid = new gEdit(new form.ColorField({ allowBlank: pair.optional(), msgTarget:'title' }));
  17821. var editorPicker = new Ext.ux.ColorField({ allowBlank: pair.optional(), msgTarget:'title', facade: this.facade });
  17822. /*this.facade.registerOnEvent(ORYX.CONFIG.EVENT_COLOR_CHANGE, function(option) {
  17823. this.editDirectly(key, option.value);
  17824. }.bind(this));*/
  17825. editorGrid = new Ext.Editor(editorPicker);
  17826. break;
  17827. case ORYX.CONFIG.TYPE_CHOICE:
  17828. var items = pair.items();
  17829. var options = [];
  17830. items.each(function(value) {
  17831. if(value.value() == attribute)
  17832. attribute = value.title();
  17833. options.push([value.icon(), value.title(), value.value()]);
  17834. icons.push({
  17835. name: value.title(),
  17836. icon: value.icon()
  17837. });
  17838. });
  17839. var store = new Ext.data.SimpleStore({
  17840. fields: [{name: 'icon'},
  17841. {name: 'title'},
  17842. {name: 'value'} ],
  17843. data : options // from states.js
  17844. });
  17845. // Set the grid Editor
  17846. var editorCombo = new Ext.form.ComboBox({
  17847. tpl: '<tpl for="."><div class="x-combo-list-item">{[(values.icon) ? "<img src=\'" + values.icon + "\' />" : ""]} {title}</div></tpl>',
  17848. store: store,
  17849. displayField:'title',
  17850. valueField: 'value',
  17851. typeAhead: true,
  17852. mode: 'local',
  17853. triggerAction: 'all',
  17854. selectOnFocus:true
  17855. });
  17856. editorCombo.on('select', function(combo, record, index) {
  17857. this.editDirectly(key, combo.getValue());
  17858. }.bind(this))
  17859. editorGrid = new Ext.Editor(editorCombo);
  17860. break;
  17861. case ORYX.CONFIG.TYPE_DATE:
  17862. var currFormat = ORYX.I18N.PropertyWindow.dateFormat
  17863. if(!(attribute instanceof Date))
  17864. attribute = Date.parseDate(attribute, currFormat)
  17865. editorGrid = new Ext.Editor(new Ext.form.DateField({ allowBlank: pair.optional(), format:currFormat, msgTarget:'title'}));
  17866. break;
  17867. case ORYX.CONFIG.TYPE_TEXT:
  17868. var cf = new Ext.form.ComplexTextField({
  17869. allowBlank: pair.optional(),
  17870. dataSource:this.dataSource,
  17871. grid:this.grid,
  17872. row:index,
  17873. facade:this.facade
  17874. });
  17875. cf.on('dialogClosed', this.dialogClosed, {scope:this, row:index, col:1,field:cf});
  17876. editorGrid = new Ext.Editor(cf);
  17877. break;
  17878. case ORYX.CONFIG.TYPE_MODEL_LINK:
  17879. var cf = new Ext.form.ComplexModelLinkField({
  17880. allowBlank: pair.optional(),
  17881. dataSource:this.dataSource,
  17882. grid:this.grid,
  17883. row:index,
  17884. facade:this.facade
  17885. });
  17886. cf.on('dialogClosed', this.dialogClosed, {scope:this, row:index, col:1,field:cf});
  17887. editorGrid = new Ext.Editor(cf);
  17888. break;
  17889. case ORYX.CONFIG.TYPE_LISTENER:
  17890. var cf = new Ext.form.ListenerDefinitionField({
  17891. allowBlank: pair.optional(),
  17892. dataSource:this.dataSource,
  17893. grid:this.grid,
  17894. row:index,
  17895. facade:this.facade
  17896. });
  17897. cf.on('dialogClosed', this.dialogClosed, {scope:this, row:index, col:1,field:cf});
  17898. editorGrid = new Ext.Editor(cf);
  17899. break;
  17900. // extended by Kerstin (start)
  17901. case ORYX.CONFIG.TYPE_COMPLEX:
  17902. var cf = new Ext.form.ComplexListField({ allowBlank: pair.optional()}, pair.complexItems(), key, this.facade);
  17903. cf.on('dialogClosed', this.dialogClosed, {scope:this, row:index, col:1,field:cf});
  17904. editorGrid = new Ext.Editor(cf);
  17905. break;
  17906. // extended by Kerstin (end)
  17907. case ORYX.CONFIG.TYPE_MULTIPLECOMPLEX:
  17908. var cf = new Ext.form.MultipleComplexListField({ allowBlank: pair.optional()}, pair.complexItems(), key, this.facade);
  17909. cf.on('dialogClosed', this.dialogClosed, {scope:this, row:index, col:1,field:cf});
  17910. editorGrid = new Ext.Editor(cf);
  17911. break;
  17912. // extended by Gerardo (Start)
  17913. case "CPNString":
  17914. var editorInput = new Ext.form.TextField(
  17915. {
  17916. allowBlank: pair.optional(),
  17917. msgTarget:'title',
  17918. maxLength:pair.length(),
  17919. enableKeyEvents: true
  17920. });
  17921. editorInput.on('keyup', function(input, event) {
  17922. this.editDirectly(key, input.getValue());
  17923. console.log(input.getValue());
  17924. alert("huhu");
  17925. }.bind(this));
  17926. editorGrid = new Ext.Editor(editorInput);
  17927. break;
  17928. // extended by Gerardo (End)
  17929. default:
  17930. var editorInput = new Ext.form.TextField({ allowBlank: pair.optional(), msgTarget:'title', maxLength:pair.length(), enableKeyEvents: true});
  17931. editorInput.on('keyup', function(input, event) {
  17932. this.editDirectly(key, input.getValue());
  17933. }.bind(this));
  17934. editorGrid = new Ext.Editor(editorInput);
  17935. }
  17936. // Register Event to enable KeyDown
  17937. editorGrid.on('beforehide', this.facade.enableEvent.bind(this, ORYX.CONFIG.EVENT_KEYDOWN));
  17938. editorGrid.on('specialkey', this.specialKeyDown.bind(this));
  17939. } else if(pair.type() === ORYX.CONFIG.TYPE_URL || pair.type() === ORYX.CONFIG.TYPE_DIAGRAM_LINK){
  17940. attribute = String(attribute).search("http") !== 0 ? ("http://" + attribute) : attribute;
  17941. attribute = "<a href='" + attribute + "' target='_blank'>" + attribute.split("://")[1] + "</a>"
  17942. }
  17943. // Push to the properties-array
  17944. if(pair.visible()) {
  17945. // Popular Properties are those which are set to be popular
  17946. if (pair.popular()) {
  17947. pair.setPopular();
  17948. }
  17949. if(pair.popular()) {
  17950. this.popularProperties.push([pair.popular(), name, attribute, icons, {
  17951. editor: editorGrid,
  17952. propId: key,
  17953. type: pair.type(),
  17954. tooltip: pair.description(),
  17955. renderer: editorRenderer
  17956. }]);
  17957. }
  17958. else {
  17959. this.properties.push([pair.popular(), name, attribute, icons, {
  17960. editor: editorGrid,
  17961. propId: key,
  17962. type: pair.type(),
  17963. tooltip: pair.description(),
  17964. renderer: editorRenderer
  17965. }]);
  17966. }
  17967. }
  17968. }).bind(this));
  17969. }
  17970. this.setProperties();
  17971. },
  17972. hideMoreAttrs: function(panel) {
  17973. // TODO: Implement the case that the canvas has no attributes
  17974. if (this.properties.length <= 0){ return }
  17975. // collapse the "more attr" group
  17976. this.grid.view.toggleGroup(this.grid.view.getGroupId(this.properties[0][0]), false);
  17977. // prevent the more attributes pane from closing after a attribute has been edited
  17978. this.grid.view.un("refresh", this.hideMoreAttrs, this);
  17979. },
  17980. setProperties: function() {
  17981. var props = this.popularProperties.concat(this.properties);
  17982. this.dataSource.loadData(props);
  17983. }
  17984. }
  17985. ORYX.Plugins.PropertyWindow = Clazz.extend(ORYX.Plugins.PropertyWindow);
  17986. /**
  17987. * Editor for complex type
  17988. *
  17989. * When starting to edit the editor, it creates a new dialog where new attributes
  17990. * can be specified which generates json out of this and put this
  17991. * back to the input field.
  17992. *
  17993. * This is implemented from Kerstin Pfitzner
  17994. *
  17995. * @param {Object} config
  17996. * @param {Object} items
  17997. * @param {Object} key
  17998. * @param {Object} facade
  17999. */
  18000. Ext.form.ComplexListField = function(config, items, key, facade){
  18001. Ext.form.ComplexListField.superclass.constructor.call(this, config);
  18002. this.items = items;
  18003. this.key = key;
  18004. this.facade = facade;
  18005. };
  18006. /**
  18007. * This is a special trigger field used for complex properties.
  18008. * The trigger field opens a dialog that shows a list of properties.
  18009. * The entered values will be stored as trigger field value in the JSON format.
  18010. */
  18011. Ext.extend(Ext.form.ComplexListField, Ext.form.TriggerField, {
  18012. /**
  18013. * @cfg {String} triggerClass
  18014. * An additional CSS class used to style the trigger button. The trigger will always get the
  18015. * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified.
  18016. */
  18017. triggerClass: 'x-form-complex-trigger',
  18018. readOnly: true,
  18019. emptyText: ORYX.I18N.PropertyWindow.clickIcon,
  18020. /**
  18021. * Builds the JSON value from the data source of the grid in the dialog.
  18022. */
  18023. buildValue: function() {
  18024. var ds = this.grid.getStore();
  18025. ds.commitChanges();
  18026. if (ds.getCount() == 0) {
  18027. return "";
  18028. }
  18029. var jsonString = "[";
  18030. for (var i = 0; i < ds.getCount(); i++) {
  18031. var data = ds.getAt(i);
  18032. jsonString += "{";
  18033. for (var j = 0; j < this.items.length; j++) {
  18034. var key = this.items[j].id();
  18035. jsonString += key + ':' + ("" + data.get(key)).toJSON();
  18036. if (j < (this.items.length - 1)) {
  18037. jsonString += ", ";
  18038. }
  18039. }
  18040. jsonString += "}";
  18041. if (i < (ds.getCount() - 1)) {
  18042. jsonString += ", ";
  18043. }
  18044. }
  18045. jsonString += "]";
  18046. jsonString = "{'totalCount':" + ds.getCount().toJSON() +
  18047. ", 'items':" + jsonString + "}";
  18048. return Object.toJSON(jsonString.evalJSON());
  18049. },
  18050. /**
  18051. * Returns the field key.
  18052. */
  18053. getFieldKey: function() {
  18054. return this.key;
  18055. },
  18056. /**
  18057. * Returns the actual value of the trigger field.
  18058. * If the table does not contain any values the empty
  18059. * string will be returned.
  18060. */
  18061. getValue : function(){
  18062. // return actual value if grid is active
  18063. if (this.grid) {
  18064. return this.buildValue();
  18065. } else if (this.data == undefined) {
  18066. return "";
  18067. } else {
  18068. return this.data;
  18069. }
  18070. },
  18071. /**
  18072. * Sets the value of the trigger field.
  18073. * In this case this sets the data that will be shown in
  18074. * the grid of the dialog.
  18075. *
  18076. * @param {Object} value The value to be set (JSON format or empty string)
  18077. */
  18078. setValue: function(value) {
  18079. if (value.length > 0 && value.indexOf('<') == -1) {
  18080. // set only if this.data not set yet
  18081. // only to initialize the grid
  18082. if (this.data == undefined) {
  18083. this.data = value;
  18084. }
  18085. }
  18086. },
  18087. /**
  18088. * Returns false. In this way key events will not be propagated
  18089. * to other elements.
  18090. *
  18091. * @param {Object} event The keydown event.
  18092. */
  18093. keydownHandler: function(event) {
  18094. return false;
  18095. },
  18096. /**
  18097. * The listeners of the dialog.
  18098. *
  18099. * If the dialog is hidded, a dialogClosed event will be fired.
  18100. * This has to be used by the parent element of the trigger field
  18101. * to reenable the trigger field (focus gets lost when entering values
  18102. * in the dialog).
  18103. */
  18104. dialogListeners : {
  18105. show : function(){ // retain focus styling
  18106. this.onFocus();
  18107. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keydownHandler.bind(this));
  18108. this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  18109. return;
  18110. },
  18111. hide : function(){
  18112. var dl = this.dialogListeners;
  18113. this.dialog.un("show", dl.show, this);
  18114. this.dialog.un("hide", dl.hide, this);
  18115. this.dialog.destroy(true);
  18116. this.grid.destroy(true);
  18117. delete this.grid;
  18118. delete this.dialog;
  18119. this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keydownHandler.bind(this));
  18120. this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  18121. // store data and notify parent about the closed dialog
  18122. // parent has to handel this event and start editing the text field again
  18123. this.fireEvent('dialogClosed', this.data);
  18124. Ext.form.ComplexListField.superclass.setValue.call(this, this.data);
  18125. }
  18126. },
  18127. /**
  18128. * Builds up the initial values of the grid.
  18129. *
  18130. * @param {Object} recordType The record type of the grid.
  18131. * @param {Object} items The initial items of the grid (columns)
  18132. */
  18133. buildInitial: function(recordType, items) {
  18134. var initial = new Hash();
  18135. for (var i = 0; i < items.length; i++) {
  18136. var id = items[i].id();
  18137. initial[id] = items[i].value();
  18138. }
  18139. var RecordTemplate = Ext.data.Record.create(recordType);
  18140. return new RecordTemplate(initial);
  18141. },
  18142. /**
  18143. * Builds up the column model of the grid. The parent element of the
  18144. * grid.
  18145. *
  18146. * Sets up the editors for the grid columns depending on the
  18147. * type of the items.
  18148. *
  18149. * @param {Object} parent The
  18150. */
  18151. buildColumnModel: function(parent) {
  18152. var cols = [];
  18153. for (var i = 0; i < this.items.length; i++) {
  18154. var id = this.items[i].id();
  18155. var header = this.items[i].name();
  18156. var width = this.items[i].width();
  18157. var type = this.items[i].type();
  18158. var editor;
  18159. if (type == ORYX.CONFIG.TYPE_STRING) {
  18160. editor = new Ext.form.TextField({ allowBlank : this.items[i].optional(), width : width});
  18161. } else if (type == ORYX.CONFIG.TYPE_CHOICE) {
  18162. var items = this.items[i].items();
  18163. var select = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parent, ['select', {style:'display:none'}]);
  18164. var optionTmpl = new Ext.Template('<option value="{value}">{value}</option>');
  18165. items.each(function(value){
  18166. optionTmpl.append(select, {value:value.value()});
  18167. });
  18168. editor = new Ext.form.ComboBox(
  18169. { typeAhead: true, triggerAction: 'all', transform:select, lazyRender:true, msgTarget:'title', width : width});
  18170. } else if (type == ORYX.CONFIG.TYPE_BOOLEAN) {
  18171. editor = new Ext.form.Checkbox( { width : width } );
  18172. } else if (type == ORYX.CONFIG.TYPE_COMPLEX) {
  18173. continue;
  18174. }
  18175. cols.push({
  18176. id: id,
  18177. header: header,
  18178. dataIndex: id,
  18179. resizable: true,
  18180. editor: editor,
  18181. width: width
  18182. });
  18183. }
  18184. return new Ext.grid.ColumnModel(cols);
  18185. },
  18186. /**
  18187. * After a cell was edited the changes will be commited.
  18188. *
  18189. * @param {Object} option The option that was edited.
  18190. */
  18191. afterEdit: function(option) {
  18192. option.grid.getStore().commitChanges();
  18193. },
  18194. /**
  18195. * Before a cell is edited it has to be checked if this
  18196. * cell is disabled by another cell value. If so, the cell editor will
  18197. * be disabled.
  18198. *
  18199. * @param {Object} option The option to be edited.
  18200. */
  18201. beforeEdit: function(option) {
  18202. var state = this.grid.getView().getScrollState();
  18203. var col = option.column;
  18204. var row = option.row;
  18205. var editId = this.grid.getColumnModel().config[col].id;
  18206. // check if there is an item in the row, that disables this cell
  18207. for (var i = 0; i < this.items.length; i++) {
  18208. // check each item that defines a "disable" property
  18209. var item = this.items[i];
  18210. var disables = item.disable();
  18211. if (disables != undefined) {
  18212. // check if the value of the column of this item in this row is equal to a disabling value
  18213. var value = this.grid.getStore().getAt(row).get(item.id());
  18214. for (var j = 0; j < disables.length; j++) {
  18215. var disable = disables[j];
  18216. if (disable.value == value) {
  18217. for (var k = 0; k < disable.items.length; k++) {
  18218. // check if this value disables the cell to select
  18219. // (id is equals to the id of the column to edit)
  18220. var disItem = disable.items[k];
  18221. if (disItem == editId) {
  18222. this.grid.getColumnModel().getCellEditor(col, row).disable();
  18223. return;
  18224. }
  18225. }
  18226. }
  18227. }
  18228. }
  18229. }
  18230. this.grid.getColumnModel().getCellEditor(col, row).enable();
  18231. //this.grid.getView().restoreScroll(state);
  18232. },
  18233. onCellClick: function() {
  18234. alert()
  18235. },
  18236. /**
  18237. * If the trigger was clicked a dialog has to be opened
  18238. * to enter the values for the complex property.
  18239. */
  18240. onTriggerClick : function(){
  18241. if(this.disabled){
  18242. return;
  18243. }
  18244. //if(!this.dialog) {
  18245. var dialogWidth = 0;
  18246. var recordType = [];
  18247. for (var i = 0; i < this.items.length; i++) {
  18248. var id = this.items[i].id();
  18249. var width = this.items[i].width();
  18250. var type = this.items[i].type();
  18251. if (type == ORYX.CONFIG.TYPE_CHOICE || type == ORYX.CONFIG.TYPE_COMPLEX) {
  18252. type = ORYX.CONFIG.TYPE_STRING;
  18253. }
  18254. dialogWidth += width;
  18255. recordType[i] = {name:id, type:type};
  18256. }
  18257. if (dialogWidth > 800) {
  18258. dialogWidth = 800;
  18259. }
  18260. dialogWidth += 22;
  18261. var data = this.data;
  18262. if (data == "") {
  18263. // empty string can not be parsed
  18264. data = "{}";
  18265. }
  18266. var ds = new Ext.data.Store({
  18267. proxy: new Ext.data.MemoryProxy(eval("(" + data + ")")),
  18268. reader: new Ext.data.JsonReader({
  18269. root: 'items',
  18270. totalProperty: 'totalCount'
  18271. }, recordType)
  18272. });
  18273. ds.load();
  18274. var cm = this.buildColumnModel();
  18275. //var gridHead = this.grid.getView().getHeaderPanel(true);
  18276. var toolbar = new Ext.Toolbar(
  18277. [{
  18278. text: ORYX.I18N.PropertyWindow.add,
  18279. icon: '../editor/images/add.png',
  18280. iconCls: "x-dummy",
  18281. handler: function(){
  18282. var ds = this.grid.getStore();
  18283. var index = ds.getCount();
  18284. this.grid.stopEditing();
  18285. var p = this.buildInitial(recordType, this.items);
  18286. ds.insert(index, p);
  18287. ds.commitChanges();
  18288. this.grid.startEditing(index, 0);
  18289. }.bind(this)
  18290. },{
  18291. text: ORYX.I18N.PropertyWindow.rem,
  18292. icon: '../editor/images/delete.png',
  18293. iconCls: "x-dummy",
  18294. handler : function(){
  18295. var ds = this.grid.getStore();
  18296. var selection = this.grid.getSelectionModel().getSelectedCell();
  18297. if (selection == undefined) {
  18298. return;
  18299. }
  18300. this.grid.getSelectionModel().clearSelections();
  18301. this.grid.stopEditing();
  18302. var record = ds.getAt(selection[0]);
  18303. ds.remove(record);
  18304. ds.commitChanges();
  18305. }.bind(this)
  18306. }]);
  18307. this.grid = new Ext.grid.EditorGridPanel({
  18308. store: ds,
  18309. cm: cm,
  18310. stripeRows: true,
  18311. clicksToEdit: 1,
  18312. autoScroll: true,
  18313. stateId: "x-editor-complex-grid",
  18314. anchor: "100% 100%",
  18315. enableHdMenu: false, // Disable header menu
  18316. selModel: new Ext.grid.CellSelectionModel(),
  18317. tbar:toolbar
  18318. });
  18319. // Basic Dialog
  18320. this.dialog = new Ext.Window({
  18321. autoCreate: true,
  18322. layout: "anchor",
  18323. title: ORYX.I18N.PropertyWindow.complex,
  18324. height: 350,
  18325. width: dialogWidth,
  18326. modal:true,
  18327. collapsible:false,
  18328. fixedcenter: true,
  18329. shadow:true,
  18330. proxyDrag: true,
  18331. keys:[{
  18332. key: 27,
  18333. fn: function(){
  18334. this.dialog.hide
  18335. }.bind(this)
  18336. }],
  18337. items:[this.grid],
  18338. bodyStyle:"background-color:#FFFFFF",
  18339. buttons: [{
  18340. text: ORYX.I18N.PropertyWindow.ok,
  18341. handler: function(){
  18342. this.grid.stopEditing();
  18343. // store dialog input
  18344. this.data = this.buildValue();
  18345. this.dialog.hide()
  18346. }.bind(this)
  18347. }, {
  18348. text: ORYX.I18N.PropertyWindow.cancel,
  18349. handler: function(){
  18350. this.dialog.hide()
  18351. }.bind(this)
  18352. }]
  18353. });
  18354. this.dialog.on(Ext.apply({}, this.dialogListeners, {
  18355. scope:this
  18356. }));
  18357. this.dialog.show();
  18358. this.grid.on('beforeedit', this.beforeEdit, this, true);
  18359. this.grid.on('afteredit', this.afterEdit, this, true);
  18360. this.grid.render();
  18361. /*} else {
  18362. this.dialog.show();
  18363. }*/
  18364. }
  18365. });
  18366. Ext.form.MultipleComplexListField = function(config, items, key, facade){
  18367. Ext.form.MultipleComplexListField.superclass.constructor.call(this, config);
  18368. this.items = items;
  18369. this.key = key;
  18370. this.facade = facade;
  18371. };
  18372. Ext.extend(Ext.form.MultipleComplexListField, Ext.form.TriggerField, {
  18373. /**
  18374. * @cfg {String} triggerClass
  18375. * An additional CSS class used to style the trigger button. The trigger will always get the
  18376. * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified.
  18377. */
  18378. triggerClass: 'x-form-complex-trigger',
  18379. readOnly: true,
  18380. emptyText: ORYX.I18N.PropertyWindow.clickIcon,
  18381. /**
  18382. * Builds the JSON value from the data source of the grid in the dialog.
  18383. */
  18384. buildValue: function() {
  18385. var ds = this.grid.getStore();
  18386. ds.commitChanges();
  18387. if (ds.getCount() == 0) {
  18388. return "";
  18389. }
  18390. var jsonString = "[";
  18391. for (var i = 0; i < ds.getCount(); i++) {
  18392. var data = ds.getAt(i);
  18393. jsonString += "{";
  18394. for (var j = 0; j < this.items.length; j++) {
  18395. var key = this.items[j].id();
  18396. jsonString += key + ':' + ("" + data.get(key)).toJSON();
  18397. if (j < (this.items.length - 1)) {
  18398. jsonString += ", ";
  18399. }
  18400. }
  18401. jsonString += "}";
  18402. if (i < (ds.getCount() - 1)) {
  18403. jsonString += ", ";
  18404. }
  18405. }
  18406. jsonString += "]";
  18407. jsonString = "{'totalCount':" + ds.getCount().toJSON() +
  18408. ", 'items':" + jsonString + "}";
  18409. return Object.toJSON(jsonString.evalJSON());
  18410. },
  18411. /**
  18412. * Returns the field key.
  18413. */
  18414. getFieldKey: function() {
  18415. return this.key;
  18416. },
  18417. /**
  18418. * Returns the actual value of the trigger field.
  18419. * If the table does not contain any values the empty
  18420. * string will be returned.
  18421. */
  18422. getValue : function(){
  18423. // return actual value if grid is active
  18424. if (this.grid) {
  18425. return this.buildValue();
  18426. } else if (this.data == undefined) {
  18427. return "";
  18428. } else {
  18429. return this.data;
  18430. }
  18431. },
  18432. /**
  18433. * Sets the value of the trigger field.
  18434. * In this case this sets the data that will be shown in
  18435. * the grid of the dialog.
  18436. *
  18437. * @param {Object} value The value to be set (JSON format or empty string)
  18438. */
  18439. setValue: function(value) {
  18440. if (value.length > 0 && value.indexOf('<') == -1) {
  18441. // set only if this.data not set yet
  18442. // only to initialize the grid
  18443. if (this.data == undefined) {
  18444. this.data = value;
  18445. }
  18446. }
  18447. },
  18448. /**
  18449. * Returns false. In this way key events will not be propagated
  18450. * to other elements.
  18451. *
  18452. * @param {Object} event The keydown event.
  18453. */
  18454. keydownHandler: function(event) {
  18455. return false;
  18456. },
  18457. /**
  18458. * The listeners of the dialog.
  18459. *
  18460. * If the dialog is hidded, a dialogClosed event will be fired.
  18461. * This has to be used by the parent element of the trigger field
  18462. * to reenable the trigger field (focus gets lost when entering values
  18463. * in the dialog).
  18464. */
  18465. dialogListeners : {
  18466. show : function(){ // retain focus styling
  18467. this.onFocus();
  18468. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keydownHandler.bind(this));
  18469. this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  18470. return;
  18471. },
  18472. hide : function(){
  18473. var dl = this.dialogListeners;
  18474. this.dialog.un("show", dl.show, this);
  18475. this.dialog.un("hide", dl.hide, this);
  18476. this.dialog.destroy(true);
  18477. this.grid.destroy(true);
  18478. delete this.grid;
  18479. delete this.dialog;
  18480. this.facade.unregisterOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keydownHandler.bind(this));
  18481. this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  18482. // store data and notify parent about the closed dialog
  18483. // parent has to handel this event and start editing the text field again
  18484. this.fireEvent('dialogClosed', this.data);
  18485. Ext.form.ComplexListField.superclass.setValue.call(this, this.data);
  18486. }
  18487. },
  18488. /**
  18489. * Builds up the initial values of the grid.
  18490. *
  18491. * @param {Object} recordType The record type of the grid.
  18492. * @param {Object} items The initial items of the grid (columns)
  18493. */
  18494. buildInitial: function(recordType, items) {
  18495. var initial = new Hash();
  18496. for (var i = 0; i < items.length; i++) {
  18497. var id = items[i].id();
  18498. initial[id] = items[i].value();
  18499. }
  18500. var RecordTemplate = Ext.data.Record.create(recordType);
  18501. return new RecordTemplate(initial);
  18502. },
  18503. /**
  18504. * Builds up the column model of the grid. The parent element of the
  18505. * grid.
  18506. *
  18507. * Sets up the editors for the grid columns depending on the
  18508. * type of the items.
  18509. *
  18510. * @param {Object} parent The
  18511. */
  18512. buildColumnModel: function(parent) {
  18513. var cols = [];
  18514. for (var i = 0; i < this.items.length; i++) {
  18515. var id = this.items[i].id();
  18516. var header = this.items[i].name();
  18517. var width = this.items[i].width();
  18518. var type = this.items[i].type();
  18519. var editor;
  18520. if (type == ORYX.CONFIG.TYPE_STRING) {
  18521. editor = new Ext.form.TextField({ allowBlank : this.items[i].optional(), width : width});
  18522. } else if (type == ORYX.CONFIG.TYPE_CHOICE) {
  18523. var items = this.items[i].items();
  18524. var select = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parent, ['select', {style:'display:none'}]);
  18525. var optionTmpl = new Ext.Template('<option value="{value}">{value}</option>');
  18526. items.each(function(value){
  18527. optionTmpl.append(select, {value:value.value()});
  18528. });
  18529. editor = new Ext.form.ComboBox(
  18530. { typeAhead: true, triggerAction: 'all', transform:select, lazyRender:true, msgTarget:'title', width : width});
  18531. } else if (type == ORYX.CONFIG.TYPE_BOOLEAN) {
  18532. editor = new Ext.form.Checkbox( { width : width } );
  18533. } else if (type == ORYX.CONFIG.TYPE_COMPLEX) {
  18534. continue;
  18535. }
  18536. cols.push({
  18537. id: id,
  18538. header: header,
  18539. dataIndex: id,
  18540. resizable: true,
  18541. editor: editor,
  18542. width: width
  18543. });
  18544. }
  18545. return new Ext.grid.ColumnModel(cols);
  18546. },
  18547. buildSecondColumnModel: function(parent) {
  18548. var cols = [];
  18549. for (var i = 0; i < this.items.length; i++) {
  18550. var parentType = this.items[i].type();
  18551. if (parentType != ORYX.CONFIG.TYPE_COMPLEX) {
  18552. continue;
  18553. }
  18554. var complexItems = this.items[i].complexItems();
  18555. for (var j = 0; j < complexItems.length; j++) {
  18556. var id = complexItems[j].id();
  18557. var header = complexItems[j].name();
  18558. var type = complexItems[j].type();
  18559. var width = complexItems[j].width();
  18560. var editor;
  18561. if (type == ORYX.CONFIG.TYPE_STRING) {
  18562. editor = new Ext.form.TextField({ allowBlank : complexItems[j].optional(), width : width});
  18563. } else if (type == ORYX.CONFIG.TYPE_CHOICE) {
  18564. var items = complexItems[j].items();
  18565. var select = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parent, ['select', {style:'display:none'}]);
  18566. var optionTmpl = new Ext.Template('<option value="{value}">{value}</option>');
  18567. items.each(function(value){
  18568. optionTmpl.append(select, {value:value.value()});
  18569. });
  18570. editor = new Ext.form.ComboBox(
  18571. { typeAhead: true, triggerAction: 'all', transform:select, lazyRender:true, msgTarget:'title', width : width});
  18572. } else if (type == ORYX.CONFIG.TYPE_BOOLEAN) {
  18573. editor = new Ext.form.Checkbox( { width : width } );
  18574. } else if (type == ORYX.CONFIG.TYPE_COMPLEX) {
  18575. continue;
  18576. }
  18577. cols.push({
  18578. id: id,
  18579. header: header,
  18580. dataIndex: id,
  18581. resizable: true,
  18582. editor: editor,
  18583. width: width
  18584. });
  18585. }
  18586. }
  18587. return new Ext.grid.ColumnModel(cols);
  18588. },
  18589. /**
  18590. * After a cell was edited the changes will be commited.
  18591. *
  18592. * @param {Object} option The option that was edited.
  18593. */
  18594. afterEdit: function(option) {
  18595. option.grid.getStore().commitChanges();
  18596. },
  18597. afterEditSecondGrid: function(option) {
  18598. this.secondGrid.getStore().commitChanges();
  18599. var selectedCell = this.grid.getSelectionModel().getSelectedCell();
  18600. if (selectedCell.length == 2) {
  18601. var row = selectedCell[0];
  18602. var jsonString = "[";
  18603. for (var i = 0; i < this.secondGrid.getStore().getCount(); i++) {
  18604. var data = this.secondGrid.getStore().getAt(i);
  18605. jsonString += "{";
  18606. for (var j = 0; j < this.items.length; j++) {
  18607. var parentType = this.items[j].type();
  18608. if (parentType != ORYX.CONFIG.TYPE_COMPLEX) {
  18609. continue;
  18610. }
  18611. var complexItems = this.items[j].complexItems();
  18612. for (var k = 0; k < complexItems.length; k++) {
  18613. var key = complexItems[k].id();
  18614. jsonString += key + ':' + ("" + data.get(key)).toJSON();
  18615. if (k < (complexItems.length - 1)) {
  18616. jsonString += ", ";
  18617. }
  18618. }
  18619. }
  18620. jsonString += "}";
  18621. if (i < (this.secondGrid.getStore().getCount() - 1)) {
  18622. jsonString += ", ";
  18623. }
  18624. }
  18625. jsonString += "]";
  18626. jsonString = "{'totalCount':" + this.secondGrid.getStore().getCount().toJSON() +
  18627. ", 'items':" + jsonString + "}";
  18628. var activeRecord = this.grid.getStore().getAt(row);
  18629. activeRecord.set(this.complexFieldId, Object.toJSON(jsonString.evalJSON()));
  18630. }
  18631. },
  18632. /**
  18633. * Before a cell is edited it has to be checked if this
  18634. * cell is disabled by another cell value. If so, the cell editor will
  18635. * be disabled.
  18636. *
  18637. * @param {Object} option The option to be edited.
  18638. */
  18639. beforeEdit: function(option) {
  18640. var state = this.grid.getView().getScrollState();
  18641. var col = option.column;
  18642. var row = option.row;
  18643. var editId = this.grid.getColumnModel().config[col].id;
  18644. // check if there is an item in the row, that disables this cell
  18645. for (var i = 0; i < this.items.length; i++) {
  18646. if (this.items[i].type() == ORYX.CONFIG.TYPE_COMPLEX) {
  18647. continue;
  18648. }
  18649. // check each item that defines a "disable" property
  18650. var item = this.items[i];
  18651. var disables = item.disable();
  18652. if (disables != undefined) {
  18653. // check if the value of the column of this item in this row is equal to a disabling value
  18654. var value = this.grid.getStore().getAt(row).get(item.id());
  18655. for (var j = 0; j < disables.length; j++) {
  18656. var disable = disables[j];
  18657. if (disable.value == value) {
  18658. for (var k = 0; k < disable.items.length; k++) {
  18659. // check if this value disables the cell to select
  18660. // (id is equals to the id of the column to edit)
  18661. var disItem = disable.items[k];
  18662. if (disItem == editId) {
  18663. this.grid.getColumnModel().getCellEditor(col, row).disable();
  18664. return;
  18665. }
  18666. }
  18667. }
  18668. }
  18669. }
  18670. }
  18671. this.grid.getColumnModel().getCellEditor(col, row).enable();
  18672. //this.grid.getView().restoreScroll(state);
  18673. },
  18674. /**
  18675. * If the trigger was clicked a dialog has to be opened
  18676. * to enter the values for the complex property.
  18677. */
  18678. onTriggerClick : function(){
  18679. if(this.disabled){
  18680. return;
  18681. }
  18682. //if(!this.dialog) {
  18683. var dialogWidth = 0;
  18684. var recordType = [];
  18685. var secondRecordType = [];
  18686. this.complexFieldId;
  18687. var complexItems;
  18688. for (var i = 0; i < this.items.length; i++) {
  18689. var id = this.items[i].id();
  18690. var width = this.items[i].width();
  18691. var type = this.items[i].type();
  18692. if (type == ORYX.CONFIG.TYPE_CHOICE) {
  18693. type = ORYX.CONFIG.TYPE_STRING;
  18694. }
  18695. if (type == ORYX.CONFIG.TYPE_COMPLEX) {
  18696. this.complexFieldId = id;
  18697. type = ORYX.CONFIG.TYPE_STRING;
  18698. complexItems = this.items[i].complexItems();
  18699. for (var j = 0; j < complexItems.length; j++) {
  18700. var secondId = complexItems[j].id();
  18701. var secondWidth = complexItems[j].width();
  18702. var secondType = complexItems[j].type();
  18703. if (secondType == ORYX.CONFIG.TYPE_CHOICE) {
  18704. secondType = ORYX.CONFIG.TYPE_STRING;
  18705. }
  18706. secondRecordType[j] = {name:secondId, type:secondType};
  18707. }
  18708. } else {
  18709. dialogWidth += width;
  18710. }
  18711. recordType[i] = {name:id, type:type};
  18712. }
  18713. if (dialogWidth > 800) {
  18714. dialogWidth = 800;
  18715. }
  18716. dialogWidth += 22;
  18717. var data = this.data;
  18718. if (data == "") {
  18719. // empty string can not be parsed
  18720. data = "{}";
  18721. }
  18722. var ds = new Ext.data.Store({
  18723. proxy: new Ext.data.MemoryProxy(eval("(" + data + ")")),
  18724. reader: new Ext.data.JsonReader({
  18725. root: 'items',
  18726. totalProperty: 'totalCount'
  18727. }, recordType)
  18728. });
  18729. ds.load();
  18730. var secondDs = new Ext.data.Store();
  18731. var cm = this.buildColumnModel();
  18732. var secondCm = this.buildSecondColumnModel();
  18733. //var gridHead = this.grid.getView().getHeaderPanel(true);
  18734. var toolbar = new Ext.Toolbar(
  18735. [{
  18736. text: ORYX.I18N.PropertyWindow.add,
  18737. icon: '../editor/images/add.png',
  18738. iconCls: "x-dummy",
  18739. handler: function(){
  18740. var ds = this.grid.getStore();
  18741. var index = ds.getCount();
  18742. this.grid.stopEditing();
  18743. var p = this.buildInitial(recordType, this.items);
  18744. ds.insert(index, p);
  18745. ds.commitChanges();
  18746. this.grid.startEditing(index, 0);
  18747. }.bind(this)
  18748. },{
  18749. text: ORYX.I18N.PropertyWindow.rem,
  18750. icon: '../editor/images/delete.png',
  18751. iconCls: "x-dummy",
  18752. handler : function(){
  18753. var ds = this.grid.getStore();
  18754. var selection = this.grid.getSelectionModel().getSelectedCell();
  18755. if (selection == undefined) {
  18756. return;
  18757. }
  18758. this.grid.getSelectionModel().clearSelections();
  18759. this.grid.stopEditing();
  18760. var record = ds.getAt(selection[0]);
  18761. ds.remove(record);
  18762. ds.commitChanges();
  18763. }.bind(this)
  18764. }]);
  18765. this.grid = new Ext.grid.EditorGridPanel({
  18766. store: ds,
  18767. cm: cm,
  18768. stripeRows: true,
  18769. clicksToEdit: 1,
  18770. autoScroll: true,
  18771. stateId: "x-editor-complex-grid",
  18772. height: 280,
  18773. anchor: '100%',
  18774. enableHdMenu: false, // Disable header menu
  18775. selModel: new Ext.grid.CellSelectionModel({
  18776. listeners: {
  18777. scope: this,
  18778. cellselect: function(sm,row,col) {
  18779. secondDs.removeAll(true);
  18780. var masterRecord = ds.getAt(row);
  18781. if (masterRecord.get('' + this.complexFieldId) != undefined && masterRecord.get('' + this.complexFieldId) != 'undefined') {
  18782. var newDs = new Ext.data.Store({
  18783. proxy: new Ext.data.MemoryProxy(eval("(" + masterRecord.get('' + this.complexFieldId) + ")")),
  18784. reader: new Ext.data.JsonReader({
  18785. root: 'items',
  18786. totalProperty: 'totalCount'
  18787. }, secondRecordType)
  18788. });
  18789. newDs.load();
  18790. secondDs.removeAll(true);
  18791. for (var i = 0; i < newDs.getCount(); i++) {
  18792. secondDs.add(newDs.getAt(i));
  18793. }
  18794. }
  18795. secondDs.commitChanges();
  18796. }
  18797. }
  18798. }),
  18799. tbar:toolbar
  18800. });
  18801. var secondToolbar = new Ext.Toolbar(
  18802. [{
  18803. text: ORYX.I18N.PropertyWindow.add,
  18804. icon: '../editor/images/add.png',
  18805. iconCls: "x-dummy",
  18806. handler: function(){
  18807. var ds = this.secondGrid.getStore();
  18808. var index = ds.getCount();
  18809. this.secondGrid.stopEditing();
  18810. var p = this.buildInitial(secondRecordType, complexItems);
  18811. ds.insert(index, p);
  18812. ds.commitChanges();
  18813. this.secondGrid.startEditing(index, 0);
  18814. }.bind(this)
  18815. },{
  18816. text: ORYX.I18N.PropertyWindow.rem,
  18817. icon: '../editor/images/delete.png',
  18818. iconCls: "x-dummy",
  18819. handler : function(){
  18820. var ds = this.secondGrid.getStore();
  18821. var selection = this.secondGrid.getSelectionModel().getSelectedCell();
  18822. if (selection == undefined) {
  18823. return;
  18824. }
  18825. this.secondGrid.getSelectionModel().clearSelections();
  18826. this.secondGrid.stopEditing();
  18827. var record = ds.getAt(selection[0]);
  18828. ds.remove(record);
  18829. ds.commitChanges();
  18830. this.afterEditSecondGrid();
  18831. }.bind(this)
  18832. }]);
  18833. this.secondGrid = new Ext.grid.EditorGridPanel({
  18834. store: secondDs,
  18835. cm: secondCm,
  18836. stripeRows: true,
  18837. clicksToEdit: 1,
  18838. autoScroll: true,
  18839. stateId: "x-editor-complex-grid",
  18840. height: 280,
  18841. anchor: '100%',
  18842. enableHdMenu: false, // Disable header menu
  18843. selModel: new Ext.grid.CellSelectionModel(),
  18844. tbar:secondToolbar
  18845. });
  18846. // Basic Dialog
  18847. this.dialog = new Ext.Window({
  18848. autoCreate: true,
  18849. layout: "anchor",
  18850. title: ORYX.I18N.PropertyWindow.complex,
  18851. height: 600,
  18852. width: dialogWidth,
  18853. modal:true,
  18854. collapsible:false,
  18855. fixedcenter: true,
  18856. shadow:true,
  18857. proxyDrag: true,
  18858. keys:[{
  18859. key: 27,
  18860. fn: function(){
  18861. this.dialog.hide
  18862. }.bind(this)
  18863. }],
  18864. items:[this.grid, this.secondGrid],
  18865. bodyStyle:"background-color:#FFFFFF",
  18866. buttons: [{
  18867. text: ORYX.I18N.PropertyWindow.ok,
  18868. handler: function(){
  18869. this.grid.stopEditing();
  18870. // store dialog input
  18871. this.data = this.buildValue();
  18872. this.dialog.hide()
  18873. }.bind(this)
  18874. }]
  18875. });
  18876. this.dialog.on(Ext.apply({}, this.dialogListeners, {
  18877. scope:this
  18878. }));
  18879. this.dialog.show();
  18880. this.grid.on('beforeedit', this.beforeEdit, this, true);
  18881. this.grid.on('afteredit', this.afterEdit, this, true);
  18882. this.secondGrid.on('beforeedit', this.beforeEdit, this, true);
  18883. this.secondGrid.on('afteredit', this.afterEditSecondGrid, this, true);
  18884. this.grid.render();
  18885. this.secondGrid.render();
  18886. if (ds.getCount() > 0) {
  18887. this.grid.getSelectionModel().select(0,0);
  18888. }
  18889. /*} else {
  18890. this.dialog.show();
  18891. }*/
  18892. }
  18893. });
  18894. Ext.form.ComplexTextField = Ext.extend(Ext.form.TriggerField, {
  18895. defaultAutoCreate : {tag: "textarea", rows:1, style:"height:16px;overflow:hidden;" },
  18896. /**
  18897. * If the trigger was clicked a dialog has to be opened
  18898. * to enter the values for the complex property.
  18899. */
  18900. onTriggerClick : function(){
  18901. if(this.disabled){
  18902. return;
  18903. }
  18904. var grid = new Ext.form.TextArea({
  18905. anchor : '100% 100%',
  18906. value : this.value,
  18907. listeners : {
  18908. focus: function(){
  18909. this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  18910. }.bind(this)
  18911. }
  18912. })
  18913. // Basic Dialog
  18914. var dialog = new Ext.Window({
  18915. layout : 'anchor',
  18916. autoCreate : true,
  18917. title : ORYX.I18N.PropertyWindow.text,
  18918. height : 500,
  18919. width : 500,
  18920. modal : true,
  18921. collapsible : false,
  18922. fixedcenter : true,
  18923. shadow : true,
  18924. proxyDrag : true,
  18925. keys:[{
  18926. key : 27,
  18927. fn : function(){
  18928. dialog.hide()
  18929. }.bind(this)
  18930. }],
  18931. items :[grid],
  18932. listeners :{
  18933. hide: function(){
  18934. this.fireEvent('dialogClosed', this.value);
  18935. //this.focus.defer(10, this);
  18936. dialog.destroy();
  18937. }.bind(this)
  18938. },
  18939. buttons : [{
  18940. text: ORYX.I18N.PropertyWindow.ok,
  18941. handler: function(){
  18942. // store dialog input
  18943. var value = grid.getValue();
  18944. this.setValue(value);
  18945. this.dataSource.getAt(this.row).set('value', value)
  18946. this.dataSource.commitChanges()
  18947. dialog.hide()
  18948. }.bind(this)
  18949. }, {
  18950. text: ORYX.I18N.PropertyWindow.cancel,
  18951. handler: function(){
  18952. this.setValue(this.value);
  18953. dialog.hide()
  18954. }.bind(this)
  18955. }]
  18956. });
  18957. dialog.show();
  18958. grid.render();
  18959. this.grid.stopEditing();
  18960. grid.focus( false, 100 );
  18961. }
  18962. });
  18963. Ext.form.ComplexModelLinkField = Ext.extend(Ext.form.TriggerField, {
  18964. onTriggerClick : function() {
  18965. if(this.disabled){
  18966. return;
  18967. }
  18968. var CallElementDef = Ext.data.Record.create([{
  18969. name: 'name'
  18970. }, {
  18971. name: 'revision'
  18972. }, {
  18973. name: 'imgsrc'
  18974. }]);
  18975. var calldefsProxy = new Ext.data.MemoryProxy({
  18976. root: []
  18977. });
  18978. var calldefs = new Ext.data.Store({
  18979. autoDestroy: true,
  18980. reader: new Ext.data.JsonReader({
  18981. root: "root"
  18982. }, CallElementDef),
  18983. proxy: calldefsProxy,
  18984. sorters: [{
  18985. property: 'name',
  18986. direction:'ASC'
  18987. }]
  18988. });
  18989. calldefs.load();
  18990. var loadProcessesMask = new Ext.LoadMask(Ext.getBody(), {msg:'Loading Process Information'});
  18991. loadProcessesMask.show();
  18992. Ext.Ajax.request({
  18993. url: ORYX.CONFIG.MODEL_LIST_URL,
  18994. method: 'GET',
  18995. success: function(response) {
  18996. try {
  18997. loadProcessesMask.hide();
  18998. if(response.responseText.length > 0 && response.responseText != "false") {
  18999. var responseJson = Ext.decode(response.responseText);
  19000. var modelsArray = responseJson["models"];
  19001. for(var i = 0; i < modelsArray.length; i++) {
  19002. var modelObj = modelsArray[i];
  19003. calldefs.add(new CallElementDef({
  19004. name: modelObj["name"],
  19005. revision: modelObj["revision"],
  19006. imgsrc: ORYX.CONFIG.SERVER_MODEL_HANDLER + "/" + modelObj["modelId"] + "/svg"
  19007. }));
  19008. }
  19009. calldefs.commitChanges();
  19010. var gridId = Ext.id();
  19011. var grid = new Ext.grid.EditorGridPanel({
  19012. store: calldefs,
  19013. id: gridId,
  19014. stripeRows: true,
  19015. cm: new Ext.grid.ColumnModel([new Ext.grid.RowNumberer(), {
  19016. id: 'pid',
  19017. header: 'Process Id',
  19018. width: 200,
  19019. dataIndex: 'name',
  19020. editor: new Ext.form.TextField({ allowBlank: false, disabled: true })
  19021. }, {
  19022. id: 'revi',
  19023. header: 'Revision',
  19024. width: 200,
  19025. dataIndex: 'revision',
  19026. editor: new Ext.form.TextField({ allowBlank: false, disabled: true })
  19027. },{
  19028. id: 'pim',
  19029. header: 'Process Image',
  19030. width: 250,
  19031. dataIndex: 'imgsrc',
  19032. renderer: function(val) {
  19033. if(val && val.length > 0) {
  19034. return '<center><img src="'+ORYX.CONFIG.ROOT_PATH+'images/processimagepreview.png" onclick="new ImageViewer({title: \'Process Image\', width: \'1100\', height: \'900\', autoScroll: true, fixedcenter: true, src: \''+val+'\',hideAction: \'close\'}).show();" alt="Click to view Process Image"/></center>';
  19035. } else {
  19036. return "<center>Process image not available.</center>";
  19037. }
  19038. }
  19039. }]),
  19040. autoHeight: true
  19041. });
  19042. grid.on('afterrender', function(e) {
  19043. if(this.value.length > 0) {
  19044. var index = 0;
  19045. var val = this.value;
  19046. var mygrid = grid;
  19047. calldefs.data.each(function() {
  19048. if(this.data['name'] == val) {
  19049. mygrid.getSelectionModel().select(index, 1);
  19050. }
  19051. index++;
  19052. });
  19053. }
  19054. }.bind(this));
  19055. var calledElementsPanel = new Ext.Panel({
  19056. id: 'calledElementsPanel',
  19057. title: '<center>Select Process Id and click "Save" to select.</center>',
  19058. layout:'column',
  19059. items:[
  19060. grid
  19061. ],
  19062. layoutConfig: {
  19063. columns: 1
  19064. },
  19065. defaults: {
  19066. columnWidth: 1.0
  19067. }
  19068. });
  19069. var dialog = new Ext.Window({
  19070. layout : 'anchor',
  19071. autoCreate : true,
  19072. title : 'Editor for Called Elements',
  19073. height : 350,
  19074. width : 680,
  19075. modal : true,
  19076. collapsible : false,
  19077. fixedcenter : true,
  19078. shadow : true,
  19079. resizable : true,
  19080. proxyDrag : true,
  19081. autoScroll : true,
  19082. keys:[{
  19083. key : 27,
  19084. fn : function(){
  19085. dialog.hide()
  19086. }.bind(this)
  19087. }],
  19088. items :[calledElementsPanel],
  19089. listeners :{
  19090. hide: function(){
  19091. this.fireEvent('dialogClosed', this.value);
  19092. dialog.destroy();
  19093. }.bind(this)
  19094. },
  19095. buttons : [{
  19096. text: 'Save',
  19097. handler: function(){
  19098. if(grid.getSelectionModel().getSelectedCell() != null) {
  19099. var selectedIndex = grid.getSelectionModel().getSelectedCell()[0];
  19100. var outValue = calldefs.getAt(selectedIndex).data['name'];
  19101. grid.stopEditing();
  19102. grid.getView().refresh();
  19103. this.setValue(outValue);
  19104. this.dataSource.getAt(this.row).set('value', outValue)
  19105. this.dataSource.commitChanges()
  19106. dialog.hide()
  19107. } else {
  19108. Ext.Msg.alert('Please select a process id.');
  19109. }
  19110. }.bind(this)
  19111. }, {
  19112. text: ORYX.I18N.PropertyWindow.cancel,
  19113. handler: function(){
  19114. this.setValue(this.value);
  19115. dialog.hide()
  19116. }.bind(this)
  19117. }]
  19118. });
  19119. dialog.show();
  19120. grid.render();
  19121. grid.fireEvent('afterrender');
  19122. this.grid.stopEditing();
  19123. grid.focus( false, 100 );
  19124. } else {
  19125. Ext.Msg.alert('Unable to find other processes in pacakge.');
  19126. }
  19127. } catch(e) {
  19128. Ext.Msg.alert('Error resolving other process info :\n' + e);
  19129. }
  19130. }.bind(this),
  19131. failure: function(){
  19132. loadProcessesMask.hide();
  19133. Ext.Msg.alert('Error resolving other process info.');
  19134. }
  19135. });
  19136. }
  19137. });
  19138. Ext.form.ListenerDefinitionField = Ext.extend(Ext.form.TriggerField, {
  19139. onTriggerClick : function() {
  19140. if(this.disabled){
  19141. return;
  19142. }
  19143. var ListenerDef = Ext.data.Record.create([{
  19144. name: 'class'
  19145. }, {
  19146. name: 'expression'
  19147. }, {
  19148. name: 'event'
  19149. }]);
  19150. var calldefsProxy = new Ext.data.MemoryProxy({
  19151. root: []
  19152. });
  19153. var calldefs = new Ext.data.Store({
  19154. autoDestroy: true,
  19155. reader: new Ext.data.JsonReader({
  19156. root: "root"
  19157. }, ListenerDef),
  19158. proxy: calldefsProxy,
  19159. sorters: [{
  19160. property: 'event',
  19161. direction:'ASC'
  19162. }]
  19163. });
  19164. calldefs.load();
  19165. var gridId = Ext.id();
  19166. var grid = new Ext.grid.EditorGridPanel({
  19167. store: calldefs,
  19168. id: gridId,
  19169. stripeRows: true,
  19170. cm: new Ext.grid.ColumnModel([new Ext.grid.RowNumberer(), {
  19171. id: 'pid',
  19172. header: 'Process Id',
  19173. width: 200,
  19174. dataIndex: 'class',
  19175. editor: new Ext.form.TextField({ allowBlank: false, disabled: true })
  19176. }, {
  19177. id: 'revi',
  19178. header: 'Revision',
  19179. width: 200,
  19180. dataIndex: 'expression',
  19181. editor: new Ext.form.TextField({ allowBlank: false, disabled: true })
  19182. },{
  19183. id: 'pim',
  19184. header: 'Process Image',
  19185. width: 250,
  19186. dataIndex: 'event',
  19187. renderer: function(val) {
  19188. if(val && val.length > 0) {
  19189. return '<center><img src="'+ORYX.CONFIG.ROOT_PATH+'images/processimagepreview.png" onclick="new ImageViewer({title: \'Process Image\', width: \'1100\', height: \'900\', autoScroll: true, fixedcenter: true, src: \''+val+'\',hideAction: \'close\'}).show();" alt="Click to view Process Image"/></center>';
  19190. } else {
  19191. return "<center>Process image not available.</center>";
  19192. }
  19193. }
  19194. }]),
  19195. autoHeight: true
  19196. });
  19197. var calledElementsPanel = new Ext.Panel({
  19198. id: 'calledElementsPanel',
  19199. title: '<center>Select Process Id and click "Save" to select.</center>',
  19200. layout:'column',
  19201. items:[
  19202. grid
  19203. ],
  19204. layoutConfig: {
  19205. columns: 1
  19206. },
  19207. defaults: {
  19208. columnWidth: 1.0
  19209. }
  19210. });
  19211. var dialog = new Ext.Window({
  19212. layout : 'anchor',
  19213. autoCreate : true,
  19214. title : 'Editor for Called Elements',
  19215. height : 350,
  19216. width : 680,
  19217. modal : true,
  19218. collapsible : false,
  19219. fixedcenter : true,
  19220. shadow : true,
  19221. resizable : true,
  19222. proxyDrag : true,
  19223. autoScroll : true,
  19224. keys:[{
  19225. key : 27,
  19226. fn : function(){
  19227. dialog.hide()
  19228. }.bind(this)
  19229. }],
  19230. items :[calledElementsPanel],
  19231. listeners :{
  19232. hide: function(){
  19233. this.fireEvent('dialogClosed', this.value);
  19234. dialog.destroy();
  19235. }.bind(this)
  19236. },
  19237. buttons : [{
  19238. text: 'Save',
  19239. handler: function(){
  19240. if(grid.getSelectionModel().getSelectedCell() != null) {
  19241. var selectedIndex = grid.getSelectionModel().getSelectedCell()[0];
  19242. var outValue = calldefs.getAt(selectedIndex).data['name'];
  19243. grid.stopEditing();
  19244. grid.getView().refresh();
  19245. this.setValue(outValue);
  19246. this.dataSource.getAt(this.row).set('value', outValue)
  19247. this.dataSource.commitChanges()
  19248. dialog.hide()
  19249. } else {
  19250. Ext.Msg.alert('Please select a process id.');
  19251. }
  19252. }.bind(this)
  19253. }, {
  19254. text: ORYX.I18N.PropertyWindow.cancel,
  19255. handler: function(){
  19256. this.setValue(this.value);
  19257. dialog.hide()
  19258. }.bind(this)
  19259. }]
  19260. });
  19261. dialog.show();
  19262. grid.render();
  19263. grid.fireEvent('afterrender');
  19264. this.grid.stopEditing();
  19265. grid.focus( false, 100 );
  19266. }
  19267. });/**
  19268. * Copyright (c) 2006
  19269. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  19270. *
  19271. * Permission is hereby granted, free of charge, to any person obtaining a
  19272. * copy of this software and associated documentation files (the "Software"),
  19273. * to deal in the Software without restriction, including without limitation
  19274. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19275. * and/or sell copies of the Software, and to permit persons to whom the
  19276. * Software is furnished to do so, subject to the following conditions:
  19277. *
  19278. * The above copyright notice and this permission notice shall be included in
  19279. * all copies or substantial portions of the Software.
  19280. *
  19281. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19282. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19283. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19284. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19285. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19286. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19287. * DEALINGS IN THE SOFTWARE.
  19288. **/
  19289. if (!ORYX.Plugins) {
  19290. ORYX.Plugins = new Object();
  19291. }
  19292. /**
  19293. * This plugin is responsible for displaying loading indicators and to prevent
  19294. * the user from accidently unloading the page by, e.g., pressing the backspace
  19295. * button and returning to the previous site in history.
  19296. * @param {Object} facade The editor plugin facade to register enhancements with.
  19297. */
  19298. ORYX.Plugins.Loading = {
  19299. construct: function(facade){
  19300. this.facade = facade;
  19301. // The parent Node
  19302. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.facade.getCanvas().getHTMLContainer().parentNode, ['div', {
  19303. 'class': 'LoadingIndicator'
  19304. }, '']);
  19305. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_ENABLE, this.enableLoading.bind(this));
  19306. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_DISABLE, this.disableLoading.bind(this));
  19307. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADING_STATUS, this.showStatus.bind(this));
  19308. this.disableLoading();
  19309. },
  19310. enableLoading: function(options){
  19311. if(options.text)
  19312. this.node.innerHTML = options.text + "...";
  19313. else
  19314. this.node.innerHTML = ORYX.I18N.Loading.waiting;
  19315. this.node.removeClassName('StatusIndicator');
  19316. this.node.addClassName('LoadingIndicator');
  19317. this.node.style.display = "block";
  19318. var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode;
  19319. this.node.style.top = pos.offsetTop + 'px';
  19320. this.node.style.left = pos.offsetLeft +'px';
  19321. },
  19322. disableLoading: function(){
  19323. this.node.style.display = "none";
  19324. },
  19325. showStatus: function(options) {
  19326. if(options.text) {
  19327. this.node.innerHTML = options.text;
  19328. this.node.addClassName('StatusIndicator');
  19329. this.node.removeClassName('LoadingIndicator');
  19330. this.node.style.display = 'block';
  19331. var pos = this.facade.getCanvas().rootNode.parentNode.parentNode.parentNode.parentNode;
  19332. this.node.style.top = pos.offsetTop + 'px';
  19333. this.node.style.left = pos.offsetLeft +'px';
  19334. var tout = options.timeout ? options.timeout : 2000;
  19335. window.setTimeout((function(){
  19336. this.disableLoading();
  19337. }).bind(this), tout);
  19338. }
  19339. }
  19340. }
  19341. ORYX.Plugins.Loading = Clazz.extend(ORYX.Plugins.Loading);
  19342. /**
  19343. * Copyright (c) 2008
  19344. * Willi Tscheschner
  19345. *
  19346. * Permission is hereby granted, free of charge, to any person obtaining a
  19347. * copy of this software and associated documentation files (the "Software"),
  19348. * to deal in the Software without restriction, including without limitation
  19349. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19350. * and/or sell copies of the Software, and to permit persons to whom the
  19351. * Software is furnished to do so, subject to the following conditions:
  19352. *
  19353. * The above copyright notice and this permission notice shall be included in
  19354. * all copies or substantial portions of the Software.
  19355. *
  19356. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19357. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19358. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19359. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19360. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19361. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19362. * DEALINGS IN THE SOFTWARE.
  19363. **/
  19364. if (!ORYX.Plugins) {
  19365. ORYX.Plugins = new Object();
  19366. }
  19367. /**
  19368. * This plugin is responsible for resizing the canvas.
  19369. * @param {Object} facade The editor plugin facade to register enhancements with.
  19370. */
  19371. ORYX.Plugins.CanvasResize = Clazz.extend({
  19372. construct: function(facade){
  19373. this.facade = facade;
  19374. new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "N", this.resize.bind(this));
  19375. new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "W", this.resize.bind(this));
  19376. new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "E", this.resize.bind(this));
  19377. new ORYX.Plugins.CanvasResizeButton( this.facade.getCanvas(), "S", this.resize.bind(this));
  19378. },
  19379. resize: function( position, shrink ){
  19380. resizeCanvas = function(position, extentionSize, facade) {
  19381. var canvas = facade.getCanvas();
  19382. var b = canvas.bounds;
  19383. var scrollNode = facade.getCanvas().getHTMLContainer().parentNode.parentNode;
  19384. if( position == "E" || position == "W"){
  19385. canvas.setSize({width: (b.width() + extentionSize)*canvas.zoomLevel, height: (b.height())*canvas.zoomLevel})
  19386. } else if( position == "S" || position == "N"){
  19387. canvas.setSize({width: (b.width())*canvas.zoomLevel, height: (b.height() + extentionSize)*canvas.zoomLevel})
  19388. }
  19389. if( position == "N" || position == "W"){
  19390. var move = position == "N" ? {x: 0, y: extentionSize}: {x: extentionSize, y: 0 };
  19391. // Move all children
  19392. canvas.getChildNodes(false, function(shape){ shape.bounds.moveBy(move) })
  19393. // Move all dockers, when the edge has at least one docked shape
  19394. var edges = canvas.getChildEdges().findAll(function(edge){ return edge.getAllDockedShapes().length > 0})
  19395. var dockers = edges.collect(function(edge){ return edge.dockers.findAll(function(docker){ return !docker.getDockedShape() })}).flatten();
  19396. dockers.each(function(docker){ docker.bounds.moveBy(move)})
  19397. } else if( position == "S" ){
  19398. scrollNode.scrollTop += extentionSize;
  19399. } else if( position == "E" ){
  19400. scrollNode.scrollLeft += extentionSize;
  19401. }
  19402. canvas.update();
  19403. facade.updateSelection();
  19404. }
  19405. var commandClass = ORYX.Core.Command.extend({
  19406. construct: function(position, extentionSize, facade){
  19407. this.position = position;
  19408. this.extentionSize = extentionSize;
  19409. this.facade = facade;
  19410. },
  19411. execute: function(){
  19412. resizeCanvas(this.position, this.extentionSize, this.facade);
  19413. },
  19414. rollback: function(){
  19415. resizeCanvas(this.position, -this.extentionSize, this.facade);
  19416. },
  19417. update:function(){
  19418. }
  19419. });
  19420. var extentionSize = ORYX.CONFIG.CANVAS_RESIZE_INTERVAL;
  19421. if(shrink) extentionSize = -extentionSize;
  19422. var command = new commandClass(position, extentionSize, this.facade);
  19423. this.facade.executeCommands([command]);
  19424. }
  19425. });
  19426. ORYX.Plugins.CanvasResizeButton = Clazz.extend({
  19427. construct: function(canvas, position, callback){
  19428. this.canvas = canvas;
  19429. var parentNode = canvas.getHTMLContainer().parentNode.parentNode.parentNode;
  19430. window.myParent=parentNode
  19431. var scrollNode = parentNode.firstChild;
  19432. var svgRootNode = scrollNode.firstChild.firstChild;
  19433. // The buttons
  19434. var buttonGrow = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', { 'class': 'canvas_resize_indicator canvas_resize_indicator_grow' + ' ' + position ,'title':ORYX.I18N.RESIZE.tipGrow+ORYX.I18N.RESIZE[position]}]);
  19435. var buttonShrink = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", parentNode, ['div', { 'class': 'canvas_resize_indicator canvas_resize_indicator_shrink' + ' ' + position ,'title':ORYX.I18N.RESIZE.tipShrink+ORYX.I18N.RESIZE[position]}]);
  19436. // Defines a callback which gives back
  19437. // a boolean if the current mouse event
  19438. // is over the particular button area
  19439. var offSetWidth = 60;
  19440. var isOverOffset = function(event){
  19441. if(event.target!=parentNode && event.target!=scrollNode&& event.target!=scrollNode.firstChild&& event.target!=svgRootNode&& event.target!=scrollNode){ return false }
  19442. //if(inCanvas){offSetWidth=30}else{offSetWidth=30*2}
  19443. //Safari work around
  19444. var X=event.layerX !== undefined ? event.layerX : event.offsetX;
  19445. var Y=event.layerY !== undefined ? event.layerY : event.offsetY;
  19446. if((X - scrollNode.scrollLeft)<0 ||Ext.isSafari){ X+=scrollNode.scrollLeft;}
  19447. if((Y - scrollNode.scrollTop )<0 ||Ext.isSafari){ Y+=scrollNode.scrollTop ;}
  19448. //
  19449. if(position == "N"){
  19450. return Y < offSetWidth+scrollNode.firstChild.offsetTop;
  19451. } else if(position == "W"){
  19452. return X < offSetWidth + scrollNode.firstChild.offsetLeft;
  19453. } else if(position == "E"){
  19454. //other offset
  19455. var offsetRight=(scrollNode.offsetWidth-(scrollNode.firstChild.offsetLeft + scrollNode.firstChild.offsetWidth));
  19456. if(offsetRight<0)offsetRight=0;
  19457. return X > scrollNode.scrollWidth-offsetRight-offSetWidth;
  19458. } else if(position == "S"){
  19459. //other offset
  19460. var offsetDown=(scrollNode.offsetHeight-(scrollNode.firstChild.offsetTop + scrollNode.firstChild.offsetHeight));
  19461. if(offsetDown<0)offsetDown=0;
  19462. return Y > scrollNode.scrollHeight -offsetDown- offSetWidth;
  19463. }
  19464. return false;
  19465. }
  19466. var showButtons = (function() {
  19467. buttonGrow.show();
  19468. var x1, y1, x2, y2;
  19469. try {
  19470. var bb = this.canvas.getRootNode().childNodes[1].getBBox();
  19471. x1 = bb.x;
  19472. y1 = bb.y;
  19473. x2 = bb.x + bb.width;
  19474. y2 = bb.y + bb.height;
  19475. } catch(e) {
  19476. this.canvas.getChildShapes(true).each(function(shape) {
  19477. var absBounds = shape.absoluteBounds();
  19478. var ul = absBounds.upperLeft();
  19479. var lr = absBounds.lowerRight();
  19480. if(x1 == undefined) {
  19481. x1 = ul.x;
  19482. y1 = ul.y;
  19483. x2 = lr.x;
  19484. y2 = lr.y;
  19485. } else {
  19486. x1 = Math.min(x1, ul.x);
  19487. y1 = Math.min(y1, ul.y);
  19488. x2 = Math.max(x2, lr.x);
  19489. y2 = Math.max(y2, lr.y);
  19490. }
  19491. });
  19492. }
  19493. var w = canvas.bounds.width();
  19494. var h = canvas.bounds.height();
  19495. var isEmpty = canvas.getChildNodes().size()==0;
  19496. if(position=="N" && (y1>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL || (isEmpty && h>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL))) buttonShrink.show();
  19497. else if(position=="E" && (w-x2)>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL) buttonShrink.show();
  19498. else if(position=="S" && (h-y2)>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL) buttonShrink.show();
  19499. else if(position=="W" && (x1>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL || (isEmpty && w>ORYX.CONFIG.CANVAS_RESIZE_INTERVAL))) buttonShrink.show();
  19500. else buttonShrink.hide();
  19501. }).bind(this);
  19502. var hideButtons = function() {
  19503. buttonGrow.hide();
  19504. buttonShrink.hide();
  19505. }
  19506. // If the mouse move is over the button area, show the button
  19507. scrollNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEMOVE, function(event){ if( isOverOffset(event) ){showButtons();} else {hideButtons()}} , false );
  19508. // If the mouse is over the button, show them
  19509. buttonGrow.addEventListener( ORYX.CONFIG.EVENT_MOUSEOVER, function(event){showButtons();}, true );
  19510. buttonShrink.addEventListener( ORYX.CONFIG.EVENT_MOUSEOVER, function(event){showButtons();}, true );
  19511. // If the mouse is out, hide the button
  19512. //scrollNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){button.hide()}, true )
  19513. parentNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){hideButtons()} , true );
  19514. //svgRootNode.addEventListener( ORYX.CONFIG.EVENT_MOUSEOUT, function(event){ inCanvas = false } , true );
  19515. // Hide the button initialy
  19516. hideButtons();
  19517. // Add the callbacks
  19518. buttonGrow.addEventListener('click', function(){callback( position ); showButtons();}, true);
  19519. buttonShrink.addEventListener('click', function(){callback( position, true ); showButtons();}, true);
  19520. }
  19521. });
  19522. /**
  19523. * Copyright (c) 2008
  19524. * Willi Tscheschner
  19525. *
  19526. * Permission is hereby granted, free of charge, to any person obtaining a
  19527. * copy of this software and associated documentation files (the "Software"),
  19528. * to deal in the Software without restriction, including without limitation
  19529. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19530. * and/or sell copies of the Software, and to permit persons to whom the
  19531. * Software is furnished to do so, subject to the following conditions:
  19532. *
  19533. * The above copyright notice and this permission notice shall be included in
  19534. * all copies or substantial portions of the Software.
  19535. *
  19536. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19537. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19538. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19539. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19540. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19541. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19542. * DEALINGS IN THE SOFTWARE.
  19543. **/
  19544. if (!ORYX.Plugins)
  19545. ORYX.Plugins = new Object();
  19546. ORYX.Plugins.RenameShapes = Clazz.extend({
  19547. facade: undefined,
  19548. construct: function(facade){
  19549. this.facade = facade;
  19550. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DBLCLICK, this.actOnDBLClick.bind(this));
  19551. this.facade.offer({
  19552. keyCodes: [{
  19553. keyCode: 113, // F2-Key
  19554. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  19555. }
  19556. ],
  19557. functionality: this.renamePerF2.bind(this)
  19558. });
  19559. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.hide.bind(this), true )
  19560. },
  19561. /**
  19562. * This method handles the "F2" key down event. The selected shape are looked
  19563. * up and the editing of title/name of it gets started.
  19564. */
  19565. renamePerF2 : function() {
  19566. var selectedShapes = this.facade.getSelection();
  19567. this.actOnDBLClick(undefined, selectedShapes.first());
  19568. },
  19569. actOnDBLClick: function(evt, shape){
  19570. if( !(shape instanceof ORYX.Core.Shape) ){ return }
  19571. // Destroys the old input, if there is one
  19572. this.destroy();
  19573. // Get all properties which where at least one ref to view is set
  19574. var props = shape.getStencil().properties().findAll(function(item){
  19575. return (item.refToView()
  19576. && item.refToView().length > 0
  19577. && item.directlyEditable());
  19578. });
  19579. // from these, get all properties where write access are and the type is String
  19580. props = props.findAll(function(item){ return !item.readonly() && item.type() == ORYX.CONFIG.TYPE_STRING });
  19581. // Get all ref ids
  19582. var allRefToViews = props.collect(function(prop){ return prop.refToView() }).flatten().compact();
  19583. // Get all labels from the shape with the ref ids
  19584. var labels = shape.getLabels().findAll(function(label){ return allRefToViews.any(function(toView){ return label.id.endsWith(toView) }); })
  19585. // If there are no referenced labels --> return
  19586. if( labels.length == 0 ){ return }
  19587. // Define the nearest label
  19588. var nearestLabel = labels.length <= 1 ? labels[0] : null;
  19589. if( !nearestLabel ){
  19590. nearestLabel = labels.find(function(label){ return label.node == evt.target || label.node == evt.target.parentNode })
  19591. if( !nearestLabel ){
  19592. var evtCoord = this.facade.eventCoordinates(evt);
  19593. var trans = this.facade.getCanvas().rootNode.lastChild.getScreenCTM();
  19594. evtCoord.x *= trans.a;
  19595. evtCoord.y *= trans.d;
  19596. var diff = labels.collect(function(label){
  19597. var center = this.getCenterPosition( label.node );
  19598. var len = Math.sqrt( Math.pow(center.x - evtCoord.x, 2) + Math.pow(center.y - evtCoord.y, 2));
  19599. return {diff: len, label: label}
  19600. }.bind(this));
  19601. diff.sort(function(a, b){ return a.diff > b.diff })
  19602. nearestLabel = diff[0].label;
  19603. }
  19604. }
  19605. // Get the particular property for the label
  19606. var prop = props.find(function(item){ return item.refToView().any(function(toView){ return nearestLabel.id == shape.id + toView })});
  19607. // Set all particular config values
  19608. var htmlCont = this.facade.getCanvas().getHTMLContainer().id;
  19609. // Get the center position from the nearest label
  19610. var width = Math.min(Math.max(100, shape.bounds.width()), 200);
  19611. var center = this.getCenterPosition( nearestLabel.node );
  19612. center.x -= (width/2);
  19613. var propId = prop.prefix() + "-" + prop.id();
  19614. // Set the config values for the TextField/Area
  19615. var config = {
  19616. renderTo : htmlCont,
  19617. value : shape.properties[propId],
  19618. x : (center.x < 10) ? 10 : center.x,
  19619. y : center.y,
  19620. width : width,
  19621. style : 'position:absolute',
  19622. allowBlank : prop.optional(),
  19623. maxLength : prop.length(),
  19624. emptyText : prop.title(),
  19625. cls : 'x_form_text_set_absolute'
  19626. }
  19627. // Depending on the property, generate
  19628. // ether an TextArea or TextField
  19629. if(prop.wrapLines()) {
  19630. config.y -= (60/2);
  19631. config['grow'] = true;
  19632. this.shownTextField = new Ext.form.TextArea(config);
  19633. } else {
  19634. config.y -= (20/2);
  19635. this.shownTextField = new Ext.form.TextField(config);
  19636. }
  19637. //focus
  19638. this.shownTextField.focus();
  19639. // Define event handler
  19640. // Blur -> Destroy
  19641. // Change -> Set new values
  19642. this.shownTextField.on( 'blur', this.destroy.bind(this) )
  19643. this.shownTextField.on( 'change', function(node, value){
  19644. var currentEl = shape;
  19645. var oldValue = currentEl.properties[propId];
  19646. var newValue = value;
  19647. var facade = this.facade;
  19648. if (oldValue != newValue) {
  19649. // Implement the specific command for property change
  19650. var commandClass = ORYX.Core.Command.extend({
  19651. construct: function(){
  19652. this.el = currentEl;
  19653. this.propId = propId;
  19654. this.oldValue = oldValue;
  19655. this.newValue = newValue;
  19656. this.facade = facade;
  19657. },
  19658. execute: function(){
  19659. this.el.setProperty(this.propId, this.newValue);
  19660. //this.el.update();
  19661. this.facade.setSelection([this.el]);
  19662. this.facade.getCanvas().update();
  19663. this.facade.updateSelection();
  19664. },
  19665. rollback: function(){
  19666. this.el.setProperty(this.propId, this.oldValue);
  19667. //this.el.update();
  19668. this.facade.setSelection([this.el]);
  19669. this.facade.getCanvas().update();
  19670. this.facade.updateSelection();
  19671. }
  19672. })
  19673. // Instanciated the class
  19674. var command = new commandClass();
  19675. // Execute the command
  19676. this.facade.executeCommands([command]);
  19677. }
  19678. }.bind(this) )
  19679. // Diable the keydown in the editor (that when hitting the delete button, the shapes not get deleted)
  19680. this.facade.disableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  19681. },
  19682. getCenterPosition: function(svgNode){
  19683. if (!svgNode) { return {x:0, y:0} }
  19684. var center = {x: 0, y:0 };
  19685. var trans,scale,transLocal,bounds;
  19686. var useParent = false;
  19687. try {
  19688. if (('hidden' === svgNode.getAttributeNS(null, 'visibility')&&svgNode.childNodes.length>0)
  19689. ||svgNode.childNodes.length === 0) {
  19690. useParent = true;
  19691. }
  19692. var el = useParent ? svgNode.parentNode : svgNode;
  19693. trans = el.getTransformToElement(this.facade.getCanvas().rootNode.lastChild);
  19694. scale = this.facade.getCanvas().rootNode.lastChild.getScreenCTM();
  19695. transLocal = el.getTransformToElement(el.parentNode);
  19696. } catch(e){
  19697. return {x:0, y:0}
  19698. }
  19699. center.x = trans.e - transLocal.e;
  19700. center.y = trans.f - transLocal.f;
  19701. try {
  19702. bounds = svgNode.getBBox();
  19703. if (!useParent&&!(bounds.x<-1000)) {
  19704. bounds.y -= 1;
  19705. } else {
  19706. bounds = {x:Number(svgNode.getAttribute('x')), y:Number(svgNode.getAttribute('y')), width:0, height:0};
  19707. }
  19708. } catch(e){
  19709. bounds = {x:Number(svgNode.getAttribute('x')), y:Number(svgNode.getAttribute('y')), width:0, height:0};
  19710. }
  19711. center.x += bounds.x;
  19712. center.y += bounds.y;
  19713. center.x += bounds.width/2;
  19714. center.y += bounds.height/2;
  19715. center.x *= scale.a;
  19716. center.y *= scale.d;
  19717. return center;
  19718. },
  19719. hide: function(e){
  19720. if (this.shownTextField && (!e || !this.shownTextField.el || e.target !== this.shownTextField.el.dom)) {
  19721. this.shownTextField.onBlur();
  19722. }
  19723. },
  19724. destroy: function(e){
  19725. if( this.shownTextField ){
  19726. this.shownTextField.destroy();
  19727. delete this.shownTextField;
  19728. this.facade.enableEvent(ORYX.CONFIG.EVENT_KEYDOWN);
  19729. }
  19730. }
  19731. });
  19732. /**
  19733. * Copyright (c) 2008
  19734. * Willi Tscheschner
  19735. *
  19736. * Permission is hereby granted, free of charge, to any person obtaining a
  19737. * copy of this software and associated documentation files (the "Software"),
  19738. * to deal in the Software without restriction, including without limitation
  19739. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19740. * and/or sell copies of the Software, and to permit persons to whom the
  19741. * Software is furnished to do so, subject to the following conditions:
  19742. *
  19743. * The above copyright notice and this permission notice shall be included in
  19744. * all copies or substantial portions of the Software.
  19745. *
  19746. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19747. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19748. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19749. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19750. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19751. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19752. * DEALINGS IN THE SOFTWARE.
  19753. **/
  19754. /**
  19755. * This plugin offer the functionality of undo/redo
  19756. * Therewith the command pattern is used.
  19757. *
  19758. * A Plugin which want that the changes could get undo/redo has
  19759. * to implement a command-class (which implements the method .execute(), .rollback()).
  19760. * Those instance of class must be execute thru the facade.executeCommands(). If so,
  19761. * those command get stored here in the undo/redo stack and can get reset/restore.
  19762. *
  19763. **/
  19764. if (!ORYX.Plugins)
  19765. ORYX.Plugins = new Object();
  19766. ORYX.Plugins.Undo = Clazz.extend({
  19767. // Defines the facade
  19768. facade : undefined,
  19769. // Defines the undo/redo Stack
  19770. undoStack : [],
  19771. redoStack : [],
  19772. // Constructor
  19773. construct: function(facade){
  19774. this.facade = facade;
  19775. // Offers the functionality of undo
  19776. this.facade.offer({
  19777. name : ORYX.I18N.Undo.undo,
  19778. description : ORYX.I18N.Undo.undoDesc,
  19779. icon : ORYX.PATH + "images/arrow_undo.png",
  19780. keyCodes: [{
  19781. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  19782. keyCode: 90,
  19783. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  19784. }
  19785. ],
  19786. functionality : this.doUndo.bind(this),
  19787. group : ORYX.I18N.Undo.group,
  19788. isEnabled : function(){ return this.undoStack.length > 0 }.bind(this),
  19789. index : 0
  19790. });
  19791. // Offers the functionality of redo
  19792. this.facade.offer({
  19793. name : ORYX.I18N.Undo.redo,
  19794. description : ORYX.I18N.Undo.redoDesc,
  19795. icon : ORYX.PATH + "images/arrow_redo.png",
  19796. keyCodes: [{
  19797. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  19798. keyCode: 89,
  19799. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  19800. }
  19801. ],
  19802. functionality : this.doRedo.bind(this),
  19803. group : ORYX.I18N.Undo.group,
  19804. isEnabled : function(){ return this.redoStack.length > 0 }.bind(this),
  19805. index : 1
  19806. });
  19807. // Register on event for executing commands --> store all commands in a stack
  19808. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, this.handleExecuteCommands.bind(this) );
  19809. },
  19810. /**
  19811. * Stores all executed commands in a stack
  19812. *
  19813. * @param {Object} evt
  19814. */
  19815. handleExecuteCommands: function( evt ){
  19816. // If the event has commands
  19817. if( !evt.commands ){ return }
  19818. // Add the commands to a undo stack ...
  19819. this.undoStack.push( evt.commands );
  19820. // ...and delete the redo stack
  19821. this.redoStack = [];
  19822. // Update
  19823. this.facade.getCanvas().update();
  19824. this.facade.updateSelection();
  19825. },
  19826. /**
  19827. * Does the undo
  19828. *
  19829. */
  19830. doUndo: function(){
  19831. // Get the last commands
  19832. var lastCommands = this.undoStack.pop();
  19833. if( lastCommands ){
  19834. // Add the commands to the redo stack
  19835. this.redoStack.push( lastCommands );
  19836. // Rollback every command
  19837. for(var i=lastCommands.length-1; i>=0; --i){
  19838. lastCommands[i].rollback();
  19839. }
  19840. // Update and refresh the canvas
  19841. //this.facade.getCanvas().update();
  19842. //this.facade.updateSelection();
  19843. this.facade.raiseEvent({
  19844. type : ORYX.CONFIG.EVENT_UNDO_ROLLBACK,
  19845. commands: lastCommands
  19846. });
  19847. // Update
  19848. this.facade.getCanvas().update();
  19849. this.facade.updateSelection();
  19850. }
  19851. },
  19852. /**
  19853. * Does the redo
  19854. *
  19855. */
  19856. doRedo: function(){
  19857. // Get the last commands from the redo stack
  19858. var lastCommands = this.redoStack.pop();
  19859. if( lastCommands ){
  19860. // Add this commands to the undo stack
  19861. this.undoStack.push( lastCommands );
  19862. // Execute those commands
  19863. lastCommands.each(function(command){
  19864. command.execute();
  19865. });
  19866. // Update and refresh the canvas
  19867. //this.facade.getCanvas().update();
  19868. //this.facade.updateSelection();
  19869. this.facade.raiseEvent({
  19870. type : ORYX.CONFIG.EVENT_UNDO_EXECUTE,
  19871. commands: lastCommands
  19872. });
  19873. // Update
  19874. this.facade.getCanvas().update();
  19875. this.facade.updateSelection();
  19876. }
  19877. }
  19878. });
  19879. /**
  19880. * Copyright (c) 2008
  19881. * Willi Tscheschner
  19882. *
  19883. * Permission is hereby granted, free of charge, to any person obtaining a
  19884. * copy of this software and associated documentation files (the "Software"),
  19885. * to deal in the Software without restriction, including without limitation
  19886. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19887. * and/or sell copies of the Software, and to permit persons to whom the
  19888. * Software is furnished to do so, subject to the following conditions:
  19889. *
  19890. * The above copyright notice and this permission notice shall be included in
  19891. * all copies or substantial portions of the Software.
  19892. *
  19893. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19894. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19895. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19896. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19897. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19898. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  19899. * DEALINGS IN THE SOFTWARE.
  19900. **/
  19901. if(!ORYX.Plugins)
  19902. ORYX.Plugins = new Object();
  19903. /**
  19904. * Supports EPCs by offering a syntax check and export and import ability..
  19905. *
  19906. *
  19907. */
  19908. ORYX.Plugins.ProcessLink = Clazz.extend({
  19909. facade: undefined,
  19910. /**
  19911. * Offers the plugin functionality:
  19912. *
  19913. */
  19914. construct: function(facade) {
  19915. this.facade = facade;
  19916. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPERTY_CHANGED, this.propertyChanged.bind(this) );
  19917. },
  19918. /**
  19919. *
  19920. * @param {Object} option
  19921. */
  19922. propertyChanged: function( option, node){
  19923. if( option.name !== "oryx-refuri" || !node instanceof ORYX.Core.Node ){ return }
  19924. if( option.value && option.value.length > 0 && option.value != "undefined"){
  19925. this.show( node, option.value );
  19926. } else {
  19927. this.hide( node );
  19928. }
  19929. },
  19930. /**
  19931. * Shows the Link for a particular shape with a specific url
  19932. *
  19933. * @param {Object} shape
  19934. * @param {Object} url
  19935. */
  19936. show: function( shape, url){
  19937. // Generate the svg-representation of a link
  19938. var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null ,
  19939. [ 'a',
  19940. {'target': '_blank'},
  19941. ['path',
  19942. { "stroke-width": 1.0, "stroke":"#00DD00", "fill": "#00AA00", "d": "M3,3 l0,-2.5 l7.5,0 l0,-2.5 l7.5,4.5 l-7.5,3.5 l0,-2.5 l-8,0", "line-captions": "round"}
  19943. ]
  19944. ]);
  19945. var link = ORYX.Editor.graft("http://www.w3.org/2000/svg", null ,
  19946. [ 'a',
  19947. {'target': '_blank'},
  19948. ['path', { "style": "fill:#92BFFC;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", "d": "M0 1.44 L0 15.05 L11.91 15.05 L11.91 5.98 L7.37 1.44 L0 1.44 Z"}],
  19949. ['path', { "style": "stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72;fill:none;", "transform": "translate(7.5, -8.5)", "d": "M0 10.51 L0 15.05 L4.54 15.05"}],
  19950. ['path', { "style": "fill:#f28226;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:0.72", "transform": "translate(-3, -1)", "d": "M0 8.81 L0 13.06 L5.95 13.06 L5.95 15.05 A50.2313 50.2313 -175.57 0 0 10.77 11.08 A49.9128 49.9128 -1.28 0 0 5.95 6.54 L5.95 8.81 L0 8.81 Z"}],
  19951. ]);
  19952. /*
  19953. *
  19954. * [ 'a',
  19955. {'target': '_blank'},
  19956. ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M7,4 l0,2"}],
  19957. ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M4,8 l-2,0 l0,6"}],
  19958. ['path', { "style": "fill:none;stroke-width:0.5px; stroke:#000000", "d": "M10,8 l2,0 l0,6"}],
  19959. ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 0}],
  19960. ['rect', { "style": "fill:#ffafff;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 4, "y": 6}],
  19961. ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 0, "y": 12}],
  19962. ['rect', { "style": "fill:#96ff96;stroke:#000000;stroke-width:1", "width": 6, "height": 4, "x": 8, "y": 12}],
  19963. ['rect', { "style": "fill:none;stroke:none;pointer-events:all", "width": 14, "height": 16, "x": 0, "y": 0}]
  19964. ]);
  19965. */
  19966. // Set the link with the special namespace
  19967. link.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", url);
  19968. // Shows the link in the overlay
  19969. this.facade.raiseEvent({
  19970. type: ORYX.CONFIG.EVENT_OVERLAY_SHOW,
  19971. id: "arissupport.urlref_" + shape.id,
  19972. shapes: [shape],
  19973. node: link,
  19974. nodePosition: "SE"
  19975. });
  19976. },
  19977. /**
  19978. * Hides the Link for a particular shape
  19979. *
  19980. * @param {Object} shape
  19981. */
  19982. hide: function( shape ){
  19983. this.facade.raiseEvent({
  19984. type: ORYX.CONFIG.EVENT_OVERLAY_HIDE,
  19985. id: "arissupport.urlref_" + shape.id
  19986. });
  19987. }
  19988. });/**
  19989. * Copyright (c) 2006
  19990. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  19991. *
  19992. * Permission is hereby granted, free of charge, to any person obtaining a
  19993. * copy of this software and associated documentation files (the "Software"),
  19994. * to deal in the Software without restriction, including without limitation
  19995. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19996. * and/or sell copies of the Software, and to permit persons to whom the
  19997. * Software is furnished to do so, subject to the following conditions:
  19998. *
  19999. * The above copyright notice and this permission notice shall be included in
  20000. * all copies or substantial portions of the Software.
  20001. *
  20002. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20003. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20004. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20005. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20006. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20007. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20008. * DEALINGS IN THE SOFTWARE.
  20009. **/
  20010. Array.prototype.insertFrom = function(from, to){
  20011. to = Math.max(0, to);
  20012. from = Math.min( Math.max(0, from), this.length-1 );
  20013. var el = this[from];
  20014. var old = this.without(el);
  20015. var newA = old.slice(0, to);
  20016. newA.push(el);
  20017. if(old.length > to ){
  20018. newA = newA.concat(old.slice(to))
  20019. };
  20020. return newA;
  20021. }
  20022. if(!ORYX.Plugins)
  20023. ORYX.Plugins = new Object();
  20024. ORYX.Plugins.Arrangement = ORYX.Plugins.AbstractPlugin.extend({
  20025. facade: undefined,
  20026. construct: function(facade) {
  20027. this.facade = facade;
  20028. // Z-Ordering
  20029. /** Hide for SIGNAVIO
  20030. this.facade.offer({
  20031. 'name':ORYX.I18N.Arrangement.btf,
  20032. 'functionality': this.setZLevel.bind(this, this.setToTop),
  20033. 'group': ORYX.I18N.Arrangement.groupZ,
  20034. 'icon': ORYX.PATH + "images/shape_move_front.png",
  20035. 'description': ORYX.I18N.Arrangement.btfDesc,
  20036. 'index': 1,
  20037. 'minShape': 1});
  20038. this.facade.offer({
  20039. 'name':ORYX.I18N.Arrangement.btb,
  20040. 'functionality': this.setZLevel.bind(this, this.setToBack),
  20041. 'group': ORYX.I18N.Arrangement.groupZ,
  20042. 'icon': ORYX.PATH + "images/shape_move_back.png",
  20043. 'description': ORYX.I18N.Arrangement.btbDesc,
  20044. 'index': 2,
  20045. 'minShape': 1});
  20046. this.facade.offer({
  20047. 'name':ORYX.I18N.Arrangement.bf,
  20048. 'functionality': this.setZLevel.bind(this, this.setForward),
  20049. 'group': ORYX.I18N.Arrangement.groupZ,
  20050. 'icon': ORYX.PATH + "images/shape_move_forwards.png",
  20051. 'description': ORYX.I18N.Arrangement.bfDesc,
  20052. 'index': 3,
  20053. 'minShape': 1});
  20054. this.facade.offer({
  20055. 'name':ORYX.I18N.Arrangement.bb,
  20056. 'functionality': this.setZLevel.bind(this, this.setBackward),
  20057. 'group': ORYX.I18N.Arrangement.groupZ,
  20058. 'icon': ORYX.PATH + "images/shape_move_backwards.png",
  20059. 'description': ORYX.I18N.Arrangement.bbDesc,
  20060. 'index': 4,
  20061. 'minShape': 1});
  20062. // Aligment
  20063. this.facade.offer({
  20064. 'name':ORYX.I18N.Arrangement.ab,
  20065. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_BOTTOM]),
  20066. 'group': ORYX.I18N.Arrangement.groupA,
  20067. 'icon': ORYX.PATH + "images/shape_align_bottom.png",
  20068. 'description': ORYX.I18N.Arrangement.abDesc,
  20069. 'index': 1,
  20070. 'minShape': 2});
  20071. this.facade.offer({
  20072. 'name':ORYX.I18N.Arrangement.at,
  20073. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_TOP]),
  20074. 'group': ORYX.I18N.Arrangement.groupA,
  20075. 'icon': ORYX.PATH + "images/shape_align_top.png",
  20076. 'description': ORYX.I18N.Arrangement.atDesc,
  20077. 'index': 3,
  20078. 'minShape': 2});
  20079. this.facade.offer({
  20080. 'name':ORYX.I18N.Arrangement.al,
  20081. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_LEFT]),
  20082. 'group': ORYX.I18N.Arrangement.groupA,
  20083. 'icon': ORYX.PATH + "images/shape_align_left.png",
  20084. 'description': ORYX.I18N.Arrangement.alDesc,
  20085. 'index': 4,
  20086. 'minShape': 2});
  20087. this.facade.offer({
  20088. 'name':ORYX.I18N.Arrangement.ar,
  20089. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_RIGHT]),
  20090. 'group': ORYX.I18N.Arrangement.groupA,
  20091. 'icon': ORYX.PATH + "images/shape_align_right.png",
  20092. 'description': ORYX.I18N.Arrangement.arDesc,
  20093. 'index': 6,
  20094. 'minShape': 2});
  20095. **/
  20096. this.facade.offer({
  20097. 'name':ORYX.I18N.Arrangement.am,
  20098. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_MIDDLE]),
  20099. 'group': ORYX.I18N.Arrangement.groupA,
  20100. 'icon': ORYX.PATH + "images/shape_align_middle.png",
  20101. 'description': ORYX.I18N.Arrangement.amDesc,
  20102. 'index': 1,
  20103. 'minShape': 2});
  20104. this.facade.offer({
  20105. 'name':ORYX.I18N.Arrangement.ac,
  20106. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_CENTER]),
  20107. 'group': ORYX.I18N.Arrangement.groupA,
  20108. 'icon': ORYX.PATH + "images/shape_align_center.png",
  20109. 'description': ORYX.I18N.Arrangement.acDesc,
  20110. 'index': 2,
  20111. 'minShape': 2});
  20112. this.facade.offer({
  20113. 'name':ORYX.I18N.Arrangement.as,
  20114. 'functionality': this.alignShapes.bind(this, [ORYX.CONFIG.EDITOR_ALIGN_SIZE]),
  20115. 'group': ORYX.I18N.Arrangement.groupA,
  20116. 'icon': ORYX.PATH + "images/shape_align_size.png",
  20117. 'description': ORYX.I18N.Arrangement.asDesc,
  20118. 'index': 3,
  20119. 'minShape': 2});
  20120. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, this.setZLevel.bind(this, this.setToTop) );
  20121. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACK, this.setZLevel.bind(this, this.setToBack) );
  20122. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_FORWARD, this.setZLevel.bind(this, this.setForward) );
  20123. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_ARRANGEMENT_BACKWARD, this.setZLevel.bind(this, this.setBackward) );
  20124. },
  20125. onSelectionChanged: function(elemnt){
  20126. var selection = this.facade.getSelection();
  20127. if (selection.length === 1 && selection[0] instanceof ORYX.Core.Edge) {
  20128. this.setToTop(selection);
  20129. }
  20130. },
  20131. setZLevel:function(callback, event){
  20132. //Command-Pattern for dragging one docker
  20133. var zLevelCommand = ORYX.Core.Command.extend({
  20134. construct: function(callback, elements, facade){
  20135. this.callback = callback;
  20136. this.elements = elements;
  20137. // For redo, the previous elements get stored
  20138. this.elAndIndex = elements.map(function(el){ return {el:el, previous:el.parent.children[el.parent.children.indexOf(el)-1]} })
  20139. this.facade = facade;
  20140. },
  20141. execute: function(){
  20142. // Call the defined z-order callback with the elements
  20143. this.callback( this.elements )
  20144. this.facade.setSelection( this.elements )
  20145. },
  20146. rollback: function(){
  20147. // Sort all elements on the index of there containment
  20148. var sortedEl = this.elAndIndex.sortBy( function( el ) {
  20149. var value = el.el;
  20150. var t = $A(value.node.parentNode.childNodes);
  20151. return t.indexOf(value.node);
  20152. });
  20153. // Every element get setted back bevor the old previous element
  20154. for(var i=0; i<sortedEl.length; i++){
  20155. var el = sortedEl[i].el;
  20156. var p = el.parent;
  20157. var oldIndex = p.children.indexOf(el);
  20158. var newIndex = p.children.indexOf(sortedEl[i].previous);
  20159. newIndex = newIndex || 0
  20160. p.children = p.children.insertFrom(oldIndex, newIndex)
  20161. el.node.parentNode.insertBefore(el.node, el.node.parentNode.childNodes[newIndex+1]);
  20162. }
  20163. // Reset the selection
  20164. this.facade.setSelection( this.elements )
  20165. }
  20166. });
  20167. // Instanziate the dockCommand
  20168. var command = new zLevelCommand(callback, this.facade.getSelection(), this.facade);
  20169. if( event.excludeCommand ){
  20170. command.execute();
  20171. } else {
  20172. this.facade.executeCommands( [command] );
  20173. }
  20174. },
  20175. setToTop: function(elements) {
  20176. // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten.
  20177. var tmpElem = elements.sortBy( function(value, index) {
  20178. var t = $A(value.node.parentNode.childNodes);
  20179. return t.indexOf(value.node);
  20180. });
  20181. // Sortiertes Array wird nach oben verschoben.
  20182. tmpElem.each( function(value) {
  20183. var p = value.parent;
  20184. if (p.children.last() === value){
  20185. return;
  20186. }
  20187. p.children = p.children.without( value )
  20188. p.children.push(value);
  20189. value.node.parentNode.appendChild(value.node);
  20190. });
  20191. },
  20192. setToBack: function(elements) {
  20193. // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten.
  20194. var tmpElem = elements.sortBy( function(value, index) {
  20195. var t = $A(value.node.parentNode.childNodes);
  20196. return t.indexOf(value.node);
  20197. });
  20198. tmpElem = tmpElem.reverse();
  20199. // Sortiertes Array wird nach unten verschoben.
  20200. tmpElem.each( function(value) {
  20201. var p = value.parent
  20202. p.children = p.children.without( value )
  20203. p.children.unshift( value );
  20204. value.node.parentNode.insertBefore(value.node, value.node.parentNode.firstChild);
  20205. });
  20206. },
  20207. setBackward: function(elements) {
  20208. // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten.
  20209. var tmpElem = elements.sortBy( function(value, index) {
  20210. var t = $A(value.node.parentNode.childNodes);
  20211. return t.indexOf(value.node);
  20212. });
  20213. // Reverse the elements
  20214. tmpElem = tmpElem.reverse();
  20215. // Delete all Nodes who are the next Node in the nodes-Array
  20216. var compactElem = tmpElem.findAll(function(el) {return !tmpElem.some(function(checkedEl){ return checkedEl.node == el.node.previousSibling})});
  20217. // Sortiertes Array wird nach eine Ebene nach oben verschoben.
  20218. compactElem.each( function(el) {
  20219. if(el.node.previousSibling === null) { return; }
  20220. var p = el.parent;
  20221. var index = p.children.indexOf(el);
  20222. p.children = p.children.insertFrom(index, index-1)
  20223. el.node.parentNode.insertBefore(el.node, el.node.previousSibling);
  20224. });
  20225. },
  20226. setForward: function(elements) {
  20227. // Sortieren des Arrays nach dem Index des SVGKnotens im Bezug auf dem Elternknoten.
  20228. var tmpElem = elements.sortBy( function(value, index) {
  20229. var t = $A(value.node.parentNode.childNodes);
  20230. return t.indexOf(value.node);
  20231. });
  20232. // Delete all Nodes who are the next Node in the nodes-Array
  20233. var compactElem = tmpElem.findAll(function(el) {return !tmpElem.some(function(checkedEl){ return checkedEl.node == el.node.nextSibling})});
  20234. // Sortiertes Array wird eine Ebene nach unten verschoben.
  20235. compactElem.each( function(el) {
  20236. var nextNode = el.node.nextSibling
  20237. if(nextNode === null) { return; }
  20238. var index = el.parent.children.indexOf(el);
  20239. var p = el.parent;
  20240. p.children = p.children.insertFrom(index, index+1)
  20241. el.node.parentNode.insertBefore(nextNode, el.node);
  20242. });
  20243. },
  20244. alignShapes: function(way) {
  20245. var elements = this.facade.getSelection();
  20246. // Set the elements to all Top-Level elements
  20247. elements = this.facade.getCanvas().getShapesWithSharedParent(elements);
  20248. // Get only nodes
  20249. elements = elements.findAll(function(value) {
  20250. return (value instanceof ORYX.Core.Node)
  20251. });
  20252. // Delete all attached intermediate events from the array
  20253. elements = elements.findAll(function(value) {
  20254. var d = value.getIncomingShapes()
  20255. return d.length == 0 || !elements.include(d[0])
  20256. });
  20257. if(elements.length < 2) { return; }
  20258. // get bounds of all shapes.
  20259. var bounds = elements[0].absoluteBounds().clone();
  20260. elements.each(function(shape) {
  20261. bounds.include(shape.absoluteBounds().clone());
  20262. });
  20263. // get biggest width and heigth
  20264. var maxWidth = 0;
  20265. var maxHeight = 0;
  20266. elements.each(function(shape){
  20267. maxWidth = Math.max(shape.bounds.width(), maxWidth);
  20268. maxHeight = Math.max(shape.bounds.height(), maxHeight);
  20269. });
  20270. var commandClass = ORYX.Core.Command.extend({
  20271. construct: function(elements, bounds, maxHeight, maxWidth, way, plugin){
  20272. this.elements = elements;
  20273. this.bounds = bounds;
  20274. this.maxHeight = maxHeight;
  20275. this.maxWidth = maxWidth;
  20276. this.way = way;
  20277. this.facade = plugin.facade;
  20278. this.plugin = plugin;
  20279. this.orgPos = [];
  20280. },
  20281. setBounds: function(shape, maxSize) {
  20282. if(!maxSize)
  20283. maxSize = {width: ORYX.CONFIG.MAXIMUM_SIZE, height: ORYX.CONFIG.MAXIMUM_SIZE};
  20284. if(!shape.bounds) { throw "Bounds not definined." }
  20285. var newBounds = {
  20286. a: {x: shape.bounds.upperLeft().x - (this.maxWidth - shape.bounds.width())/2,
  20287. y: shape.bounds.upperLeft().y - (this.maxHeight - shape.bounds.height())/2},
  20288. b: {x: shape.bounds.lowerRight().x + (this.maxWidth - shape.bounds.width())/2,
  20289. y: shape.bounds.lowerRight().y + (this.maxHeight - shape.bounds.height())/2}
  20290. }
  20291. /* If the new width of shape exceeds the maximum width, set width value to maximum. */
  20292. if(this.maxWidth > maxSize.width) {
  20293. newBounds.a.x = shape.bounds.upperLeft().x -
  20294. (maxSize.width - shape.bounds.width())/2;
  20295. newBounds.b.x = shape.bounds.lowerRight().x + (maxSize.width - shape.bounds.width())/2
  20296. }
  20297. /* If the new height of shape exceeds the maximum height, set height value to maximum. */
  20298. if(this.maxHeight > maxSize.height) {
  20299. newBounds.a.y = shape.bounds.upperLeft().y -
  20300. (maxSize.height - shape.bounds.height())/2;
  20301. newBounds.b.y = shape.bounds.lowerRight().y + (maxSize.height - shape.bounds.height())/2
  20302. }
  20303. /* set bounds of shape */
  20304. shape.bounds.set(newBounds);
  20305. },
  20306. execute: function(){
  20307. // align each shape according to the way that was specified.
  20308. this.elements.each(function(shape, index) {
  20309. this.orgPos[index] = shape.bounds.upperLeft();
  20310. var relBounds = this.bounds.clone();
  20311. var newCoordinates;
  20312. if (shape.parent && !(shape.parent instanceof ORYX.Core.Canvas) ) {
  20313. var upL = shape.parent.absoluteBounds().upperLeft();
  20314. relBounds.moveBy(-upL.x, -upL.y);
  20315. }
  20316. switch (this.way) {
  20317. // align the shapes in the requested way.
  20318. case ORYX.CONFIG.EDITOR_ALIGN_BOTTOM:
  20319. newCoordinates = {
  20320. x: shape.bounds.upperLeft().x,
  20321. y: relBounds.b.y - shape.bounds.height()
  20322. }; break;
  20323. case ORYX.CONFIG.EDITOR_ALIGN_MIDDLE:
  20324. newCoordinates = {
  20325. x: shape.bounds.upperLeft().x,
  20326. y: (relBounds.a.y + relBounds.b.y - shape.bounds.height()) / 2
  20327. }; break;
  20328. case ORYX.CONFIG.EDITOR_ALIGN_TOP:
  20329. newCoordinates = {
  20330. x: shape.bounds.upperLeft().x,
  20331. y: relBounds.a.y
  20332. }; break;
  20333. case ORYX.CONFIG.EDITOR_ALIGN_LEFT:
  20334. newCoordinates = {
  20335. x: relBounds.a.x,
  20336. y: shape.bounds.upperLeft().y
  20337. }; break;
  20338. case ORYX.CONFIG.EDITOR_ALIGN_CENTER:
  20339. newCoordinates = {
  20340. x: (relBounds.a.x + relBounds.b.x - shape.bounds.width()) / 2,
  20341. y: shape.bounds.upperLeft().y
  20342. }; break;
  20343. case ORYX.CONFIG.EDITOR_ALIGN_RIGHT:
  20344. newCoordinates = {
  20345. x: relBounds.b.x - shape.bounds.width(),
  20346. y: shape.bounds.upperLeft().y
  20347. }; break;
  20348. case ORYX.CONFIG.EDITOR_ALIGN_SIZE:
  20349. if(shape.isResizable) {
  20350. this.orgPos[index] = {a: shape.bounds.upperLeft(), b: shape.bounds.lowerRight()};
  20351. this.setBounds(shape, shape.maximumSize);
  20352. }
  20353. break;
  20354. }
  20355. if (newCoordinates){
  20356. var offset = {
  20357. x: shape.bounds.upperLeft().x - newCoordinates.x,
  20358. y: shape.bounds.upperLeft().y - newCoordinates.y
  20359. }
  20360. // Set the new position
  20361. shape.bounds.moveTo(newCoordinates);
  20362. this.plugin.layoutEdges(shape, shape.getAllDockedShapes(),offset);
  20363. //shape.update()
  20364. }
  20365. }.bind(this));
  20366. //this.facade.getCanvas().update();
  20367. //this.facade.updateSelection();
  20368. },
  20369. rollback: function(){
  20370. this.elements.each(function(shape, index) {
  20371. if (this.way == ORYX.CONFIG.EDITOR_ALIGN_SIZE) {
  20372. if(shape.isResizable) {shape.bounds.set(this.orgPos[index]);}
  20373. } else {shape.bounds.moveTo(this.orgPos[index]);}
  20374. }.bind(this));
  20375. //this.facade.getCanvas().update();
  20376. //this.facade.updateSelection();
  20377. }
  20378. })
  20379. var command = new commandClass(elements, bounds, maxHeight, maxWidth, parseInt(way), this);
  20380. this.facade.executeCommands([command]);
  20381. }
  20382. });/**
  20383. * Copyright (c) 2006
  20384. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  20385. *
  20386. * Permission is hereby granted, free of charge, to any person obtaining a
  20387. * copy of this software and associated documentation files (the "Software"),
  20388. * to deal in the Software without restriction, including without limitation
  20389. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20390. * and/or sell copies of the Software, and to permit persons to whom the
  20391. * Software is furnished to do so, subject to the following conditions:
  20392. *
  20393. * The above copyright notice and this permission notice shall be included in
  20394. * all copies or substantial portions of the Software.
  20395. *
  20396. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20397. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20398. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20399. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20400. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20401. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20402. * DEALINGS IN THE SOFTWARE.
  20403. **/
  20404. if (!ORYX.Plugins)
  20405. ORYX.Plugins = new Object();
  20406. ORYX.Plugins.Save = Clazz.extend({
  20407. facade: undefined,
  20408. processURI: undefined,
  20409. changeSymbol : "*",
  20410. construct: function(facade){
  20411. this.facade = facade;
  20412. this.facade.offer({
  20413. 'name': ORYX.I18N.Save.save,
  20414. 'functionality': this.save.bind(this,false),
  20415. 'group': ORYX.I18N.Save.group,
  20416. 'icon': ORYX.PATH + "images/disk.png",
  20417. 'description': ORYX.I18N.Save.saveDesc,
  20418. 'index': 1,
  20419. 'minShape': 0,
  20420. 'maxShape': 0,
  20421. keyCodes: [{
  20422. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  20423. keyCode: 83, // s-Keycode
  20424. keyAction: ORYX.CONFIG.KEY_ACTION_UP
  20425. }
  20426. ]
  20427. });
  20428. document.addEventListener("keydown", function(e){
  20429. if (e.ctrlKey&&e.keyCode === 83){
  20430. Event.stop(e);
  20431. }
  20432. }, false)
  20433. /*this.facade.offer({
  20434. 'name': ORYX.I18N.Save.saveAs,
  20435. 'functionality': this.save.bind(this,true),
  20436. 'group': ORYX.I18N.Save.group,
  20437. 'icon': ORYX.PATH + "images/disk_multi.png",
  20438. 'description': ORYX.I18N.Save.saveAsDesc,
  20439. 'index': 2,
  20440. 'minShape': 0,
  20441. 'maxShape': 0
  20442. }); */
  20443. window.onbeforeunload = this.onUnLoad.bind(this)
  20444. this.changeDifference = 0;
  20445. // Register on event for executing commands --> store all commands in a stack
  20446. // --> Execute
  20447. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_EXECUTE, function(){ this.changeDifference++; this.updateTitle(); }.bind(this) );
  20448. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_EXECUTE_COMMANDS, function(){ this.changeDifference++; this.updateTitle(); }.bind(this) );
  20449. // --> Rollback
  20450. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_UNDO_ROLLBACK, function(){ this.changeDifference--; this.updateTitle(); }.bind(this) );
  20451. //TODO very critical for load time performance!!!
  20452. //this.serializedDOM = DataManager.__persistDOM(this.facade);
  20453. },
  20454. updateTitle: function(){
  20455. var value = window.document.title || document.getElementsByTagName("title")[0].childNodes[0].nodeValue;
  20456. if (this.changeDifference === 0 && value.startsWith(this.changeSymbol)){
  20457. window.document.title = value.slice(1);
  20458. } else if (this.changeDifference !== 0 && !value.startsWith(this.changeSymbol)){
  20459. window.document.title = this.changeSymbol + "" + value;
  20460. }
  20461. },
  20462. onUnLoad: function(){
  20463. if(this.changeDifference !== 0 || (this.facade.getModelMetaData()['new'] && this.facade.getCanvas().getChildShapes().size() > 0)) {
  20464. return ORYX.I18N.Save.unsavedData;
  20465. }
  20466. },
  20467. saveSynchronously: function(forceNew, modelInfo){
  20468. if (!modelInfo) {
  20469. return;
  20470. }
  20471. var modelMeta = this.facade.getModelMetaData();
  20472. var reqURI = modelMeta.modelHandler;
  20473. // Get the stencilset
  20474. var ss = this.facade.getStencilSets().values()[0]
  20475. var typeTitle = ss.title();
  20476. // Define Default values
  20477. var name = (modelMeta["new"] && modelMeta.name === "") ? ORYX.I18N.Save.newProcess : modelInfo.name;
  20478. var defaultData = {title:Signavio.Utils.escapeHTML(name||""), summary:Signavio.Utils.escapeHTML(modelInfo.description||""), type:typeTitle, url: reqURI, namespace: modelInfo.model.stencilset.namespace, comment: '' }
  20479. // Create a Template
  20480. var dialog = new Ext.XTemplate(
  20481. // TODO find some nice words here -- copy from above ;)
  20482. '<form class="oryx_repository_edit_model" action="#" id="edit_model" onsubmit="return false;">',
  20483. '<fieldset>',
  20484. '<p class="description">' + ORYX.I18N.Save.dialogDesciption + '</p>',
  20485. '<input type="hidden" name="namespace" value="{namespace}" />',
  20486. '<p><label for="edit_model_title">' + ORYX.I18N.Save.dialogLabelTitle + '</label><input type="text" class="text" name="title" value="{title}" id="edit_model_title" onfocus="this.className = \'text activated\'" onblur="this.className = \'text\'"/></p>',
  20487. '<p><label for="edit_model_summary">' + ORYX.I18N.Save.dialogLabelDesc + '</label><textarea rows="5" name="summary" id="edit_model_summary" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{summary}</textarea></p>',
  20488. (modelMeta.versioning) ? '<p><label for="edit_model_comment">' + ORYX.I18N.Save.dialogLabelComment + '</label><textarea rows="5" name="comment" id="edit_model_comment" onfocus="this.className = \'activated\'" onblur="this.className = \'\'">{comment}</textarea></p>' : '',
  20489. '<p><label for="edit_model_type">' + ORYX.I18N.Save.dialogLabelType + '</label><input type="text" name="type" class="text disabled" value="{type}" disabled="disabled" id="edit_model_type" /></p>',
  20490. '</fieldset>',
  20491. '</form>')
  20492. // Create the callback for the template
  20493. callback = function(form){
  20494. // raise loading enable event
  20495. /*this.facade.raiseEvent({
  20496. type: ORYX.CONFIG.EVENT_LOADING_ENABLE,
  20497. text: ORYX.I18N.Save.saving
  20498. });*/
  20499. var title = form.elements["title"].value.strip();
  20500. title = title.length == 0 ? defaultData.title : title;
  20501. var summary = form.elements["summary"].value.strip();
  20502. summary = summary.length == 0 ? defaultData.summary : summary;
  20503. var namespace = form.elements["namespace"].value.strip();
  20504. namespace = namespace.length == 0 ? defaultData.namespace : namespace;
  20505. modelMeta.name = title;
  20506. modelMeta.description = summary;
  20507. modelMeta.parent = modelInfo.parent;
  20508. modelMeta.namespace = namespace;
  20509. //added changing title of page after first save, but with the changed flag
  20510. if(!forceNew) window.document.title = this.changeSymbol + title + " | " + ORYX.CONFIG.APPNAME;
  20511. // Get json
  20512. var json = this.facade.getJSON();
  20513. var glossary = [];
  20514. //Support for glossary
  20515. if (this.facade.hasGlossaryExtension) {
  20516. Ext.apply(json, ORYX.Core.AbstractShape.JSONHelper);
  20517. var allNodes = json.getChildShapes(true);
  20518. var orders = {};
  20519. this.facade.getGlossary().each(function(entry){
  20520. if ("undefined" == typeof orders[entry.shape.resourceId+"-"+entry.property.prefix()+"-"+entry.property.id()]){
  20521. orders[entry.shape.resourceId+"-"+entry.property.prefix()+"-"+entry.property.id()] = 0;
  20522. }
  20523. // Add entry
  20524. glossary.push({
  20525. itemId : entry.glossary,
  20526. elementId : entry.shape.resourceId,
  20527. propertyId : entry.property.prefix()+"-"+entry.property.id(),
  20528. order : orders[entry.shape.resourceId+"-"+entry.property.prefix()+"-"+entry.property.id()]++
  20529. });
  20530. // Replace the property with the generated glossary url
  20531. /*var rId = entry.shape.resourceId;
  20532. var pKe = entry.property.id();
  20533. for (var i=0, size=allNodes.length; i<size; ++i) {
  20534. var sh = allNodes[i];
  20535. if (sh.resourceId == rId) {
  20536. for (var prop in sh.properties) {
  20537. if (prop === pKe) {
  20538. sh.properties[prop] = this.facade.generateGlossaryURL(entry.glossary, sh.properties[prop]);
  20539. break;
  20540. }
  20541. }
  20542. break;
  20543. }
  20544. }*/
  20545. // Replace SVG
  20546. if (entry.property.refToView() && entry.property.refToView().length > 0) {
  20547. entry.property.refToView().each(function(ref){
  20548. var node = $(entry.shape.id+""+ref);
  20549. if (node)
  20550. node.setAttribute("oryx:glossaryIds", entry.glossary + ";")
  20551. })
  20552. }
  20553. }.bind(this))
  20554. // Set the json as string
  20555. json = json.serialize();
  20556. } else {
  20557. json = Ext.encode(json);
  20558. }
  20559. // Set the glossaries as string
  20560. glossary = Ext.encode(glossary);
  20561. var selection = this.facade.getSelection();
  20562. this.facade.setSelection([]);
  20563. // Get the serialized svg image source
  20564. var svgClone = this.facade.getCanvas().getSVGRepresentation(true);
  20565. this.facade.setSelection(selection);
  20566. if (this.facade.getCanvas().properties["oryx-showstripableelements"] === false) {
  20567. var stripOutArray = svgClone.getElementsByClassName("stripable-element");
  20568. for (var i=stripOutArray.length-1; i>=0; i--) {
  20569. stripOutArray[i].parentNode.removeChild(stripOutArray[i]);
  20570. }
  20571. }
  20572. // Remove all forced stripable elements
  20573. var stripOutArray = svgClone.getElementsByClassName("stripable-element-force");
  20574. for (var i=stripOutArray.length-1; i>=0; i--) {
  20575. stripOutArray[i].parentNode.removeChild(stripOutArray[i]);
  20576. }
  20577. // Parse dom to string
  20578. var svgDOM = DataManager.serialize(svgClone);
  20579. var params = {
  20580. json_xml: json,
  20581. svg_xml: svgDOM,
  20582. name: title,
  20583. type: defaultData.type,
  20584. parent: modelMeta.parent,
  20585. description: summary,
  20586. glossary_xml: glossary,
  20587. namespace: modelMeta.namespace,
  20588. views: Ext.util.JSON.encode(modelMeta.views || [])
  20589. };
  20590. var success = false;
  20591. var successFn = function(transport) {
  20592. var loc = transport.getResponseHeader.location;
  20593. if (!this.processURI && loc) {
  20594. this.processURI = loc;
  20595. }
  20596. if( forceNew ){
  20597. var resJSON = transport.responseText.evalJSON();
  20598. var modelURL = location.href.substring(0, location.href.indexOf(location.search)) + '?id=' + resJSON.href.substring(7);
  20599. var newURLWin = new Ext.Window({
  20600. title: ORYX.I18N.Save.savedAs,
  20601. bodyStyle: "background:white;padding:10px",
  20602. width: 'auto',
  20603. height: 'auto',
  20604. html:"<div style='font-weight:bold;margin-bottom:10px'>"+ORYX.I18N.Save.savedDescription+":</div><span><a href='" + modelURL +"' target='_blank'>" + modelURL + "</a></span>",
  20605. buttons:[{text:'Ok',handler:function(){newURLWin.destroy()}}]
  20606. });
  20607. newURLWin.show();
  20608. window.open(modelURL);
  20609. }
  20610. //show saved status
  20611. /*this.facade.raiseEvent({
  20612. type:ORYX.CONFIG.EVENT_LOADING_STATUS,
  20613. text:ORYX.I18N.Save.saved
  20614. });*/
  20615. success = true;
  20616. win.close();
  20617. if (success) {
  20618. // Reset changes
  20619. this.changeDifference = 0;
  20620. this.updateTitle();
  20621. var resJSON = transport.responseText.evalJSON();
  20622. if(resJSON.modelId) {
  20623. modelMeta.modelId = resJSON.modelId;
  20624. }
  20625. if(modelMeta["new"]) {
  20626. modelMeta["new"] = false;
  20627. }
  20628. }
  20629. delete this.saving;
  20630. }.bind(this);
  20631. var failure = function(transport) {
  20632. // raise loading disable event.
  20633. this.facade.raiseEvent({
  20634. type: ORYX.CONFIG.EVENT_LOADING_DISABLE
  20635. });
  20636. win.close();
  20637. if(transport.status && transport.status === 401) {
  20638. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.notAuthorized).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).center().syncSize();
  20639. } else if(transport.status && transport.status === 403) {
  20640. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.noRights).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).center().syncSize();
  20641. } else if(transport.statusText === "transaction aborted") {
  20642. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.transAborted).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).center().syncSize();
  20643. } else if(transport.statusText === "communication failure") {
  20644. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.comFailed).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).center().syncSize();
  20645. } else {
  20646. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.failed).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).center().syncSize();
  20647. }
  20648. delete this.saving;
  20649. }.bind(this);
  20650. if(modelMeta["new"]) {
  20651. // Send the request out
  20652. params.id = modelMeta.modelId;
  20653. this.sendSaveRequest('POST', reqURI, params, true, successFn, failure);
  20654. } else if(forceNew) {
  20655. this.sendSaveRequest('POST', reqURI, params, true, successFn, failure);
  20656. } else {
  20657. params.id = modelMeta.modelId;
  20658. // Send the request out
  20659. this.sendSaveRequest('PUT', reqURI, params, false, successFn, failure);
  20660. }
  20661. }.bind(this);
  20662. // Create a new window
  20663. win = new Ext.Window({
  20664. id : 'Propertie_Window',
  20665. width : 'auto',
  20666. height : 'auto',
  20667. title : forceNew ? ORYX.I18N.Save.saveAsTitle : ORYX.I18N.Save.save,
  20668. modal : true,
  20669. resize : false,
  20670. bodyStyle: 'background:#FFFFFF',
  20671. html : dialog.apply( defaultData ),
  20672. defaultButton: 0,
  20673. buttons:[{
  20674. text: ORYX.I18N.Save.saveBtn,
  20675. handler: function(){
  20676. win.body.mask(ORYX.I18N.Save.pleaseWait, "x-waiting-box");
  20677. window.setTimeout(function(){
  20678. callback($('edit_model'));
  20679. }.bind(this), 10);
  20680. },
  20681. listeners:{
  20682. render:function(){
  20683. this.focus();
  20684. }
  20685. }
  20686. },{
  20687. text: ORYX.I18N.Save.close,
  20688. handler: function(){
  20689. win.close();
  20690. }.bind(this)
  20691. }],
  20692. listeners: {
  20693. close: function(){
  20694. win.destroy();
  20695. delete this.saving;
  20696. }.bind(this)
  20697. }
  20698. });
  20699. win.show();
  20700. },
  20701. /**
  20702. * Get the model data and call the success callback
  20703. *
  20704. * @param {Function} success Success callback
  20705. */
  20706. retrieveModelData: function(success){
  20707. var onComplete = function(){
  20708. Ext.getBody().unmask();
  20709. }
  20710. var modelMeta = this.facade.getModelMetaData();
  20711. new Ajax.Request("../service/model/" + modelMeta.modelId + "/json", {
  20712. method: 'get',
  20713. asynchronous: true,
  20714. requestHeaders: {
  20715. "Accept":"application/json"
  20716. },
  20717. encoding: 'UTF-8',
  20718. onSuccess: (function(transport) {
  20719. modelInfo = (transport.responseText||"{}").evalJSON();
  20720. onComplete();
  20721. success(modelInfo);
  20722. }).bind(this),
  20723. onException: function(){
  20724. // raise loading disable event.
  20725. this.facade.raiseEvent({
  20726. type: ORYX.CONFIG.EVENT_LOADING_DISABLE
  20727. });
  20728. delete this.saving;
  20729. onComplete();
  20730. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.exception).setIcon(Ext.Msg.ERROR).getDialog().setWidth(260).syncSize();
  20731. }.bind(this),
  20732. onFailure: (function(transport) {
  20733. // raise loading disable event.
  20734. this.facade.raiseEvent({
  20735. type: ORYX.CONFIG.EVENT_LOADING_DISABLE
  20736. });
  20737. delete this.saving;
  20738. onComplete();
  20739. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.failed).setIcon(Ext.Msg.ERROR).getDialog().setWidth(260).syncSize();
  20740. }).bind(this),
  20741. on401: (function(transport) {
  20742. // raise loading disable event.
  20743. this.facade.raiseEvent({
  20744. type: ORYX.CONFIG.EVENT_LOADING_DISABLE
  20745. });
  20746. delete this.saving;
  20747. onComplete();
  20748. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.notAuthorized).setIcon(Ext.Msg.WARNING).getDialog().setWidth(260).syncSize();
  20749. }).bind(this),
  20750. on403: (function(transport) {
  20751. // raise loading disable event.
  20752. this.facade.raiseEvent({
  20753. type: ORYX.CONFIG.EVENT_LOADING_DISABLE
  20754. });
  20755. delete this.saving;
  20756. onComplete();
  20757. Ext.Msg.alert(ORYX.I18N.Oryx.title, ORYX.I18N.Save.noRights).setIcon(Ext.Msg.ERROR).getDialog().setWidth(260).syncSize();
  20758. }).bind(this)
  20759. });
  20760. },
  20761. sendSaveRequest: function(method, url, params, forceNew, success, failure){
  20762. var saveUri;
  20763. if(forceNew == false) {
  20764. saveUri = "../service/model/" + params.id + "/save";
  20765. } else {
  20766. saveUri = "../service/model/new";
  20767. }
  20768. // Send the request to the server.
  20769. Ext.Ajax.request({
  20770. url : saveUri,
  20771. method : method,
  20772. timeout : 1800000,
  20773. disableCaching : true,
  20774. headers : {'Accept':"application/json", 'Content-Type':'charset=UTF-8'},
  20775. params : params,
  20776. success : success,
  20777. failure : failure
  20778. });
  20779. },
  20780. /**
  20781. * Saves the current process to the server.
  20782. */
  20783. save: function(forceNew, event){
  20784. // Check if currently is saving
  20785. if (this.saving){
  20786. return;
  20787. }
  20788. this.saving = true;
  20789. this.facade.raiseEvent({
  20790. type: ORYX.CONFIG.EVENT_ABOUT_TO_SAVE
  20791. });
  20792. // ... save synchronously
  20793. window.setTimeout((function(){
  20794. var meta = this.facade.getModelMetaData();
  20795. // Check if new...
  20796. if (meta["new"]){
  20797. this.saveSynchronously(forceNew, meta);
  20798. } else {
  20799. Ext.getBody().mask(ORYX.I18N.Save.retrieveData, "x-waiting-box");
  20800. // ...otherwise, get the current model data first.
  20801. this.retrieveModelData(this.saveSynchronously.bind(this, forceNew))
  20802. }
  20803. }).bind(this), 10);
  20804. return true;
  20805. }
  20806. });
  20807. /**
  20808. * Copyright (c) 2006
  20809. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  20810. *
  20811. * Permission is hereby granted, free of charge, to any person obtaining a
  20812. * copy of this software and associated documentation files (the "Software"),
  20813. * to deal in the Software without restriction, including without limitation
  20814. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20815. * and/or sell copies of the Software, and to permit persons to whom the
  20816. * Software is furnished to do so, subject to the following conditions:
  20817. *
  20818. * The above copyright notice and this permission notice shall be included in
  20819. * all copies or substantial portions of the Software.
  20820. *
  20821. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20822. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20823. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20824. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20825. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20826. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20827. * DEALINGS IN THE SOFTWARE.
  20828. **/
  20829. /**
  20830. * @namespace Oryx name space for plugins
  20831. * @name ORYX.Plugins
  20832. */
  20833. if(!ORYX.Plugins)
  20834. ORYX.Plugins = new Object();
  20835. /**
  20836. * The view plugin offers all of zooming functionality accessible over the
  20837. * tool bar. This are zoom in, zoom out, zoom to standard, zoom fit to model.
  20838. *
  20839. * @class ORYX.Plugins.View
  20840. * @extends Clazz
  20841. * @param {Object} facade The editor facade for plugins.
  20842. */
  20843. ORYX.Plugins.View = {
  20844. /** @lends ORYX.Plugins.View.prototype */
  20845. facade: undefined,
  20846. construct: function(facade, ownPluginData) {
  20847. this.facade = facade;
  20848. //Standard Values
  20849. this.zoomLevel = 1.0;
  20850. this.maxFitToScreenLevel=1.5;
  20851. this.minZoomLevel = 0.1;
  20852. this.maxZoomLevel = 2.5;
  20853. this.diff=5; //difference between canvas and view port, s.th. like toolbar??
  20854. //Read properties
  20855. ownPluginData.properties.each( function(property) {
  20856. if (property.zoomLevel) {this.zoomLevel = Number(1.0);}
  20857. if (property.maxFitToScreenLevel) {this.maxFitToScreenLevel=Number(property.maxFitToScreenLevel);}
  20858. if (property.minZoomLevel) {this.minZoomLevel = Number(property.minZoomLevel);}
  20859. if (property.maxZoomLevel) {this.maxZoomLevel = Number(property.maxZoomLevel);}
  20860. }.bind(this));
  20861. /* Register zoom in */
  20862. this.facade.offer({
  20863. 'name':ORYX.I18N.View.zoomIn,
  20864. 'functionality': this.zoom.bind(this, [1.0 + ORYX.CONFIG.ZOOM_OFFSET]),
  20865. 'group': ORYX.I18N.View.group,
  20866. 'icon': ORYX.PATH + "images/magnifier_zoom_in.png",
  20867. 'description': ORYX.I18N.View.zoomInDesc,
  20868. 'index': 1,
  20869. 'minShape': 0,
  20870. 'maxShape': 0,
  20871. 'isEnabled': function(){return this.zoomLevel < this.maxZoomLevel }.bind(this)});
  20872. /* Register zoom out */
  20873. this.facade.offer({
  20874. 'name':ORYX.I18N.View.zoomOut,
  20875. 'functionality': this.zoom.bind(this, [1.0 - ORYX.CONFIG.ZOOM_OFFSET]),
  20876. 'group': ORYX.I18N.View.group,
  20877. 'icon': ORYX.PATH + "images/magnifier_zoom_out.png",
  20878. 'description': ORYX.I18N.View.zoomOutDesc,
  20879. 'index': 2,
  20880. 'minShape': 0,
  20881. 'maxShape': 0,
  20882. 'isEnabled': function(){ return this._checkSize() }.bind(this)});
  20883. /* Register zoom standard */
  20884. this.facade.offer({
  20885. 'name':ORYX.I18N.View.zoomStandard,
  20886. 'functionality': this.setAFixZoomLevel.bind(this, 1),
  20887. 'group': ORYX.I18N.View.group,
  20888. 'icon': ORYX.PATH + "images/zoom_standard.png",
  20889. 'cls' : 'icon-large',
  20890. 'description': ORYX.I18N.View.zoomStandardDesc,
  20891. 'index': 3,
  20892. 'minShape': 0,
  20893. 'maxShape': 0,
  20894. 'isEnabled': function(){return this.zoomLevel != 1}.bind(this)
  20895. });
  20896. /* Register zoom fit to model */
  20897. this.facade.offer({
  20898. 'name':ORYX.I18N.View.zoomFitToModel,
  20899. 'functionality': this.zoomFitToModel.bind(this),
  20900. 'group': ORYX.I18N.View.group,
  20901. 'icon': ORYX.PATH + "images/image.png",
  20902. 'description': ORYX.I18N.View.zoomFitToModelDesc,
  20903. 'index': 4,
  20904. 'minShape': 0,
  20905. 'maxShape': 0
  20906. });
  20907. },
  20908. /**
  20909. * It sets the zoom level to a fix value and call the zooming function.
  20910. *
  20911. * @param {Number} zoomLevel
  20912. * the zoom level
  20913. */
  20914. setAFixZoomLevel : function(zoomLevel) {
  20915. this.zoomLevel = zoomLevel;
  20916. this._checkZoomLevelRange();
  20917. this.zoom(1);
  20918. },
  20919. /**
  20920. * It does the actual zooming. It changes the viewable size of the canvas
  20921. * and all to its child elements.
  20922. *
  20923. * @param {Number} factor
  20924. * the factor to adjust the zoom level
  20925. */
  20926. zoom: function(factor) {
  20927. // TODO: Zoomen auf allen Objekten im SVG-DOM
  20928. this.zoomLevel *= factor;
  20929. var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode;
  20930. var canvas = this.facade.getCanvas();
  20931. var newWidth = canvas.bounds.width() * this.zoomLevel;
  20932. var newHeight = canvas.bounds.height() * this.zoomLevel;
  20933. /* Set new top offset */
  20934. var offsetTop = (canvas.node.parentNode.parentNode.parentNode.offsetHeight - newHeight) / 2.0;
  20935. offsetTop = offsetTop > 20 ? offsetTop - 20 : 0;
  20936. canvas.node.parentNode.parentNode.style.marginTop = offsetTop + "px";
  20937. offsetTop += 5;
  20938. canvas.getHTMLContainer().style.top = offsetTop + "px";
  20939. /*readjust scrollbar*/
  20940. var newScrollTop= scrollNode.scrollTop - Math.round((canvas.getHTMLContainer().parentNode.getHeight()-newHeight) / 2)+this.diff;
  20941. var newScrollLeft= scrollNode.scrollLeft - Math.round((canvas.getHTMLContainer().parentNode.getWidth()-newWidth) / 2)+this.diff;
  20942. /* Set new Zoom-Level */
  20943. canvas.setSize({width: newWidth, height: newHeight}, true);
  20944. /* Set Scale-Factor */
  20945. canvas.node.setAttributeNS(null, "transform", "scale(" +this.zoomLevel+ ")");
  20946. /* Refresh the Selection */
  20947. this.facade.updateSelection();
  20948. scrollNode.scrollTop=newScrollTop;
  20949. scrollNode.scrollLeft=newScrollLeft;
  20950. /* Update the zoom-level*/
  20951. canvas.zoomLevel = this.zoomLevel;
  20952. },
  20953. /**
  20954. * It calculates the zoom level to fit whole model into the visible area
  20955. * of the canvas. Than the model gets zoomed and the position of the
  20956. * scroll bars are adjusted.
  20957. *
  20958. */
  20959. zoomFitToModel: function() {
  20960. /* Get the size of the visible area of the canvas */
  20961. var scrollNode = this.facade.getCanvas().getHTMLContainer().parentNode.parentNode;
  20962. var visibleHeight = scrollNode.getHeight() - 30;
  20963. var visibleWidth = scrollNode.getWidth() - 30;
  20964. var nodes = this.facade.getCanvas().getChildShapes();
  20965. if(!nodes || nodes.length < 1) {
  20966. return false;
  20967. }
  20968. /* Calculate size of canvas to fit the model */
  20969. var bounds = nodes[0].absoluteBounds().clone();
  20970. nodes.each(function(node) {
  20971. bounds.include(node.absoluteBounds().clone());
  20972. });
  20973. /* Set new Zoom Level */
  20974. var scaleFactorWidth = visibleWidth / bounds.width();
  20975. var scaleFactorHeight = visibleHeight / bounds.height();
  20976. /* Choose the smaller zoom level to fit the whole model */
  20977. var zoomFactor = scaleFactorHeight < scaleFactorWidth ? scaleFactorHeight : scaleFactorWidth;
  20978. /*Test if maximum zoom is reached*/
  20979. if(zoomFactor>this.maxFitToScreenLevel){zoomFactor=this.maxFitToScreenLevel}
  20980. /* Do zooming */
  20981. this.setAFixZoomLevel(zoomFactor);
  20982. /* Set scroll bar position */
  20983. scrollNode.scrollTop = Math.round(bounds.upperLeft().y * this.zoomLevel) - 5;
  20984. scrollNode.scrollLeft = Math.round(bounds.upperLeft().x * this.zoomLevel) - 5;
  20985. },
  20986. /**
  20987. * It checks if the zoom level is less or equal to the level, which is required
  20988. * to schow the whole canvas.
  20989. *
  20990. * @private
  20991. */
  20992. _checkSize:function(){
  20993. var canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode;
  20994. var minForCanvas= Math.min((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight()));
  20995. return 1.05 > minForCanvas;
  20996. },
  20997. /**
  20998. * It checks if the zoom level is included in the definined zoom
  20999. * level range.
  21000. *
  21001. * @private
  21002. */
  21003. _checkZoomLevelRange: function() {
  21004. /*var canvasParent=this.facade.getCanvas().getHTMLContainer().parentNode;
  21005. var maxForCanvas= Math.max((canvasParent.parentNode.getWidth()/canvasParent.getWidth()),(canvasParent.parentNode.getHeight()/canvasParent.getHeight()));
  21006. if(this.zoomLevel > maxForCanvas) {
  21007. this.zoomLevel = maxForCanvas;
  21008. }*/
  21009. if(this.zoomLevel < this.minZoomLevel) {
  21010. this.zoomLevel = this.minZoomLevel;
  21011. }
  21012. if(this.zoomLevel > this.maxZoomLevel) {
  21013. this.zoomLevel = this.maxZoomLevel;
  21014. }
  21015. }
  21016. };
  21017. ORYX.Plugins.View = Clazz.extend(ORYX.Plugins.View);
  21018. /**
  21019. * Copyright (c) 2006
  21020. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  21021. *
  21022. * Permission is hereby granted, free of charge, to any person obtaining a
  21023. * copy of this software and associated documentation files (the "Software"),
  21024. * to deal in the Software without restriction, including without limitation
  21025. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  21026. * and/or sell copies of the Software, and to permit persons to whom the
  21027. * Software is furnished to do so, subject to the following conditions:
  21028. *
  21029. * The above copyright notice and this permission notice shall be included in
  21030. * all copies or substantial portions of the Software.
  21031. *
  21032. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21033. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21034. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21035. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21036. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  21037. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  21038. * DEALINGS IN THE SOFTWARE.
  21039. **/
  21040. if(!ORYX.Plugins)
  21041. ORYX.Plugins = new Object();
  21042. ORYX.Plugins.DragDropResize = ORYX.Plugins.AbstractPlugin.extend({
  21043. /**
  21044. * Constructor
  21045. * @param {Object} Facade: The Facade of the Editor
  21046. */
  21047. construct: function(facade) {
  21048. this.facade = facade;
  21049. // Initialize variables
  21050. this.currentShapes = []; // Current selected Shapes
  21051. //this.pluginsData = []; // Available Plugins
  21052. this.toMoveShapes = []; // Shapes there will be moved
  21053. this.distPoints = []; // Distance Points for Snap on Grid
  21054. this.isResizing = false; // Flag: If there was currently resized
  21055. this.dragEnable = false; // Flag: If Dragging is enabled
  21056. this.dragIntialized = false; // Flag: If the Dragging is initialized
  21057. this.edgesMovable = true; // Flag: If an edge is docked it is not movable
  21058. this.offSetPosition = {x: 0, y: 0}; // Offset of the Dragging
  21059. this.faktorXY = {x: 1, y: 1}; // The Current Zoom-Faktor
  21060. this.containmentParentNode; // the current future parent node for the dragged shapes
  21061. this.isAddingAllowed = false; // flag, if adding current selected shapes to containmentParentNode is allowed
  21062. this.isAttachingAllowed = false; // flag, if attaching to the current shape is allowed
  21063. this.callbackMouseMove = this.handleMouseMove.bind(this);
  21064. this.callbackMouseUp = this.handleMouseUp.bind(this);
  21065. // Get the SVG-Containernode
  21066. var containerNode = this.facade.getCanvas().getSvgContainer();
  21067. // Create the Selected Rectangle in the SVG
  21068. this.selectedRect = new ORYX.Plugins.SelectedRect(containerNode);
  21069. // Show grid line if enabled
  21070. if (ORYX.CONFIG.SHOW_GRIDLINE) {
  21071. this.vLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_VERTICAL);
  21072. this.hLine = new ORYX.Plugins.GridLine(containerNode, ORYX.Plugins.GridLine.DIR_HORIZONTAL);
  21073. }
  21074. // Get a HTML-ContainerNode
  21075. containerNode = this.facade.getCanvas().getHTMLContainer();
  21076. this.scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode;
  21077. // Create the southeastern button for resizing
  21078. this.resizerSE = new ORYX.Plugins.Resizer(containerNode, "southeast", this.facade);
  21079. this.resizerSE.registerOnResize(this.onResize.bind(this)); // register the resize callback
  21080. this.resizerSE.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback
  21081. this.resizerSE.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback
  21082. // Create the northwestern button for resizing
  21083. this.resizerNW = new ORYX.Plugins.Resizer(containerNode, "northwest", this.facade);
  21084. this.resizerNW.registerOnResize(this.onResize.bind(this)); // register the resize callback
  21085. this.resizerNW.registerOnResizeEnd(this.onResizeEnd.bind(this)); // register the resize end callback
  21086. this.resizerNW.registerOnResizeStart(this.onResizeStart.bind(this)); // register the resize start callback
  21087. // For the Drag and Drop
  21088. // Register on MouseDown-Event on a Shape
  21089. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this));
  21090. },
  21091. /**
  21092. * On Mouse Down
  21093. *
  21094. */
  21095. handleMouseDown: function(event, uiObj) {
  21096. // If the selection Bounds not intialized and the uiObj is not member of current selectio
  21097. // then return
  21098. if(!this.dragBounds || !this.currentShapes.member(uiObj) || !this.toMoveShapes.length) {return};
  21099. // Start Dragging
  21100. this.dragEnable = true;
  21101. this.dragIntialized = true;
  21102. this.edgesMovable = true;
  21103. // Calculate the current zoom factor
  21104. var a = this.facade.getCanvas().node.getScreenCTM();
  21105. this.faktorXY.x = a.a;
  21106. this.faktorXY.y = a.d;
  21107. // Set the offset position of dragging
  21108. var upL = this.dragBounds.upperLeft();
  21109. this.offSetPosition = {
  21110. x: Event.pointerX(event) - (upL.x * this.faktorXY.x),
  21111. y: Event.pointerY(event) - (upL.y * this.faktorXY.y)};
  21112. this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop};
  21113. // Register on Global Mouse-MOVE Event
  21114. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false);
  21115. // Register on Global Mouse-UP Event
  21116. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true);
  21117. return;
  21118. },
  21119. /**
  21120. * On Key Mouse Up
  21121. *
  21122. */
  21123. handleMouseUp: function(event) {
  21124. //disable containment highlighting
  21125. this.facade.raiseEvent({
  21126. type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  21127. highlightId:"dragdropresize.contain"
  21128. });
  21129. this.facade.raiseEvent({
  21130. type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  21131. highlightId:"dragdropresize.attached"
  21132. });
  21133. // If Dragging is finished
  21134. if(this.dragEnable) {
  21135. // and update the current selection
  21136. if(!this.dragIntialized) {
  21137. // Do Method after Dragging
  21138. this.afterDrag();
  21139. // Check if the Shape is allowed to dock to the other Shape
  21140. if ( this.isAttachingAllowed &&
  21141. this.toMoveShapes.length == 1 && this.toMoveShapes[0] instanceof ORYX.Core.Node &&
  21142. this.toMoveShapes[0].dockers.length > 0) {
  21143. // Get the position and the docker
  21144. var position = this.facade.eventCoordinates( event );
  21145. var docker = this.toMoveShapes[0].dockers[0];
  21146. //Command-Pattern for dragging several Shapes
  21147. var dockCommand = ORYX.Core.Command.extend({
  21148. construct: function(docker, position, newDockedShape, facade){
  21149. this.docker = docker;
  21150. this.newPosition = position;
  21151. this.newDockedShape = newDockedShape;
  21152. this.newParent = newDockedShape.parent || facade.getCanvas();
  21153. this.oldPosition = docker.parent.bounds.center();
  21154. this.oldDockedShape = docker.getDockedShape();
  21155. this.oldParent = docker.parent.parent || facade.getCanvas();
  21156. this.facade = facade;
  21157. if( this.oldDockedShape ){
  21158. this.oldPosition = docker.parent.absoluteBounds().center();
  21159. }
  21160. },
  21161. execute: function(){
  21162. this.dock( this.newDockedShape, this.newParent, this.newPosition );
  21163. // Raise Event for having the docked shape on top of the other shape
  21164. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_ARRANGEMENT_TOP, excludeCommand: true})
  21165. },
  21166. rollback: function(){
  21167. this.dock( this.oldDockedShape, this.oldParent, this.oldPosition );
  21168. },
  21169. dock:function( toDockShape, parent, pos ){
  21170. // Add to the same parent Shape
  21171. parent.add( this.docker.parent )
  21172. // Set the Docker to the new Shape
  21173. this.docker.setDockedShape( undefined );
  21174. this.docker.bounds.centerMoveTo( pos )
  21175. this.docker.setDockedShape( toDockShape );
  21176. //this.docker.update();
  21177. this.facade.setSelection( [this.docker.parent] );
  21178. this.facade.getCanvas().update();
  21179. this.facade.updateSelection();
  21180. }
  21181. });
  21182. // Instanziate the dockCommand
  21183. var commands = [new dockCommand(docker, position, this.containmentParentNode, this.facade)];
  21184. this.facade.executeCommands(commands);
  21185. // Check if adding is allowed to the other Shape
  21186. } else if( this.isAddingAllowed ) {
  21187. // Refresh all Shapes --> Set the new Bounds
  21188. this.refreshSelectedShapes();
  21189. }
  21190. this.facade.updateSelection();
  21191. //this.currentShapes.each(function(shape) {shape.update()})
  21192. // Raise Event: Dragging is finished
  21193. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_DRAGDROP_END});
  21194. }
  21195. if (this.vLine)
  21196. this.vLine.hide();
  21197. if (this.hLine)
  21198. this.hLine.hide();
  21199. }
  21200. // Disable
  21201. this.dragEnable = false;
  21202. // UnRegister on Global Mouse-UP/-Move Event
  21203. document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.callbackMouseUp, true);
  21204. document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.callbackMouseMove, false);
  21205. return;
  21206. },
  21207. /**
  21208. * On Key Mouse Move
  21209. *
  21210. */
  21211. handleMouseMove: function(event) {
  21212. // If dragging is not enabled, go return
  21213. if(!this.dragEnable) { return };
  21214. // If Dragging is initialized
  21215. if(this.dragIntialized) {
  21216. // Raise Event: Drag will be started
  21217. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_DRAGDROP_START});
  21218. this.dragIntialized = false;
  21219. // And hide the resizers and the highlighting
  21220. this.resizerSE.hide();
  21221. this.resizerNW.hide();
  21222. // if only edges are selected, containmentParentNode must be the canvas
  21223. this._onlyEdges = this.currentShapes.all(function(currentShape) {
  21224. return (currentShape instanceof ORYX.Core.Edge);
  21225. });
  21226. // /* If only edges are selected, check if they are movable. An Edge is
  21227. // * movable in case it is not docked
  21228. // */
  21229. // if(this._onlyEdges) {
  21230. // this.currentShapes.each(function(edge) {
  21231. // if(edge.isDocked()) {
  21232. // this.edgesMovable = false;
  21233. // throw $break;
  21234. // }
  21235. // }.bind(this));
  21236. // }
  21237. // Do method before Drag
  21238. this.beforeDrag();
  21239. this._currentUnderlyingNodes = [];
  21240. }
  21241. // Calculate the new position
  21242. var position = {
  21243. x: Event.pointerX(event) - this.offSetPosition.x,
  21244. y: Event.pointerY(event) - this.offSetPosition.y}
  21245. position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
  21246. position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;
  21247. // If not the Control-Key are pressed
  21248. var modifierKeyPressed = event.shiftKey || event.ctrlKey;
  21249. if(ORYX.CONFIG.GRID_ENABLED && !modifierKeyPressed) {
  21250. // Snap the current position to the nearest Snap-Point
  21251. position = this.snapToGrid(position);
  21252. } else {
  21253. if (this.vLine)
  21254. this.vLine.hide();
  21255. if (this.hLine)
  21256. this.hLine.hide();
  21257. }
  21258. // Adjust the point by the zoom faktor
  21259. position.x /= this.faktorXY.x;
  21260. position.y /= this.faktorXY.y;
  21261. // Set that the position is not lower than zero
  21262. position.x = Math.max( 0 , position.x)
  21263. position.y = Math.max( 0 , position.y)
  21264. // Set that the position is not bigger than the canvas
  21265. var c = this.facade.getCanvas();
  21266. position.x = Math.min( c.bounds.width() - this.dragBounds.width(), position.x)
  21267. position.y = Math.min( c.bounds.height() - this.dragBounds.height(), position.y)
  21268. // Drag this bounds
  21269. this.dragBounds.moveTo(position);
  21270. // Update all selected shapes and the selection rectangle
  21271. //this.refreshSelectedShapes();
  21272. this.resizeRectangle(this.dragBounds);
  21273. this.isAttachingAllowed = false;
  21274. //check, if a node can be added to the underlying node
  21275. var underlyingNodes = $A(this.facade.getCanvas().getAbstractShapesAtPosition(this.facade.eventCoordinates(event)));
  21276. var checkIfAttachable = this.toMoveShapes.length == 1 && this.toMoveShapes[0] instanceof ORYX.Core.Node && this.toMoveShapes[0].dockers.length > 0
  21277. checkIfAttachable = checkIfAttachable && underlyingNodes.length != 1
  21278. if( !checkIfAttachable &&
  21279. underlyingNodes.length === this._currentUnderlyingNodes.length &&
  21280. underlyingNodes.all(function(node, index){return this._currentUnderlyingNodes[index] === node}.bind(this))) {
  21281. return
  21282. } else if(this._onlyEdges) {
  21283. this.isAddingAllowed = true;
  21284. this.containmentParentNode = this.facade.getCanvas();
  21285. } else {
  21286. /* Check the containment and connection rules */
  21287. var options = {
  21288. event : event,
  21289. underlyingNodes : underlyingNodes,
  21290. checkIfAttachable : checkIfAttachable
  21291. };
  21292. this.checkRules(options);
  21293. }
  21294. this._currentUnderlyingNodes = underlyingNodes.reverse();
  21295. //visualize the containment result
  21296. if( this.isAttachingAllowed ) {
  21297. this.facade.raiseEvent({
  21298. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  21299. highlightId: "dragdropresize.attached",
  21300. elements: [this.containmentParentNode],
  21301. style: ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE,
  21302. color: ORYX.CONFIG.SELECTION_VALID_COLOR
  21303. });
  21304. } else {
  21305. this.facade.raiseEvent({
  21306. type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  21307. highlightId:"dragdropresize.attached"
  21308. });
  21309. }
  21310. if( !this.isAttachingAllowed ){
  21311. if( this.isAddingAllowed ) {
  21312. this.facade.raiseEvent({
  21313. type:ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  21314. highlightId:"dragdropresize.contain",
  21315. elements:[this.containmentParentNode],
  21316. color: ORYX.CONFIG.SELECTION_VALID_COLOR
  21317. });
  21318. } else {
  21319. this.facade.raiseEvent({
  21320. type:ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  21321. highlightId:"dragdropresize.contain",
  21322. elements:[this.containmentParentNode],
  21323. color: ORYX.CONFIG.SELECTION_INVALID_COLOR
  21324. });
  21325. }
  21326. } else {
  21327. this.facade.raiseEvent({
  21328. type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE,
  21329. highlightId:"dragdropresize.contain"
  21330. });
  21331. }
  21332. // Stop the Event
  21333. //Event.stop(event);
  21334. return;
  21335. },
  21336. // /**
  21337. // * Rollbacks the docked shape of an edge, if the edge is not movable.
  21338. // */
  21339. // redockEdges: function() {
  21340. // this._undockedEdgesCommand.dockers.each(function(el){
  21341. // el.docker.setDockedShape(el.dockedShape);
  21342. // el.docker.setReferencePoint(el.refPoint);
  21343. // })
  21344. // },
  21345. /**
  21346. * Checks the containment and connection rules for the selected shapes.
  21347. */
  21348. checkRules : function(options) {
  21349. var event = options.event;
  21350. var underlyingNodes = options.underlyingNodes;
  21351. var checkIfAttachable = options.checkIfAttachable;
  21352. var noEdges = options.noEdges;
  21353. //get underlying node that is not the same than one of the currently selected shapes or
  21354. // a child of one of the selected shapes with the highest z Order.
  21355. // The result is a shape or the canvas
  21356. this.containmentParentNode = underlyingNodes.reverse().find((function(node) {
  21357. return (node instanceof ORYX.Core.Canvas) ||
  21358. (((node instanceof ORYX.Core.Node) || ((node instanceof ORYX.Core.Edge) && !noEdges))
  21359. && (!(this.currentShapes.member(node) ||
  21360. this.currentShapes.any(function(shape) {
  21361. return (shape.children.length > 0 && shape.getChildNodes(true).member(node));
  21362. }))));
  21363. }).bind(this));
  21364. if( checkIfAttachable ){
  21365. this.isAttachingAllowed = this.facade.getRules().canConnect({
  21366. sourceShape: this.containmentParentNode,
  21367. edgeShape: this.toMoveShapes[0],
  21368. targetShape: this.toMoveShapes[0]
  21369. });
  21370. if ( this.isAttachingAllowed ) {
  21371. var point = this.facade.eventCoordinates(event);
  21372. this.isAttachingAllowed = this.containmentParentNode.isPointOverOffset( point.x, point.y );
  21373. }
  21374. }
  21375. if( !this.isAttachingAllowed ){
  21376. //check all selected shapes, if they can be added to containmentParentNode
  21377. this.isAddingAllowed = this.toMoveShapes.all((function(currentShape) {
  21378. if(currentShape instanceof ORYX.Core.Edge ||
  21379. currentShape instanceof ORYX.Core.Controls.Docker ||
  21380. this.containmentParentNode === currentShape.parent) {
  21381. return true;
  21382. } else if(this.containmentParentNode !== currentShape) {
  21383. if(!(this.containmentParentNode instanceof ORYX.Core.Edge) || !noEdges) {
  21384. if(this.facade.getRules().canContain({containingShape:this.containmentParentNode,
  21385. containedShape:currentShape})) {
  21386. return true;
  21387. }
  21388. }
  21389. }
  21390. return false;
  21391. }).bind(this));
  21392. }
  21393. if(!this.isAttachingAllowed && !this.isAddingAllowed &&
  21394. (this.containmentParentNode instanceof ORYX.Core.Edge)) {
  21395. options.noEdges = true;
  21396. options.underlyingNodes.reverse();
  21397. this.checkRules(options);
  21398. }
  21399. },
  21400. /**
  21401. * Redraw the selected Shapes.
  21402. *
  21403. */
  21404. refreshSelectedShapes: function() {
  21405. // If the selection bounds not initialized, return
  21406. if(!this.dragBounds) {return}
  21407. // Calculate the offset between the bounds and the old bounds
  21408. var upL = this.dragBounds.upperLeft();
  21409. var oldUpL = this.oldDragBounds.upperLeft();
  21410. var offset = {
  21411. x: upL.x - oldUpL.x,
  21412. y: upL.y - oldUpL.y };
  21413. // Instanciate the dragCommand
  21414. var commands = [new ORYX.Core.Command.Move(this.toMoveShapes, offset, this.containmentParentNode, this.currentShapes, this)];
  21415. // If the undocked edges command is setted, add this command
  21416. if( this._undockedEdgesCommand instanceof ORYX.Core.Command ){
  21417. commands.unshift( this._undockedEdgesCommand );
  21418. }
  21419. // Execute the commands
  21420. this.facade.executeCommands( commands );
  21421. // copy the bounds to the old bounds
  21422. if( this.dragBounds )
  21423. this.oldDragBounds = this.dragBounds.clone();
  21424. },
  21425. /**
  21426. * Callback for Resize
  21427. *
  21428. */
  21429. onResize: function(bounds) {
  21430. // If the selection bounds not initialized, return
  21431. if(!this.dragBounds) {return}
  21432. this.dragBounds = bounds;
  21433. this.isResizing = true;
  21434. // Update the rectangle
  21435. this.resizeRectangle(this.dragBounds);
  21436. },
  21437. onResizeStart: function() {
  21438. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_RESIZE_START});
  21439. },
  21440. onResizeEnd: function() {
  21441. if (!(this.currentShapes instanceof Array)||this.currentShapes.length<=0) {
  21442. return;
  21443. }
  21444. // If Resizing finished, the Shapes will be resize
  21445. if(this.isResizing) {
  21446. var commandClass = ORYX.Core.Command.extend({
  21447. construct: function(shape, newBounds, plugin){
  21448. this.shape = shape;
  21449. this.oldBounds = shape.bounds.clone();
  21450. this.newBounds = newBounds;
  21451. this.plugin = plugin;
  21452. },
  21453. execute: function(){
  21454. this.shape.bounds.set(this.newBounds.a, this.newBounds.b);
  21455. this.update(this.getOffset(this.oldBounds, this.newBounds));
  21456. },
  21457. rollback: function(){
  21458. this.shape.bounds.set(this.oldBounds.a, this.oldBounds.b);
  21459. this.update(this.getOffset(this.newBounds, this.oldBounds))
  21460. },
  21461. getOffset:function(b1, b2){
  21462. return {
  21463. x: b2.a.x - b1.a.x,
  21464. y: b2.a.y - b1.a.y,
  21465. xs: b2.width()/b1.width(),
  21466. ys: b2.height()/b1.height()
  21467. }
  21468. },
  21469. update:function(offset){
  21470. this.shape.getLabels().each(function(label) {
  21471. label.changed();
  21472. });
  21473. var allEdges = [].concat(this.shape.getIncomingShapes())
  21474. .concat(this.shape.getOutgoingShapes())
  21475. // Remove all edges which are included in the selection from the list
  21476. .findAll(function(r){ return r instanceof ORYX.Core.Edge }.bind(this))
  21477. this.plugin.layoutEdges(this.shape, allEdges, offset);
  21478. this.plugin.facade.setSelection([this.shape]);
  21479. this.plugin.facade.getCanvas().update();
  21480. this.plugin.facade.updateSelection();
  21481. }
  21482. });
  21483. var bounds = this.dragBounds.clone();
  21484. var shape = this.currentShapes[0];
  21485. if(shape.parent) {
  21486. var parentPosition = shape.parent.absoluteXY();
  21487. bounds.moveBy(-parentPosition.x, -parentPosition.y);
  21488. }
  21489. var command = new commandClass(shape, bounds, this);
  21490. this.facade.executeCommands([command]);
  21491. this.isResizing = false;
  21492. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_RESIZE_END});
  21493. }
  21494. },
  21495. /**
  21496. * Prepare the Dragging
  21497. *
  21498. */
  21499. beforeDrag: function(){
  21500. var undockEdgeCommand = ORYX.Core.Command.extend({
  21501. construct: function(moveShapes){
  21502. this.dockers = moveShapes.collect(function(shape){ return shape instanceof ORYX.Core.Controls.Docker ? {docker:shape, dockedShape:shape.getDockedShape(), refPoint:shape.referencePoint} : undefined }).compact();
  21503. },
  21504. execute: function(){
  21505. this.dockers.each(function(el){
  21506. el.docker.setDockedShape(undefined);
  21507. })
  21508. },
  21509. rollback: function(){
  21510. this.dockers.each(function(el){
  21511. el.docker.setDockedShape(el.dockedShape);
  21512. el.docker.setReferencePoint(el.refPoint);
  21513. //el.docker.update();
  21514. })
  21515. }
  21516. });
  21517. this._undockedEdgesCommand = new undockEdgeCommand( this.toMoveShapes );
  21518. this._undockedEdgesCommand.execute();
  21519. },
  21520. hideAllLabels: function(shape) {
  21521. // Hide all labels from the shape
  21522. shape.getLabels().each(function(label) {
  21523. label.hide();
  21524. });
  21525. // Hide all labels from docked shapes
  21526. shape.getAllDockedShapes().each(function(dockedShape) {
  21527. var labels = dockedShape.getLabels();
  21528. if(labels.length > 0) {
  21529. labels.each(function(label) {
  21530. label.hide();
  21531. });
  21532. }
  21533. });
  21534. // Do this recursive for all child shapes
  21535. // EXP-NICO use getShapes
  21536. shape.getChildren().each((function(value) {
  21537. if(value instanceof ORYX.Core.Shape)
  21538. this.hideAllLabels(value);
  21539. }).bind(this));
  21540. },
  21541. /**
  21542. * Finished the Dragging
  21543. *
  21544. */
  21545. afterDrag: function(){
  21546. },
  21547. /**
  21548. * Show all Labels at these shape
  21549. *
  21550. */
  21551. showAllLabels: function(shape) {
  21552. // Show the label of these shape
  21553. //shape.getLabels().each(function(label) {
  21554. for(var i=0; i<shape.length ;i++){
  21555. var label = shape[i];
  21556. label.show();
  21557. }//);
  21558. // Show all labels at docked shapes
  21559. //shape.getAllDockedShapes().each(function(dockedShape) {
  21560. var allDockedShapes = shape.getAllDockedShapes()
  21561. for(var i=0; i<allDockedShapes.length ;i++){
  21562. var dockedShape = allDockedShapes[i];
  21563. var labels = dockedShape.getLabels();
  21564. if(labels.length > 0) {
  21565. labels.each(function(label) {
  21566. label.show();
  21567. });
  21568. }
  21569. }//);
  21570. // Do this recursive
  21571. //shape.children.each((function(value) {
  21572. for(var i=0; i<shape.children.length ;i++){
  21573. var value = shape.children[i];
  21574. if(value instanceof ORYX.Core.Shape)
  21575. this.showAllLabels(value);
  21576. }//).bind(this));
  21577. },
  21578. /**
  21579. * Intialize Method, if there are new Plugins
  21580. *
  21581. */
  21582. /*registryChanged: function(pluginsData) {
  21583. // Save all new Plugin, sorted by group and index
  21584. this.pluginsData = pluginsData.sortBy( function(value) {
  21585. return (value.group + "" + value.index);
  21586. });
  21587. },*/
  21588. /**
  21589. * On the Selection-Changed
  21590. *
  21591. */
  21592. onSelectionChanged: function(event) {
  21593. var elements = event.elements;
  21594. // Reset the drag-variables
  21595. this.dragEnable = false;
  21596. this.dragIntialized = false;
  21597. this.resizerSE.hide();
  21598. this.resizerNW.hide();
  21599. // If there is no elements
  21600. if(!elements || elements.length == 0) {
  21601. // Hide all things and reset all variables
  21602. this.selectedRect.hide();
  21603. this.currentShapes = [];
  21604. this.toMoveShapes = [];
  21605. this.dragBounds = undefined;
  21606. this.oldDragBounds = undefined;
  21607. } else {
  21608. // Set the current Shapes
  21609. this.currentShapes = elements;
  21610. // Get all shapes with the highest parent in object hierarchy (canvas is the top most parent)
  21611. var topLevelElements = this.facade.getCanvas().getShapesWithSharedParent(elements);
  21612. this.toMoveShapes = topLevelElements;
  21613. this.toMoveShapes = this.toMoveShapes.findAll( function(shape) { return shape instanceof ORYX.Core.Node &&
  21614. (shape.dockers.length === 0 || !elements.member(shape.dockers.first().getDockedShape()))});
  21615. elements.each((function(shape){
  21616. if(!(shape instanceof ORYX.Core.Edge)) {return}
  21617. var dks = shape.getDockers()
  21618. var hasF = elements.member(dks.first().getDockedShape());
  21619. var hasL = elements.member(dks.last().getDockedShape());
  21620. // if(!hasL) {
  21621. // this.toMoveShapes.push(dks.last());
  21622. // }
  21623. // if(!hasF){
  21624. // this.toMoveShapes.push(dks.first())
  21625. // }
  21626. /* Enable movement of undocked edges */
  21627. if(!hasF && !hasL) {
  21628. var isUndocked = !dks.first().getDockedShape() && !dks.last().getDockedShape()
  21629. if(isUndocked) {
  21630. this.toMoveShapes = this.toMoveShapes.concat(dks);
  21631. }
  21632. }
  21633. if( shape.dockers.length > 2 && hasF && hasL){
  21634. this.toMoveShapes = this.toMoveShapes.concat(dks.findAll(function(el,index){ return index > 0 && index < dks.length-1}))
  21635. }
  21636. }).bind(this));
  21637. // Calculate the new area-bounds of the selection
  21638. var newBounds = undefined;
  21639. this.toMoveShapes.each(function(value) {
  21640. var shape = value;
  21641. if(value instanceof ORYX.Core.Controls.Docker) {
  21642. /* Get the Shape */
  21643. shape = value.parent;
  21644. }
  21645. if(!newBounds){
  21646. newBounds = shape.absoluteBounds();
  21647. }
  21648. else {
  21649. newBounds.include(shape.absoluteBounds());
  21650. }
  21651. }.bind(this));
  21652. if(!newBounds){
  21653. elements.each(function(value){
  21654. if(!newBounds) {
  21655. newBounds = value.absoluteBounds();
  21656. } else {
  21657. newBounds.include(value.absoluteBounds());
  21658. }
  21659. });
  21660. }
  21661. // Set the new bounds
  21662. this.dragBounds = newBounds;
  21663. this.oldDragBounds = newBounds.clone();
  21664. // Update and show the rectangle
  21665. this.resizeRectangle(newBounds);
  21666. this.selectedRect.show();
  21667. // Show the resize button, if there is only one element and this is resizeable
  21668. if(elements.length == 1 && elements[0].isResizable) {
  21669. var aspectRatio = elements[0].getStencil().fixedAspectRatio() ? elements[0].bounds.width() / elements[0].bounds.height() : undefined;
  21670. this.resizerSE.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio);
  21671. this.resizerSE.show();
  21672. this.resizerNW.setBounds(this.dragBounds, elements[0].minimumSize, elements[0].maximumSize, aspectRatio);
  21673. this.resizerNW.show();
  21674. } else {
  21675. this.resizerSE.setBounds(undefined);
  21676. this.resizerNW.setBounds(undefined);
  21677. }
  21678. // If Snap-To-Grid is enabled, the Snap-Point will be calculate
  21679. if(ORYX.CONFIG.GRID_ENABLED) {
  21680. // Reset all points
  21681. this.distPoints = [];
  21682. if (this.distPointTimeout)
  21683. window.clearTimeout(this.distPointTimeout)
  21684. this.distPointTimeout = window.setTimeout(function(){
  21685. // Get all the shapes, there will consider at snapping
  21686. // Consider only those elements who shares the same parent element
  21687. var distShapes = this.facade.getCanvas().getChildShapes(true).findAll(function(value){
  21688. var parentShape = value.parent;
  21689. while(parentShape){
  21690. if(elements.member(parentShape)) return false;
  21691. parentShape = parentShape.parent
  21692. }
  21693. return true;
  21694. })
  21695. // The current selection will delete from this array
  21696. //elements.each(function(shape) {
  21697. // distShapes = distShapes.without(shape);
  21698. //});
  21699. // For all these shapes
  21700. distShapes.each((function(value) {
  21701. if(!(value instanceof ORYX.Core.Edge)) {
  21702. var ul = value.absoluteXY();
  21703. var width = value.bounds.width();
  21704. var height = value.bounds.height();
  21705. // Add the upperLeft, center and lowerRight - Point to the distancePoints
  21706. this.distPoints.push({
  21707. ul: {
  21708. x: ul.x,
  21709. y: ul.y
  21710. },
  21711. c: {
  21712. x: ul.x + (width / 2),
  21713. y: ul.y + (height / 2)
  21714. },
  21715. lr: {
  21716. x: ul.x + width,
  21717. y: ul.y + height
  21718. }
  21719. });
  21720. }
  21721. }).bind(this));
  21722. }.bind(this), 10)
  21723. }
  21724. }
  21725. },
  21726. /**
  21727. * Adjust an Point to the Snap Points
  21728. *
  21729. */
  21730. snapToGrid: function(position) {
  21731. // Get the current Bounds
  21732. var bounds = this.dragBounds;
  21733. var point = {};
  21734. var ulThres = 6;
  21735. var cThres = 10;
  21736. var lrThres = 6;
  21737. var scale = this.vLine ? this.vLine.getScale() : 1;
  21738. var ul = { x: (position.x/scale), y: (position.y/scale)};
  21739. var c = { x: (position.x/scale) + (bounds.width()/2), y: (position.y/scale) + (bounds.height()/2)};
  21740. var lr = { x: (position.x/scale) + (bounds.width()), y: (position.y/scale) + (bounds.height())};
  21741. var offsetX, offsetY;
  21742. var gridX, gridY;
  21743. // For each distant point
  21744. this.distPoints.each(function(value) {
  21745. var x, y, gx, gy;
  21746. if (Math.abs(value.c.x-c.x) < cThres){
  21747. x = value.c.x-c.x;
  21748. gx = value.c.x;
  21749. }/* else if (Math.abs(value.ul.x-ul.x) < ulThres){
  21750. x = value.ul.x-ul.x;
  21751. gx = value.ul.x;
  21752. } else if (Math.abs(value.lr.x-lr.x) < lrThres){
  21753. x = value.lr.x-lr.x;
  21754. gx = value.lr.x;
  21755. } */
  21756. if (Math.abs(value.c.y-c.y) < cThres){
  21757. y = value.c.y-c.y;
  21758. gy = value.c.y;
  21759. }/* else if (Math.abs(value.ul.y-ul.y) < ulThres){
  21760. y = value.ul.y-ul.y;
  21761. gy = value.ul.y;
  21762. } else if (Math.abs(value.lr.y-lr.y) < lrThres){
  21763. y = value.lr.y-lr.y;
  21764. gy = value.lr.y;
  21765. } */
  21766. if (x !== undefined) {
  21767. offsetX = offsetX === undefined ? x : (Math.abs(x) < Math.abs(offsetX) ? x : offsetX);
  21768. if (offsetX === x)
  21769. gridX = gx;
  21770. }
  21771. if (y !== undefined) {
  21772. offsetY = offsetY === undefined ? y : (Math.abs(y) < Math.abs(offsetY) ? y : offsetY);
  21773. if (offsetY === y)
  21774. gridY = gy;
  21775. }
  21776. });
  21777. if (offsetX !== undefined) {
  21778. ul.x += offsetX;
  21779. ul.x *= scale;
  21780. if (this.vLine&&gridX)
  21781. this.vLine.update(gridX);
  21782. } else {
  21783. ul.x = (position.x - (position.x % (ORYX.CONFIG.GRID_DISTANCE/2)));
  21784. if (this.vLine)
  21785. this.vLine.hide()
  21786. }
  21787. if (offsetY !== undefined) {
  21788. ul.y += offsetY;
  21789. ul.y *= scale;
  21790. if (this.hLine&&gridY)
  21791. this.hLine.update(gridY);
  21792. } else {
  21793. ul.y = (position.y - (position.y % (ORYX.CONFIG.GRID_DISTANCE/2)));
  21794. if (this.hLine)
  21795. this.hLine.hide();
  21796. }
  21797. return ul;
  21798. },
  21799. showGridLine: function(){
  21800. },
  21801. /**
  21802. * Redraw of the Rectangle of the SelectedArea
  21803. * @param {Object} bounds
  21804. */
  21805. resizeRectangle: function(bounds) {
  21806. // Resize the Rectangle
  21807. this.selectedRect.resize(bounds);
  21808. }
  21809. });
  21810. ORYX.Plugins.SelectedRect = Clazz.extend({
  21811. construct: function(parentId) {
  21812. this.parentId = parentId;
  21813. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", $(parentId),
  21814. ['g']);
  21815. this.dashedArea = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node,
  21816. ['rect', {x: 0, y: 0,
  21817. 'stroke-width': 1, stroke: '#777777', fill: 'none',
  21818. 'stroke-dasharray': '2,2',
  21819. 'pointer-events': 'none'}]);
  21820. this.hide();
  21821. },
  21822. hide: function() {
  21823. this.node.setAttributeNS(null, 'display', 'none');
  21824. },
  21825. show: function() {
  21826. this.node.setAttributeNS(null, 'display', '');
  21827. },
  21828. resize: function(bounds) {
  21829. var upL = bounds.upperLeft();
  21830. var padding = ORYX.CONFIG.SELECTED_AREA_PADDING;
  21831. this.dashedArea.setAttributeNS(null, 'width', bounds.width() + 2*padding);
  21832. this.dashedArea.setAttributeNS(null, 'height', bounds.height() + 2*padding);
  21833. this.node.setAttributeNS(null, 'transform', "translate("+ (upL.x - padding) +", "+ (upL.y - padding) +")");
  21834. }
  21835. });
  21836. ORYX.Plugins.GridLine = Clazz.extend({
  21837. construct: function(parentId, direction) {
  21838. if (ORYX.Plugins.GridLine.DIR_HORIZONTAL !== direction && ORYX.Plugins.GridLine.DIR_VERTICAL !== direction) {
  21839. direction = ORYX.Plugins.GridLine.DIR_HORIZONTAL
  21840. }
  21841. this.parent = $(parentId);
  21842. this.direction = direction;
  21843. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parent,
  21844. ['g']);
  21845. this.line = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node,
  21846. ['path', {
  21847. 'stroke-width': 1, stroke: 'silver', fill: 'none',
  21848. 'stroke-dasharray': '5,5',
  21849. 'pointer-events': 'none'}]);
  21850. this.hide();
  21851. },
  21852. hide: function() {
  21853. this.node.setAttributeNS(null, 'display', 'none');
  21854. },
  21855. show: function() {
  21856. this.node.setAttributeNS(null, 'display', '');
  21857. },
  21858. getScale: function(){
  21859. try {
  21860. return this.parent.parentNode.transform.baseVal.getItem(0).matrix.a;
  21861. } catch(e) {
  21862. return 1;
  21863. }
  21864. },
  21865. update: function(pos) {
  21866. if (this.direction === ORYX.Plugins.GridLine.DIR_HORIZONTAL) {
  21867. var y = pos instanceof Object ? pos.y : pos;
  21868. var cWidth = this.parent.parentNode.parentNode.width.baseVal.value/this.getScale();
  21869. this.line.setAttributeNS(null, 'd', 'M 0 '+y+ ' L '+cWidth+' '+y);
  21870. } else {
  21871. var x = pos instanceof Object ? pos.x : pos;
  21872. var cHeight = this.parent.parentNode.parentNode.height.baseVal.value/this.getScale();
  21873. this.line.setAttributeNS(null, 'd', 'M'+x+ ' 0 L '+x+' '+cHeight);
  21874. }
  21875. this.show();
  21876. }
  21877. });
  21878. ORYX.Plugins.GridLine.DIR_HORIZONTAL = "hor";
  21879. ORYX.Plugins.GridLine.DIR_VERTICAL = "ver";
  21880. ORYX.Plugins.Resizer = Clazz.extend({
  21881. construct: function(parentId, orientation, facade) {
  21882. this.parentId = parentId;
  21883. this.orientation = orientation;
  21884. this.facade = facade;
  21885. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", $(this.parentId),
  21886. ['div', {'class': 'resizer_'+ this.orientation, style:'left:0px; top:0px;'}]);
  21887. this.node.addEventListener(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this), true);
  21888. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true);
  21889. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.handleMouseMove.bind(this), false);
  21890. this.dragEnable = false;
  21891. this.offSetPosition = {x: 0, y: 0};
  21892. this.bounds = undefined;
  21893. this.canvasNode = this.facade.getCanvas().node;
  21894. this.minSize = undefined;
  21895. this.maxSize = undefined;
  21896. this.aspectRatio = undefined;
  21897. this.resizeCallbacks = [];
  21898. this.resizeStartCallbacks = [];
  21899. this.resizeEndCallbacks = [];
  21900. this.hide();
  21901. // Calculate the Offset
  21902. this.scrollNode = this.node.parentNode.parentNode.parentNode;
  21903. },
  21904. handleMouseDown: function(event) {
  21905. this.dragEnable = true;
  21906. this.offsetScroll = {x:this.scrollNode.scrollLeft,y:this.scrollNode.scrollTop};
  21907. this.offSetPosition = {
  21908. x: Event.pointerX(event) - this.position.x,
  21909. y: Event.pointerY(event) - this.position.y};
  21910. this.resizeStartCallbacks.each((function(value) {
  21911. value(this.bounds);
  21912. }).bind(this));
  21913. },
  21914. handleMouseUp: function(event) {
  21915. this.dragEnable = false;
  21916. this.containmentParentNode = null;
  21917. this.resizeEndCallbacks.each((function(value) {
  21918. value(this.bounds);
  21919. }).bind(this));
  21920. },
  21921. handleMouseMove: function(event) {
  21922. if(!this.dragEnable) { return }
  21923. if(event.shiftKey || event.ctrlKey) {
  21924. this.aspectRatio = this.bounds.width() / this.bounds.height();
  21925. } else {
  21926. this.aspectRatio = undefined;
  21927. }
  21928. var position = {
  21929. x: Event.pointerX(event) - this.offSetPosition.x,
  21930. y: Event.pointerY(event) - this.offSetPosition.y}
  21931. position.x -= this.offsetScroll.x - this.scrollNode.scrollLeft;
  21932. position.y -= this.offsetScroll.y - this.scrollNode.scrollTop;
  21933. position.x = Math.min( position.x, this.facade.getCanvas().bounds.width())
  21934. position.y = Math.min( position.y, this.facade.getCanvas().bounds.height())
  21935. var offset = {
  21936. x: position.x - this.position.x,
  21937. y: position.y - this.position.y
  21938. }
  21939. if(this.aspectRatio) {
  21940. // fixed aspect ratio
  21941. newAspectRatio = (this.bounds.width()+offset.x) / (this.bounds.height()+offset.y);
  21942. if(newAspectRatio>this.aspectRatio) {
  21943. offset.x = this.aspectRatio * (this.bounds.height()+offset.y) - this.bounds.width();
  21944. } else if(newAspectRatio<this.aspectRatio) {
  21945. offset.y = (this.bounds.width()+offset.x) / this.aspectRatio - this.bounds.height();
  21946. }
  21947. }
  21948. // respect minimum and maximum sizes of stencil
  21949. if(this.orientation==="northwest") {
  21950. if(this.bounds.width()-offset.x > this.maxSize.width) {
  21951. offset.x = -(this.maxSize.width - this.bounds.width());
  21952. if(this.aspectRatio)
  21953. offset.y = this.aspectRatio * offset.x;
  21954. }
  21955. if(this.bounds.width()-offset.x < this.minSize.width) {
  21956. offset.x = -(this.minSize.width - this.bounds.width());
  21957. if(this.aspectRatio)
  21958. offset.y = this.aspectRatio * offset.x;
  21959. }
  21960. if(this.bounds.height()-offset.y > this.maxSize.height) {
  21961. offset.y = -(this.maxSize.height - this.bounds.height());
  21962. if(this.aspectRatio)
  21963. offset.x = offset.y / this.aspectRatio;
  21964. }
  21965. if(this.bounds.height()-offset.y < this.minSize.height) {
  21966. offset.y = -(this.minSize.height - this.bounds.height());
  21967. if(this.aspectRatio)
  21968. offset.x = offset.y / this.aspectRatio;
  21969. }
  21970. } else { // defaults to southeast
  21971. if(this.bounds.width()+offset.x > this.maxSize.width) {
  21972. offset.x = this.maxSize.width - this.bounds.width();
  21973. if(this.aspectRatio)
  21974. offset.y = this.aspectRatio * offset.x;
  21975. }
  21976. if(this.bounds.width()+offset.x < this.minSize.width) {
  21977. offset.x = this.minSize.width - this.bounds.width();
  21978. if(this.aspectRatio)
  21979. offset.y = this.aspectRatio * offset.x;
  21980. }
  21981. if(this.bounds.height()+offset.y > this.maxSize.height) {
  21982. offset.y = this.maxSize.height - this.bounds.height();
  21983. if(this.aspectRatio)
  21984. offset.x = offset.y / this.aspectRatio;
  21985. }
  21986. if(this.bounds.height()+offset.y < this.minSize.height) {
  21987. offset.y = this.minSize.height - this.bounds.height();
  21988. if(this.aspectRatio)
  21989. offset.x = offset.y / this.aspectRatio;
  21990. }
  21991. }
  21992. if(this.orientation==="northwest") {
  21993. var oldLR = {x: this.bounds.lowerRight().x, y: this.bounds.lowerRight().y};
  21994. this.bounds.extend({x:-offset.x, y:-offset.y});
  21995. this.bounds.moveBy(offset);
  21996. } else { // defaults to southeast
  21997. this.bounds.extend(offset);
  21998. }
  21999. this.update();
  22000. this.resizeCallbacks.each((function(value) {
  22001. value(this.bounds);
  22002. }).bind(this));
  22003. Event.stop(event);
  22004. },
  22005. registerOnResizeStart: function(callback) {
  22006. if(!this.resizeStartCallbacks.member(callback)) {
  22007. this.resizeStartCallbacks.push(callback);
  22008. }
  22009. },
  22010. unregisterOnResizeStart: function(callback) {
  22011. if(this.resizeStartCallbacks.member(callback)) {
  22012. this.resizeStartCallbacks = this.resizeStartCallbacks.without(callback);
  22013. }
  22014. },
  22015. registerOnResizeEnd: function(callback) {
  22016. if(!this.resizeEndCallbacks.member(callback)) {
  22017. this.resizeEndCallbacks.push(callback);
  22018. }
  22019. },
  22020. unregisterOnResizeEnd: function(callback) {
  22021. if(this.resizeEndCallbacks.member(callback)) {
  22022. this.resizeEndCallbacks = this.resizeEndCallbacks.without(callback);
  22023. }
  22024. },
  22025. registerOnResize: function(callback) {
  22026. if(!this.resizeCallbacks.member(callback)) {
  22027. this.resizeCallbacks.push(callback);
  22028. }
  22029. },
  22030. unregisterOnResize: function(callback) {
  22031. if(this.resizeCallbacks.member(callback)) {
  22032. this.resizeCallbacks = this.resizeCallbacks.without(callback);
  22033. }
  22034. },
  22035. hide: function() {
  22036. this.node.style.display = "none";
  22037. },
  22038. show: function() {
  22039. if(this.bounds)
  22040. this.node.style.display = "";
  22041. },
  22042. setBounds: function(bounds, min, max, aspectRatio) {
  22043. this.bounds = bounds;
  22044. if(!min)
  22045. min = {width: ORYX.CONFIG.MINIMUM_SIZE, height: ORYX.CONFIG.MINIMUM_SIZE};
  22046. if(!max)
  22047. max = {width: ORYX.CONFIG.MAXIMUM_SIZE, height: ORYX.CONFIG.MAXIMUM_SIZE};
  22048. this.minSize = min;
  22049. this.maxSize = max;
  22050. this.aspectRatio = aspectRatio;
  22051. this.update();
  22052. },
  22053. update: function() {
  22054. if(!this.bounds) { return; }
  22055. var upL = this.bounds.upperLeft();
  22056. if(this.bounds.width() < this.minSize.width) { this.bounds.set(upL.x, upL.y, upL.x + this.minSize.width, upL.y + this.bounds.height())};
  22057. if(this.bounds.height() < this.minSize.height) { this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.minSize.height)};
  22058. if(this.bounds.width() > this.maxSize.width) { this.bounds.set(upL.x, upL.y, upL.x + this.maxSize.width, upL.y + this.bounds.height())};
  22059. if(this.bounds.height() > this.maxSize.height) { this.bounds.set(upL.x, upL.y, upL.x + this.bounds.width(), upL.y + this.maxSize.height)};
  22060. var a = this.canvasNode.getScreenCTM();
  22061. upL.x *= a.a;
  22062. upL.y *= a.d;
  22063. if(this.orientation==="northwest") {
  22064. upL.x -= 13;
  22065. upL.y -= 26;
  22066. } else { // defaults to southeast
  22067. upL.x += (a.a * this.bounds.width()) + 3 ;
  22068. upL.y += (a.d * this.bounds.height()) + 3;
  22069. }
  22070. this.position = upL;
  22071. this.node.style.left = this.position.x + "px";
  22072. this.node.style.top = this.position.y + "px";
  22073. }
  22074. });
  22075. /**
  22076. * Implements a Command to move shapes
  22077. *
  22078. */
  22079. ORYX.Core.Command.Move = ORYX.Core.Command.extend({
  22080. construct: function(moveShapes, offset, parent, selectedShapes, plugin){
  22081. this.moveShapes = moveShapes;
  22082. this.selectedShapes = selectedShapes;
  22083. this.offset = offset;
  22084. this.plugin = plugin;
  22085. // Defines the old/new parents for the particular shape
  22086. this.newParents = moveShapes.collect(function(t){ return parent || t.parent });
  22087. this.oldParents = moveShapes.collect(function(shape){ return shape.parent });
  22088. this.dockedNodes= moveShapes.findAll(function(shape){ return shape instanceof ORYX.Core.Node && shape.dockers.length == 1}).collect(function(shape){ return {docker:shape.dockers[0], dockedShape:shape.dockers[0].getDockedShape(), refPoint:shape.dockers[0].referencePoint} });
  22089. },
  22090. execute: function(){
  22091. this.dockAllShapes()
  22092. // Moves by the offset
  22093. this.move( this.offset);
  22094. // Addes to the new parents
  22095. this.addShapeToParent( this.newParents );
  22096. // Set the selection to the current selection
  22097. this.selectCurrentShapes();
  22098. this.plugin.facade.getCanvas().update();
  22099. this.plugin.facade.updateSelection();
  22100. },
  22101. rollback: function(){
  22102. // Moves by the inverted offset
  22103. var offset = { x:-this.offset.x, y:-this.offset.y };
  22104. this.move( offset );
  22105. // Addes to the old parents
  22106. this.addShapeToParent( this.oldParents );
  22107. this.dockAllShapes(true)
  22108. // Set the selection to the current selection
  22109. this.selectCurrentShapes();
  22110. this.plugin.facade.getCanvas().update();
  22111. this.plugin.facade.updateSelection();
  22112. },
  22113. move:function(offset, doLayout){
  22114. // Move all Shapes by these offset
  22115. for(var i=0; i<this.moveShapes.length ;i++){
  22116. var value = this.moveShapes[i];
  22117. value.bounds.moveBy(offset);
  22118. if (value instanceof ORYX.Core.Node) {
  22119. (value.dockers||[]).each(function(d){
  22120. d.bounds.moveBy(offset);
  22121. })
  22122. // Update all Dockers of Child shapes
  22123. /*var childShapesNodes = value.getChildShapes(true).findAll(function(shape){ return shape instanceof ORYX.Core.Node });
  22124. var childDockedShapes = childShapesNodes.collect(function(shape){ return shape.getAllDockedShapes() }).flatten().uniq();
  22125. var childDockedEdge = childDockedShapes.findAll(function(shape){ return shape instanceof ORYX.Core.Edge });
  22126. childDockedEdge = childDockedEdge.findAll(function(shape){ return shape.getAllDockedShapes().all(function(dsh){ return childShapesNodes.include(dsh) }) });
  22127. var childDockedDockers = childDockedEdge.collect(function(shape){ return shape.dockers }).flatten();
  22128. for (var j = 0; j < childDockedDockers.length; j++) {
  22129. var docker = childDockedDockers[j];
  22130. if (!docker.getDockedShape() && !this.moveShapes.include(docker)) {
  22131. //docker.bounds.moveBy(offset);
  22132. //docker.update();
  22133. }
  22134. }*/
  22135. var allEdges = [].concat(value.getIncomingShapes())
  22136. .concat(value.getOutgoingShapes())
  22137. // Remove all edges which are included in the selection from the list
  22138. .findAll(function(r){ return r instanceof ORYX.Core.Edge && !this.moveShapes.any(function(d){ return d == r || (d instanceof ORYX.Core.Controls.Docker && d.parent == r)}) }.bind(this))
  22139. // Remove all edges which are between the node and a node contained in the selection from the list
  22140. .findAll(function(r){ return (r.dockers.first().getDockedShape() == value || !this.moveShapes.include(r.dockers.first().getDockedShape())) &&
  22141. (r.dockers.last().getDockedShape() == value || !this.moveShapes.include(r.dockers.last().getDockedShape()))}.bind(this))
  22142. // Layout all outgoing/incoming edges
  22143. this.plugin.layoutEdges(value, allEdges, offset);
  22144. var allSameEdges = [].concat(value.getIncomingShapes())
  22145. .concat(value.getOutgoingShapes())
  22146. // Remove all edges which are included in the selection from the list
  22147. .findAll(function(r){ return r instanceof ORYX.Core.Edge && r.dockers.first().isDocked() && r.dockers.last().isDocked() && !this.moveShapes.include(r) && !this.moveShapes.any(function(d){ return d == r || (d instanceof ORYX.Core.Controls.Docker && d.parent == r)}) }.bind(this))
  22148. // Remove all edges which are included in the selection from the list
  22149. .findAll(function(r){ return this.moveShapes.indexOf(r.dockers.first().getDockedShape()) > i || this.moveShapes.indexOf(r.dockers.last().getDockedShape()) > i}.bind(this))
  22150. for (var j = 0; j < allSameEdges.length; j++) {
  22151. for (var k = 1; k < allSameEdges[j].dockers.length-1; k++) {
  22152. var docker = allSameEdges[j].dockers[k];
  22153. if (!docker.getDockedShape() && !this.moveShapes.include(docker)) {
  22154. docker.bounds.moveBy(offset);
  22155. }
  22156. }
  22157. }
  22158. /*var i=-1;
  22159. var nodes = value.getChildShapes(true);
  22160. var allEdges = [];
  22161. while(++i<nodes.length){
  22162. var edges = [].concat(nodes[i].getIncomingShapes())
  22163. .concat(nodes[i].getOutgoingShapes())
  22164. // Remove all edges which are included in the selection from the list
  22165. .findAll(function(r){ return r instanceof ORYX.Core.Edge && !allEdges.include(r) && r.dockers.any(function(d){ return !value.bounds.isIncluded(d.bounds.center)})})
  22166. allEdges = allEdges.concat(edges);
  22167. if (edges.length <= 0){ continue }
  22168. //this.plugin.layoutEdges(nodes[i], edges, offset);
  22169. }*/
  22170. }
  22171. }
  22172. },
  22173. dockAllShapes: function(shouldDocked){
  22174. // Undock all Nodes
  22175. for (var i = 0; i < this.dockedNodes.length; i++) {
  22176. var docker = this.dockedNodes[i].docker;
  22177. docker.setDockedShape( shouldDocked ? this.dockedNodes[i].dockedShape : undefined )
  22178. if (docker.getDockedShape()) {
  22179. docker.setReferencePoint(this.dockedNodes[i].refPoint);
  22180. //docker.update();
  22181. }
  22182. }
  22183. },
  22184. addShapeToParent:function( parents ){
  22185. // For every Shape, add this and reset the position
  22186. for(var i=0; i<this.moveShapes.length ;i++){
  22187. var currentShape = this.moveShapes[i];
  22188. if(currentShape instanceof ORYX.Core.Node &&
  22189. currentShape.parent !== parents[i]) {
  22190. // Calc the new position
  22191. var unul = parents[i].absoluteXY();
  22192. var csul = currentShape.absoluteXY();
  22193. var x = csul.x - unul.x;
  22194. var y = csul.y - unul.y;
  22195. // Add the shape to the new contained shape
  22196. parents[i].add(currentShape);
  22197. // Add all attached shapes as well
  22198. currentShape.getOutgoingShapes((function(shape) {
  22199. if(shape instanceof ORYX.Core.Node && !this.moveShapes.member(shape)) {
  22200. parents[i].add(shape);
  22201. }
  22202. }).bind(this));
  22203. // Set the new position
  22204. if(currentShape instanceof ORYX.Core.Node && currentShape.dockers.length == 1){
  22205. var b = currentShape.bounds;
  22206. x += b.width()/2;y += b.height()/2
  22207. currentShape.dockers.first().bounds.centerMoveTo(x, y);
  22208. } else {
  22209. currentShape.bounds.moveTo(x, y);
  22210. }
  22211. }
  22212. // Update the shape
  22213. //currentShape.update();
  22214. }
  22215. },
  22216. selectCurrentShapes:function(){
  22217. this.plugin.facade.setSelection( this.selectedShapes );
  22218. }
  22219. });
  22220. /**
  22221. * Copyright (c) 2006
  22222. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  22223. *
  22224. * Permission is hereby granted, free of charge, to any person obtaining a
  22225. * copy of this software and associated documentation files (the "Software"),
  22226. * to deal in the Software without restriction, including without limitation
  22227. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  22228. * and/or sell copies of the Software, and to permit persons to whom the
  22229. * Software is furnished to do so, subject to the following conditions:
  22230. *
  22231. * The above copyright notice and this permission notice shall be included in
  22232. * all copies or substantial portions of the Software.
  22233. *
  22234. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22235. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22236. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22237. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22238. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22239. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22240. * DEALINGS IN THE SOFTWARE.
  22241. **/
  22242. if(!ORYX.Plugins)
  22243. ORYX.Plugins = new Object();
  22244. ORYX.Plugins.ShapeHighlighting = Clazz.extend({
  22245. construct: function(facade) {
  22246. this.parentNode = facade.getCanvas().getSvgContainer();
  22247. // The parent Node
  22248. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parentNode,
  22249. ['g']);
  22250. this.highlightNodes = {};
  22251. facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, this.setHighlight.bind(this));
  22252. facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, this.hideHighlight.bind(this));
  22253. },
  22254. setHighlight: function(options) {
  22255. if(options && options.highlightId){
  22256. var node = this.highlightNodes[options.highlightId];
  22257. if(!node){
  22258. node= ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node,
  22259. ['path', {
  22260. "stroke-width": 2.0, "fill":"none"
  22261. }]);
  22262. this.highlightNodes[options.highlightId] = node;
  22263. }
  22264. if(options.elements && options.elements.length > 0) {
  22265. this.setAttributesByStyle( node, options );
  22266. this.show(node);
  22267. } else {
  22268. this.hide(node);
  22269. }
  22270. }
  22271. },
  22272. hideHighlight: function(options) {
  22273. if(options && options.highlightId && this.highlightNodes[options.highlightId]){
  22274. this.hide(this.highlightNodes[options.highlightId]);
  22275. }
  22276. },
  22277. hide: function(node) {
  22278. node.setAttributeNS(null, 'display', 'none');
  22279. },
  22280. show: function(node) {
  22281. node.setAttributeNS(null, 'display', '');
  22282. },
  22283. setAttributesByStyle: function( node, options ){
  22284. // If the style say, that it should look like a rectangle
  22285. if( options.style && options.style == ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE ){
  22286. // Set like this
  22287. var bo = options.elements[0].absoluteBounds();
  22288. var strWidth = options.strokewidth ? options.strokewidth : ORYX.CONFIG.BORDER_OFFSET
  22289. node.setAttributeNS(null, "d", this.getPathRectangle( bo.a, bo.b , strWidth ) );
  22290. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  22291. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2);
  22292. node.setAttributeNS(null, "stroke-width", strWidth);
  22293. } else if(options.elements.length == 1
  22294. && options.elements[0] instanceof ORYX.Core.Edge &&
  22295. options.highlightId != "selection") {
  22296. /* Highlight containment of edge's childs */
  22297. node.setAttributeNS(null, "d", this.getPathEdge(options.elements[0].dockers));
  22298. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  22299. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2);
  22300. node.setAttributeNS(null, "stroke-width", ORYX.CONFIG.OFFSET_EDGE_BOUNDS);
  22301. }else {
  22302. // If not, set just the corners
  22303. node.setAttributeNS(null, "d", this.getPathByElements(options.elements));
  22304. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  22305. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 1.0);
  22306. node.setAttributeNS(null, "stroke-width", options.strokewidth ? options.strokewidth : 2.0);
  22307. }
  22308. },
  22309. getPathByElements: function(elements){
  22310. if(!elements || elements.length <= 0) {return undefined}
  22311. // Get the padding and the size
  22312. var padding = ORYX.CONFIG.SELECTED_AREA_PADDING;
  22313. var path = ""
  22314. // Get thru all Elements
  22315. elements.each((function(element) {
  22316. if(!element) {return}
  22317. // Get the absolute Bounds and the two Points
  22318. var bounds = element.absoluteBounds();
  22319. bounds.widen(padding)
  22320. var a = bounds.upperLeft();
  22321. var b = bounds.lowerRight();
  22322. path = path + this.getPath(a ,b);
  22323. }).bind(this));
  22324. return path;
  22325. },
  22326. getPath: function(a, b){
  22327. return this.getPathCorners(a, b);
  22328. },
  22329. getPathCorners: function(a, b){
  22330. var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;
  22331. var path = ""
  22332. // Set: Upper left
  22333. path = path + "M" + a.x + " " + (a.y + size) + " l0 -" + size + " l" + size + " 0 ";
  22334. // Set: Lower left
  22335. path = path + "M" + a.x + " " + (b.y - size) + " l0 " + size + " l" + size + " 0 ";
  22336. // Set: Lower right
  22337. path = path + "M" + b.x + " " + (b.y - size) + " l0 " + size + " l-" + size + " 0 ";
  22338. // Set: Upper right
  22339. path = path + "M" + b.x + " " + (a.y + size) + " l0 -" + size + " l-" + size + " 0 ";
  22340. return path;
  22341. },
  22342. getPathRectangle: function(a, b, strokeWidth){
  22343. var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;
  22344. var path = ""
  22345. var offset = strokeWidth / 2.0;
  22346. // Set: Upper left
  22347. path = path + "M" + (a.x + offset) + " " + (a.y);
  22348. path = path + " L" + (a.x + offset) + " " + (b.y - offset);
  22349. path = path + " L" + (b.x - offset) + " " + (b.y - offset);
  22350. path = path + " L" + (b.x - offset) + " " + (a.y + offset);
  22351. path = path + " L" + (a.x + offset) + " " + (a.y + offset);
  22352. return path;
  22353. },
  22354. getPathEdge: function(edgeDockers) {
  22355. var length = edgeDockers.length;
  22356. var path = "M" + edgeDockers[0].bounds.center().x + " "
  22357. + edgeDockers[0].bounds.center().y;
  22358. for(i=1; i<length; i++) {
  22359. var dockerPoint = edgeDockers[i].bounds.center();
  22360. path = path + " L" + dockerPoint.x + " " + dockerPoint.y;
  22361. }
  22362. return path;
  22363. }
  22364. });
  22365. ORYX.Plugins.HighlightingSelectedShapes = Clazz.extend({
  22366. construct: function(facade) {
  22367. this.facade = facade;
  22368. this.opacityFull = 0.9;
  22369. this.opacityLow = 0.4;
  22370. // Register on Dragging-Events for show/hide of ShapeMenu
  22371. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START, this.hide.bind(this));
  22372. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END, this.show.bind(this));
  22373. },
  22374. /**
  22375. * On the Selection-Changed
  22376. *
  22377. */
  22378. onSelectionChanged: function(event) {
  22379. if(event.elements && event.elements.length > 1) {
  22380. this.facade.raiseEvent({
  22381. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  22382. highlightId:'selection',
  22383. elements: event.elements.without(event.subSelection),
  22384. color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
  22385. opacity: !event.subSelection ? this.opacityFull : this.opacityLow
  22386. });
  22387. if(event.subSelection){
  22388. this.facade.raiseEvent({
  22389. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  22390. highlightId:'subselection',
  22391. elements: [event.subSelection],
  22392. color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
  22393. opacity: this.opacityFull
  22394. });
  22395. } else {
  22396. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'});
  22397. }
  22398. } else {
  22399. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'selection'});
  22400. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'});
  22401. }
  22402. }
  22403. });/**
  22404. * Copyright (c) 2006
  22405. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  22406. *
  22407. * Permission is hereby granted, free of charge, to any person obtaining a
  22408. * copy of this software and associated documentation files (the "Software"),
  22409. * to deal in the Software without restriction, including without limitation
  22410. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  22411. * and/or sell copies of the Software, and to permit persons to whom the
  22412. * Software is furnished to do so, subject to the following conditions:
  22413. *
  22414. * The above copyright notice and this permission notice shall be included in
  22415. * all copies or substantial portions of the Software.
  22416. *
  22417. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22418. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22419. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22420. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22421. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22422. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22423. * DEALINGS IN THE SOFTWARE.
  22424. **/
  22425. if(!ORYX.Plugins)
  22426. ORYX.Plugins = new Object();
  22427. ORYX.Plugins.DragDocker = Clazz.extend({
  22428. /**
  22429. * Constructor
  22430. * @param {Object} Facade: The Facade of the Editor
  22431. */
  22432. construct: function(facade) {
  22433. this.facade = facade;
  22434. // Set the valid and invalid color
  22435. this.VALIDCOLOR = ORYX.CONFIG.SELECTION_VALID_COLOR;
  22436. this.INVALIDCOLOR = ORYX.CONFIG.SELECTION_INVALID_COLOR;
  22437. // Define Variables
  22438. this.shapeSelection = undefined;
  22439. this.docker = undefined;
  22440. this.dockerParent = undefined;
  22441. this.dockerSource = undefined;
  22442. this.dockerTarget = undefined;
  22443. this.lastUIObj = undefined;
  22444. this.isStartDocker = undefined;
  22445. this.isEndDocker = undefined;
  22446. this.undockTreshold = 10;
  22447. this.initialDockerPosition = undefined;
  22448. this.outerDockerNotMoved = undefined;
  22449. this.isValid = false;
  22450. // For the Drag and Drop
  22451. // Register on MouseDown-Event on a Docker
  22452. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this));
  22453. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DOCKERDRAG, this.handleDockerDrag.bind(this));
  22454. // Register on over/out to show / hide a docker
  22455. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOVER, this.handleMouseOver.bind(this));
  22456. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEOUT, this.handleMouseOut.bind(this));
  22457. },
  22458. /**
  22459. * MouseOut Handler
  22460. *
  22461. */
  22462. handleMouseOut: function(event, uiObj) {
  22463. // If there is a Docker, hide this
  22464. if(!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) {
  22465. uiObj.hide()
  22466. } else if(!this.docker && uiObj instanceof ORYX.Core.Edge) {
  22467. uiObj.dockers.each(function(docker){
  22468. docker.hide();
  22469. })
  22470. }
  22471. },
  22472. /**
  22473. * MouseOver Handler
  22474. *
  22475. */
  22476. handleMouseOver: function(event, uiObj) {
  22477. // If there is a Docker, show this
  22478. if(!this.docker && uiObj instanceof ORYX.Core.Controls.Docker) {
  22479. uiObj.show()
  22480. } else if(!this.docker && uiObj instanceof ORYX.Core.Edge) {
  22481. uiObj.dockers.each(function(docker){
  22482. docker.show();
  22483. })
  22484. }
  22485. },
  22486. /**
  22487. * DockerDrag Handler
  22488. * delegates the uiEvent of the drag event to the mouseDown function
  22489. */
  22490. handleDockerDrag: function(event, uiObj) {
  22491. this.handleMouseDown(event.uiEvent, uiObj);
  22492. },
  22493. /**
  22494. * MouseDown Handler
  22495. *
  22496. */
  22497. handleMouseDown: function(event, uiObj) {
  22498. // If there is a Docker
  22499. if(uiObj instanceof ORYX.Core.Controls.Docker && uiObj.isMovable) {
  22500. /* Buffering shape selection and clear selection*/
  22501. this.shapeSelection = this.facade.getSelection();
  22502. this.facade.setSelection();
  22503. this.docker = uiObj;
  22504. this.initialDockerPosition = this.docker.bounds.center();
  22505. this.outerDockerNotMoved = false;
  22506. this.dockerParent = uiObj.parent;
  22507. // Define command arguments
  22508. this._commandArg = {docker:uiObj, dockedShape:uiObj.getDockedShape(), refPoint:uiObj.referencePoint || uiObj.bounds.center()};
  22509. // Show the Docker
  22510. this.docker.show();
  22511. // If the Dockers Parent is an Edge,
  22512. // and the Docker is either the first or last Docker of the Edge
  22513. if(uiObj.parent instanceof ORYX.Core.Edge &&
  22514. (uiObj.parent.dockers.first() == uiObj || uiObj.parent.dockers.last() == uiObj)) {
  22515. // Get the Edge Source or Target
  22516. if(uiObj.parent.dockers.first() == uiObj && uiObj.parent.dockers.last().getDockedShape()) {
  22517. this.dockerTarget = uiObj.parent.dockers.last().getDockedShape()
  22518. } else if(uiObj.parent.dockers.last() == uiObj && uiObj.parent.dockers.first().getDockedShape()) {
  22519. this.dockerSource = uiObj.parent.dockers.first().getDockedShape()
  22520. }
  22521. } else {
  22522. // If there parent is not an Edge, undefined the Source and Target
  22523. this.dockerSource = undefined;
  22524. this.dockerTarget = undefined;
  22525. }
  22526. this.isStartDocker = this.docker.parent.dockers.first() === this.docker
  22527. this.isEndDocker = this.docker.parent.dockers.last() === this.docker
  22528. // add to canvas while dragging
  22529. this.facade.getCanvas().add(this.docker.parent);
  22530. // Hide all Labels from Docker
  22531. this.docker.parent.getLabels().each(function(label) {
  22532. label.hide();
  22533. });
  22534. // Undocked the Docker from current Shape
  22535. if ((!this.isStartDocker && !this.isEndDocker) || !this.docker.isDocked()) {
  22536. this.docker.setDockedShape(undefined)
  22537. // Set the Docker to the center of the mouse pointer
  22538. var evPos = this.facade.eventCoordinates(event);
  22539. this.docker.bounds.centerMoveTo(evPos);
  22540. //this.docker.update()
  22541. //this.facade.getCanvas().update();
  22542. this.dockerParent._update();
  22543. } else {
  22544. this.outerDockerNotMoved = true;
  22545. }
  22546. var option = {movedCallback: this.dockerMoved.bind(this), upCallback: this.dockerMovedFinished.bind(this)}
  22547. // Enable the Docker for Drag'n'Drop, give the mouseMove and mouseUp-Callback with
  22548. ORYX.Core.UIEnableDrag(event, uiObj, option);
  22549. }
  22550. },
  22551. /**
  22552. * Docker MouseMove Handler
  22553. *
  22554. */
  22555. dockerMoved: function(event) {
  22556. this.outerDockerNotMoved = false;
  22557. var snapToMagnet = undefined;
  22558. if (this.docker.parent) {
  22559. if (this.isStartDocker || this.isEndDocker) {
  22560. // Get the EventPosition and all Shapes on these point
  22561. var evPos = this.facade.eventCoordinates(event);
  22562. if(this.docker.isDocked()) {
  22563. /* Only consider start/end dockers if they are moved over a treshold */
  22564. var distanceDockerPointer =
  22565. ORYX.Core.Math.getDistancePointToPoint(evPos, this.initialDockerPosition);
  22566. if(distanceDockerPointer < this.undockTreshold) {
  22567. this.outerDockerNotMoved = true;
  22568. return;
  22569. }
  22570. /* Undock the docker */
  22571. this.docker.setDockedShape(undefined)
  22572. // Set the Docker to the center of the mouse pointer
  22573. //this.docker.bounds.centerMoveTo(evPos);
  22574. this.dockerParent._update();
  22575. }
  22576. var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos);
  22577. // Get the top level Shape on these, but not the same as Dockers parent
  22578. var uiObj = shapes.pop();
  22579. if (this.docker.parent === uiObj) {
  22580. uiObj = shapes.pop();
  22581. }
  22582. // If the top level Shape the same as the last Shape, then return
  22583. if (this.lastUIObj == uiObj) {
  22584. //return;
  22585. // If the top level uiObj instance of Shape and this isn't the parent of the docker
  22586. }
  22587. else
  22588. if (uiObj instanceof ORYX.Core.Shape) {
  22589. // Get the StencilSet of the Edge
  22590. var sset = this.docker.parent.getStencil().stencilSet();
  22591. // Ask by the StencilSet if the source, the edge and the target valid connections.
  22592. if (this.docker.parent instanceof ORYX.Core.Edge) {
  22593. var highestParent = this.getHighestParentBeforeCanvas(uiObj);
  22594. /* Ensure that the shape to dock is not a child shape
  22595. * of the same edge.
  22596. */
  22597. if(highestParent instanceof ORYX.Core.Edge
  22598. && this.docker.parent === highestParent) {
  22599. this.isValid = false;
  22600. this.dockerParent._update();
  22601. return;
  22602. }
  22603. this.isValid = false;
  22604. var curObj = uiObj, orgObj = uiObj;
  22605. while(!this.isValid && curObj && !(curObj instanceof ORYX.Core.Canvas)){
  22606. uiObj = curObj;
  22607. this.isValid = this.facade.getRules().canConnect({
  22608. sourceShape: this.dockerSource ? // Is there a docked source
  22609. this.dockerSource : // than set this
  22610. (this.isStartDocker ? // if not and if the Docker is the start docker
  22611. uiObj : // take the last uiObj
  22612. undefined), // if not set it to undefined;
  22613. edgeShape: this.docker.parent,
  22614. targetShape: this.dockerTarget ? // Is there a docked target
  22615. this.dockerTarget : // than set this
  22616. (this.isEndDocker ? // if not and if the Docker is not the start docker
  22617. uiObj : // take the last uiObj
  22618. undefined) // if not set it to undefined;
  22619. });
  22620. curObj = curObj.parent;
  22621. }
  22622. // Reset uiObj if no
  22623. // valid parent is found
  22624. if (!this.isValid){
  22625. uiObj = orgObj;
  22626. }
  22627. }
  22628. else {
  22629. this.isValid = this.facade.getRules().canConnect({
  22630. sourceShape: uiObj,
  22631. edgeShape: this.docker.parent,
  22632. targetShape: this.docker.parent
  22633. });
  22634. }
  22635. // If there is a lastUIObj, hide the magnets
  22636. if (this.lastUIObj) {
  22637. this.hideMagnets(this.lastUIObj)
  22638. }
  22639. // If there is a valid connection, show the magnets
  22640. if (this.isValid) {
  22641. this.showMagnets(uiObj)
  22642. }
  22643. // Set the Highlight Rectangle by these value
  22644. this.showHighlight(uiObj, this.isValid ? this.VALIDCOLOR : this.INVALIDCOLOR);
  22645. // Buffer the current Shape
  22646. this.lastUIObj = uiObj;
  22647. }
  22648. else {
  22649. // If there is no top level Shape, then hide the highligting of the last Shape
  22650. this.hideHighlight();
  22651. this.lastUIObj ? this.hideMagnets(this.lastUIObj) : null;
  22652. this.lastUIObj = undefined;
  22653. this.isValid = false;
  22654. }
  22655. // Snap to the nearest Magnet
  22656. if (this.lastUIObj && this.isValid && !(event.shiftKey || event.ctrlKey)) {
  22657. snapToMagnet = this.lastUIObj.magnets.find(function(magnet){
  22658. return magnet.absoluteBounds().isIncluded(evPos)
  22659. });
  22660. if (snapToMagnet) {
  22661. this.docker.bounds.centerMoveTo(snapToMagnet.absoluteCenterXY());
  22662. //this.docker.update()
  22663. }
  22664. }
  22665. }
  22666. }
  22667. // Snap to on the nearest Docker of the same parent
  22668. if(!(event.shiftKey || event.ctrlKey) && !snapToMagnet) {
  22669. var minOffset = ORYX.CONFIG.DOCKER_SNAP_OFFSET;
  22670. var nearestX = minOffset + 1
  22671. var nearestY = minOffset + 1
  22672. var dockerCenter = this.docker.bounds.center();
  22673. if (this.docker.parent) {
  22674. this.docker.parent.dockers.each((function(docker){
  22675. if (this.docker == docker) {
  22676. return
  22677. };
  22678. var center = docker.referencePoint ? docker.getAbsoluteReferencePoint() : docker.bounds.center();
  22679. nearestX = Math.abs(nearestX) > Math.abs(center.x - dockerCenter.x) ? center.x - dockerCenter.x : nearestX;
  22680. nearestY = Math.abs(nearestY) > Math.abs(center.y - dockerCenter.y) ? center.y - dockerCenter.y : nearestY;
  22681. }).bind(this));
  22682. if (Math.abs(nearestX) < minOffset || Math.abs(nearestY) < minOffset) {
  22683. nearestX = Math.abs(nearestX) < minOffset ? nearestX : 0;
  22684. nearestY = Math.abs(nearestY) < minOffset ? nearestY : 0;
  22685. this.docker.bounds.centerMoveTo(dockerCenter.x + nearestX, dockerCenter.y + nearestY);
  22686. //this.docker.update()
  22687. } else {
  22688. var previous = this.docker.parent.dockers[Math.max(this.docker.parent.dockers.indexOf(this.docker)-1, 0)]
  22689. var next = this.docker.parent.dockers[Math.min(this.docker.parent.dockers.indexOf(this.docker)+1, this.docker.parent.dockers.length-1)]
  22690. if (previous && next && previous !== this.docker && next !== this.docker){
  22691. var cp = previous.bounds.center();
  22692. var cn = next.bounds.center();
  22693. var cd = this.docker.bounds.center();
  22694. // Checks if the point is on the line between previous and next
  22695. if (ORYX.Core.Math.isPointInLine(cd.x, cd.y, cp.x, cp.y, cn.x, cn.y, 10)) {
  22696. // Get the rise
  22697. var raise = (Number(cn.y)-Number(cp.y))/(Number(cn.x)-Number(cp.x));
  22698. // Calculate the intersection point
  22699. var intersecX = ((cp.y-(cp.x*raise))-(cd.y-(cd.x*(-Math.pow(raise,-1)))))/((-Math.pow(raise,-1))-raise);
  22700. var intersecY = (cp.y-(cp.x*raise))+(raise*intersecX);
  22701. if(isNaN(intersecX) || isNaN(intersecY)) {return;}
  22702. this.docker.bounds.centerMoveTo(intersecX, intersecY);
  22703. }
  22704. }
  22705. }
  22706. }
  22707. }
  22708. //this.facade.getCanvas().update();
  22709. this.dockerParent._update();
  22710. },
  22711. /**
  22712. * Docker MouseUp Handler
  22713. *
  22714. */
  22715. dockerMovedFinished: function(event) {
  22716. /* Reset to buffered shape selection */
  22717. this.facade.setSelection(this.shapeSelection);
  22718. // Hide the border
  22719. this.hideHighlight();
  22720. // Show all Labels from Docker
  22721. this.dockerParent.getLabels().each(function(label){
  22722. label.show();
  22723. //label.update();
  22724. });
  22725. // If there is a last top level Shape
  22726. if(this.lastUIObj && (this.isStartDocker || this.isEndDocker)){
  22727. // If there is a valid connection, the set as a docked Shape to them
  22728. if(this.isValid) {
  22729. this.docker.setDockedShape(this.lastUIObj);
  22730. this.facade.raiseEvent({
  22731. type :ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED,
  22732. docker : this.docker,
  22733. parent : this.docker.parent,
  22734. target : this.lastUIObj
  22735. });
  22736. }
  22737. this.hideMagnets(this.lastUIObj)
  22738. }
  22739. // Hide the Docker
  22740. this.docker.hide();
  22741. if(this.outerDockerNotMoved) {
  22742. // Get the EventPosition and all Shapes on these point
  22743. var evPos = this.facade.eventCoordinates(event);
  22744. var shapes = this.facade.getCanvas().getAbstractShapesAtPosition(evPos);
  22745. /* Remove edges from selection */
  22746. var shapeWithoutEdges = shapes.findAll(function(node) {
  22747. return node instanceof ORYX.Core.Node;
  22748. });
  22749. shapes = shapeWithoutEdges.length ? shapeWithoutEdges : shapes;
  22750. this.facade.setSelection(shapes);
  22751. } else {
  22752. //Command-Pattern for dragging one docker
  22753. var dragDockerCommand = ORYX.Core.Command.extend({
  22754. construct: function(docker, newPos, oldPos, newDockedShape, oldDockedShape, facade){
  22755. this.docker = docker;
  22756. this.index = docker.parent.dockers.indexOf(docker);
  22757. this.newPosition = newPos;
  22758. this.newDockedShape = newDockedShape;
  22759. this.oldPosition = oldPos;
  22760. this.oldDockedShape = oldDockedShape;
  22761. this.facade = facade;
  22762. this.index = docker.parent.dockers.indexOf(docker);
  22763. this.shape = docker.parent;
  22764. },
  22765. execute: function(){
  22766. if (!this.docker.parent){
  22767. this.docker = this.shape.dockers[this.index];
  22768. }
  22769. this.dock( this.newDockedShape, this.newPosition );
  22770. this.removedDockers = this.shape.removeUnusedDockers();
  22771. this.facade.updateSelection();
  22772. },
  22773. rollback: function(){
  22774. this.dock( this.oldDockedShape, this.oldPosition );
  22775. (this.removedDockers||$H({})).each(function(d){
  22776. this.shape.add(d.value, Number(d.key));
  22777. this.shape._update(true);
  22778. }.bind(this))
  22779. this.facade.updateSelection();
  22780. },
  22781. dock:function( toDockShape, pos ){
  22782. // Set the Docker to the new Shape
  22783. this.docker.setDockedShape( undefined );
  22784. if( toDockShape ){
  22785. this.docker.setDockedShape( toDockShape );
  22786. this.docker.setReferencePoint( pos );
  22787. //this.docker.update();
  22788. //this.docker.parent._update();
  22789. } else {
  22790. this.docker.bounds.centerMoveTo( pos );
  22791. }
  22792. this.facade.getCanvas().update();
  22793. }
  22794. });
  22795. if (this.docker.parent){
  22796. // Instanziate the dockCommand
  22797. var command = new dragDockerCommand(this.docker, this.docker.getDockedShape() ? this.docker.referencePoint : this.docker.bounds.center(), this._commandArg.refPoint, this.docker.getDockedShape(), this._commandArg.dockedShape, this.facade);
  22798. this.facade.executeCommands( [command] );
  22799. }
  22800. }
  22801. // Update all Shapes
  22802. //this.facade.updateSelection();
  22803. // Undefined all variables
  22804. this.docker = undefined;
  22805. this.dockerParent = undefined;
  22806. this.dockerSource = undefined;
  22807. this.dockerTarget = undefined;
  22808. this.lastUIObj = undefined;
  22809. },
  22810. /**
  22811. * Hide the highlighting
  22812. */
  22813. hideHighlight: function() {
  22814. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'validDockedShape'});
  22815. },
  22816. /**
  22817. * Show the highlighting
  22818. *
  22819. */
  22820. showHighlight: function(uiObj, color) {
  22821. this.facade.raiseEvent({
  22822. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  22823. highlightId:'validDockedShape',
  22824. elements: [uiObj],
  22825. color: color
  22826. });
  22827. },
  22828. showMagnets: function(uiObj){
  22829. uiObj.magnets.each(function(magnet) {
  22830. magnet.show();
  22831. });
  22832. },
  22833. hideMagnets: function(uiObj){
  22834. uiObj.magnets.each(function(magnet) {
  22835. magnet.hide();
  22836. });
  22837. },
  22838. getHighestParentBeforeCanvas: function(shape) {
  22839. if(!(shape instanceof ORYX.Core.Shape)) {return undefined;}
  22840. var parent = shape.parent;
  22841. while(parent && !(parent.parent instanceof ORYX.Core.Canvas)) {
  22842. parent = parent.parent;
  22843. }
  22844. return parent;
  22845. }
  22846. });
  22847. /**
  22848. * Copyright (c) 2006
  22849. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  22850. *
  22851. * Permission is hereby granted, free of charge, to any person obtaining a
  22852. * copy of this software and associated documentation files (the "Software"),
  22853. * to deal in the Software without restriction, including without limitation
  22854. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  22855. * and/or sell copies of the Software, and to permit persons to whom the
  22856. * Software is furnished to do so, subject to the following conditions:
  22857. *
  22858. * The above copyright notice and this permission notice shall be included in
  22859. * all copies or substantial portions of the Software.
  22860. *
  22861. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22862. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22863. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  22864. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22865. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22866. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  22867. * DEALINGS IN THE SOFTWARE.
  22868. **/
  22869. if(!ORYX.Plugins)
  22870. ORYX.Plugins = new Object();
  22871. ORYX.Plugins.AddDocker = Clazz.extend({
  22872. /**
  22873. * Constructor
  22874. * @param {Object} Facade: The Facade of the Editor
  22875. */
  22876. construct: function(facade) {
  22877. this.facade = facade;
  22878. this.facade.offer({
  22879. 'name':ORYX.I18N.AddDocker.add,
  22880. 'functionality': this.enableAddDocker.bind(this),
  22881. 'group': ORYX.I18N.AddDocker.group,
  22882. 'icon': ORYX.PATH + "images/vector_add.png",
  22883. 'description': ORYX.I18N.AddDocker.addDesc,
  22884. 'index': 1,
  22885. 'toggle': true,
  22886. 'minShape': 0,
  22887. 'maxShape': 0});
  22888. this.facade.offer({
  22889. 'name':ORYX.I18N.AddDocker.del,
  22890. 'functionality': this.enableDeleteDocker.bind(this),
  22891. 'group': ORYX.I18N.AddDocker.group,
  22892. 'icon': ORYX.PATH + "images/vector_delete.png",
  22893. 'description': ORYX.I18N.AddDocker.delDesc,
  22894. 'index': 2,
  22895. 'toggle': true,
  22896. 'minShape': 0,
  22897. 'maxShape': 0});
  22898. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this));
  22899. },
  22900. enableAddDocker: function(button, pressed) {
  22901. //FIXME This should be done while construct, but this isn't possible right now!
  22902. this.addDockerButton = button;
  22903. // Unpress deleteDockerButton
  22904. if(pressed && this.deleteDockerButton)
  22905. this.deleteDockerButton.toggle(false);
  22906. },
  22907. enableDeleteDocker: function(button, pressed) {
  22908. //FIXME This should be done while construct, but this isn't possible right now!
  22909. this.deleteDockerButton = button;
  22910. // Unpress addDockerButton
  22911. if(pressed && this.addDockerButton)
  22912. this.addDockerButton.toggle(false);
  22913. },
  22914. enabledAdd: function(){
  22915. return this.addDockerButton ? this.addDockerButton.pressed : false;
  22916. },
  22917. enabledDelete: function(){
  22918. return this.deleteDockerButton ? this.deleteDockerButton.pressed : false;
  22919. },
  22920. /**
  22921. * MouseDown Handler
  22922. *
  22923. */
  22924. handleMouseDown: function(event, uiObj) {
  22925. if (this.enabledAdd() && uiObj instanceof ORYX.Core.Edge) {
  22926. this.newDockerCommand({
  22927. edge: uiObj,
  22928. position: this.facade.eventCoordinates(event)
  22929. });
  22930. } else if (this.enabledDelete() &&
  22931. uiObj instanceof ORYX.Core.Controls.Docker &&
  22932. uiObj.parent instanceof ORYX.Core.Edge) {
  22933. this.newDockerCommand({
  22934. edge: uiObj.parent,
  22935. docker: uiObj
  22936. });
  22937. } else if ( this.enabledAdd() ){
  22938. this.addDockerButton.toggle(false);
  22939. } else if ( this.enabledDelete() ) {
  22940. this.deleteDockerButton.toggle(false);
  22941. }
  22942. },
  22943. // Options: edge (required), position (required if add), docker (required if delete)
  22944. newDockerCommand: function(options){
  22945. if(!options.edge)
  22946. return;
  22947. var commandClass = ORYX.Core.Command.extend({
  22948. construct: function(addEnabled, deleteEnabled, edge, docker, pos, facade){
  22949. this.addEnabled = addEnabled;
  22950. this.deleteEnabled = deleteEnabled;
  22951. this.edge = edge;
  22952. this.docker = docker;
  22953. this.pos = pos;
  22954. this.facade = facade;
  22955. //this.index = docker.parent.dockers.indexOf(docker);
  22956. },
  22957. execute: function(){
  22958. if (this.addEnabled) {
  22959. if (!this.docker){
  22960. this.docker = this.edge.addDocker(this.pos);
  22961. this.index = this.edge.dockers.indexOf(this.docker);
  22962. } else {
  22963. this.edge.add(this.docker, this.index);
  22964. }
  22965. }
  22966. else if (this.deleteEnabled) {
  22967. this.index = this.edge.dockers.indexOf(this.docker);
  22968. this.pos = this.docker.bounds.center();
  22969. this.edge.removeDocker(this.docker);
  22970. }
  22971. this.edge.getLabels().invoke("show");
  22972. this.facade.getCanvas().update();
  22973. this.facade.updateSelection();
  22974. },
  22975. rollback: function(){
  22976. if (this.addEnabled) {
  22977. if (this.docker instanceof ORYX.Core.Controls.Docker) {
  22978. this.edge.removeDocker(this.docker);
  22979. }
  22980. }
  22981. else if (this.deleteEnabled) {
  22982. this.edge.add(this.docker, this.index);
  22983. }
  22984. this.edge.getLabels().invoke("show");
  22985. this.facade.getCanvas().update();
  22986. this.facade.updateSelection();
  22987. }
  22988. })
  22989. var command = new commandClass(this.enabledAdd(), this.enabledDelete(), options.edge, options.docker, options.position, this.facade);
  22990. this.facade.executeCommands([command]);
  22991. }
  22992. });
  22993. /**
  22994. * Copyright (c) 2006
  22995. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  22996. *
  22997. * Permission is hereby granted, free of charge, to any person obtaining a
  22998. * copy of this software and associated documentation files (the "Software"),
  22999. * to deal in the Software without restriction, including without limitation
  23000. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  23001. * and/or sell copies of the Software, and to permit persons to whom the
  23002. * Software is furnished to do so, subject to the following conditions:
  23003. *
  23004. * The above copyright notice and this permission notice shall be included in
  23005. * all copies or substantial portions of the Software.
  23006. *
  23007. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23008. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23009. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23010. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23011. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23012. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23013. * DEALINGS IN THE SOFTWARE.
  23014. **/
  23015. if(!ORYX.Plugins)
  23016. ORYX.Plugins = new Object();
  23017. ORYX.Plugins.SelectionFrame = Clazz.extend({
  23018. construct: function(facade) {
  23019. this.facade = facade;
  23020. // Register on MouseEvents
  23021. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_MOUSEDOWN, this.handleMouseDown.bind(this));
  23022. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEUP, this.handleMouseUp.bind(this), true);
  23023. // Some initiale variables
  23024. this.position = {x:0, y:0};
  23025. this.size = {width:0, height:0};
  23026. this.offsetPosition = {x: 0, y: 0}
  23027. // (Un)Register Mouse-Move Event
  23028. this.moveCallback = undefined;
  23029. this.offsetScroll = {x:0,y:0}
  23030. // HTML-Node of Selection-Frame
  23031. this.node = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", this.facade.getCanvas().getHTMLContainer(),
  23032. ['div', {'class':'Oryx_SelectionFrame'}]);
  23033. this.hide();
  23034. },
  23035. handleMouseDown: function(event, uiObj) {
  23036. // If there is the Canvas
  23037. if( uiObj instanceof ORYX.Core.Canvas ) {
  23038. // Calculate the Offset
  23039. var scrollNode = uiObj.rootNode.parentNode.parentNode;
  23040. var a = this.facade.getCanvas().node.getScreenCTM();
  23041. this.offsetPosition = {
  23042. x: a.e,
  23043. y: a.f
  23044. }
  23045. // Set the new Position
  23046. this.setPos({x: Event.pointerX(event)-this.offsetPosition.x, y:Event.pointerY(event)-this.offsetPosition.y});
  23047. // Reset the size
  23048. this.resize({width:0, height:0});
  23049. this.moveCallback = this.handleMouseMove.bind(this);
  23050. // Register Mouse-Move Event
  23051. document.documentElement.addEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false);
  23052. this.offsetScroll = {x:scrollNode.scrollLeft,y:scrollNode.scrollTop};
  23053. // Show the Frame
  23054. this.show();
  23055. }
  23056. Event.stop(event);
  23057. },
  23058. handleMouseUp: function(event) {
  23059. // If there was an MouseMoving
  23060. if(this.moveCallback) {
  23061. // Hide the Frame
  23062. this.hide();
  23063. // Unregister Mouse-Move
  23064. document.documentElement.removeEventListener(ORYX.CONFIG.EVENT_MOUSEMOVE, this.moveCallback, false);
  23065. this.moveCallback = undefined;
  23066. var corrSVG = this.facade.getCanvas().node.getScreenCTM();
  23067. // Calculate the positions of the Frame
  23068. var a = {
  23069. x: this.size.width > 0 ? this.position.x : this.position.x + this.size.width,
  23070. y: this.size.height > 0 ? this.position.y : this.position.y + this.size.height
  23071. }
  23072. var b = {
  23073. x: a.x + Math.abs(this.size.width),
  23074. y: a.y + Math.abs(this.size.height)
  23075. }
  23076. // Fit to SVG-Coordinates
  23077. a.x /= corrSVG.a; a.y /= corrSVG.d;
  23078. b.x /= corrSVG.a; b.y /= corrSVG.d;
  23079. // Calculate the elements from the childs of the canvas
  23080. var elements = this.facade.getCanvas().getChildShapes(true).findAll(function(value) {
  23081. var absBounds = value.absoluteBounds();
  23082. var bA = absBounds.upperLeft();
  23083. var bB = absBounds.lowerRight();
  23084. if(bA.x > a.x && bA.y > a.y && bB.x < b.x && bB.y < b.y)
  23085. return true;
  23086. return false
  23087. });
  23088. // Set the selection
  23089. this.facade.setSelection(elements);
  23090. }
  23091. },
  23092. handleMouseMove: function(event) {
  23093. // Calculate the size
  23094. var size = {
  23095. width : Event.pointerX(event) - this.position.x - this.offsetPosition.x,
  23096. height : Event.pointerY(event) - this.position.y - this.offsetPosition.y,
  23097. }
  23098. var scrollNode = this.facade.getCanvas().rootNode.parentNode.parentNode;
  23099. size.width -= this.offsetScroll.x - scrollNode.scrollLeft;
  23100. size.height -= this.offsetScroll.y - scrollNode.scrollTop;
  23101. // Set the size
  23102. this.resize(size);
  23103. Event.stop(event);
  23104. },
  23105. hide: function() {
  23106. this.node.style.display = "none";
  23107. },
  23108. show: function() {
  23109. this.node.style.display = "";
  23110. },
  23111. setPos: function(pos) {
  23112. // Set the Position
  23113. this.node.style.top = pos.y + "px";
  23114. this.node.style.left = pos.x + "px";
  23115. this.position = pos;
  23116. },
  23117. resize: function(size) {
  23118. // Calculate the negative offset
  23119. this.setPos(this.position);
  23120. this.size = Object.clone(size);
  23121. if(size.width < 0) {
  23122. this.node.style.left = (this.position.x + size.width) + "px";
  23123. size.width = - size.width;
  23124. }
  23125. if(size.height < 0) {
  23126. this.node.style.top = (this.position.y + size.height) + "px";
  23127. size.height = - size.height;
  23128. }
  23129. // Set the size
  23130. this.node.style.width = size.width + "px";
  23131. this.node.style.height = size.height + "px";
  23132. }
  23133. });
  23134. /**
  23135. * Copyright (c) 2006
  23136. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  23137. *
  23138. * Permission is hereby granted, free of charge, to any person obtaining a
  23139. * copy of this software and associated documentation files (the "Software"),
  23140. * to deal in the Software without restriction, including without limitation
  23141. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  23142. * and/or sell copies of the Software, and to permit persons to whom the
  23143. * Software is furnished to do so, subject to the following conditions:
  23144. *
  23145. * The above copyright notice and this permission notice shall be included in
  23146. * all copies or substantial portions of the Software.
  23147. *
  23148. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23149. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23150. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23151. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23152. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23153. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23154. * DEALINGS IN THE SOFTWARE.
  23155. **/
  23156. if(!ORYX.Plugins)
  23157. ORYX.Plugins = new Object();
  23158. ORYX.Plugins.ShapeHighlighting = Clazz.extend({
  23159. construct: function(facade) {
  23160. this.parentNode = facade.getCanvas().getSvgContainer();
  23161. // The parent Node
  23162. this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.parentNode,
  23163. ['g']);
  23164. this.highlightNodes = {};
  23165. facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW, this.setHighlight.bind(this));
  23166. facade.registerOnEvent(ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, this.hideHighlight.bind(this));
  23167. },
  23168. setHighlight: function(options) {
  23169. if(options && options.highlightId){
  23170. var node = this.highlightNodes[options.highlightId];
  23171. if(!node){
  23172. node= ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node,
  23173. ['path', {
  23174. "stroke-width": 2.0, "fill":"none"
  23175. }]);
  23176. this.highlightNodes[options.highlightId] = node;
  23177. }
  23178. if(options.elements && options.elements.length > 0) {
  23179. this.setAttributesByStyle( node, options );
  23180. this.show(node);
  23181. } else {
  23182. this.hide(node);
  23183. }
  23184. }
  23185. },
  23186. hideHighlight: function(options) {
  23187. if(options && options.highlightId && this.highlightNodes[options.highlightId]){
  23188. this.hide(this.highlightNodes[options.highlightId]);
  23189. }
  23190. },
  23191. hide: function(node) {
  23192. node.setAttributeNS(null, 'display', 'none');
  23193. },
  23194. show: function(node) {
  23195. node.setAttributeNS(null, 'display', '');
  23196. },
  23197. setAttributesByStyle: function( node, options ){
  23198. // If the style say, that it should look like a rectangle
  23199. if( options.style && options.style == ORYX.CONFIG.SELECTION_HIGHLIGHT_STYLE_RECTANGLE ){
  23200. // Set like this
  23201. var bo = options.elements[0].absoluteBounds();
  23202. var strWidth = options.strokewidth ? options.strokewidth : ORYX.CONFIG.BORDER_OFFSET
  23203. node.setAttributeNS(null, "d", this.getPathRectangle( bo.a, bo.b , strWidth ) );
  23204. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  23205. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2);
  23206. node.setAttributeNS(null, "stroke-width", strWidth);
  23207. } else if(options.elements.length == 1
  23208. && options.elements[0] instanceof ORYX.Core.Edge &&
  23209. options.highlightId != "selection") {
  23210. /* Highlight containment of edge's childs */
  23211. node.setAttributeNS(null, "d", this.getPathEdge(options.elements[0].dockers));
  23212. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  23213. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 0.2);
  23214. node.setAttributeNS(null, "stroke-width", ORYX.CONFIG.OFFSET_EDGE_BOUNDS);
  23215. }else {
  23216. // If not, set just the corners
  23217. node.setAttributeNS(null, "d", this.getPathByElements(options.elements));
  23218. node.setAttributeNS(null, "stroke", options.color ? options.color : ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR);
  23219. node.setAttributeNS(null, "stroke-opacity", options.opacity ? options.opacity : 1.0);
  23220. node.setAttributeNS(null, "stroke-width", options.strokewidth ? options.strokewidth : 2.0);
  23221. }
  23222. },
  23223. getPathByElements: function(elements){
  23224. if(!elements || elements.length <= 0) {return undefined}
  23225. // Get the padding and the size
  23226. var padding = ORYX.CONFIG.SELECTED_AREA_PADDING;
  23227. var path = ""
  23228. // Get thru all Elements
  23229. elements.each((function(element) {
  23230. if(!element) {return}
  23231. // Get the absolute Bounds and the two Points
  23232. var bounds = element.absoluteBounds();
  23233. bounds.widen(padding)
  23234. var a = bounds.upperLeft();
  23235. var b = bounds.lowerRight();
  23236. path = path + this.getPath(a ,b);
  23237. }).bind(this));
  23238. return path;
  23239. },
  23240. getPath: function(a, b){
  23241. return this.getPathCorners(a, b);
  23242. },
  23243. getPathCorners: function(a, b){
  23244. var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;
  23245. var path = ""
  23246. // Set: Upper left
  23247. path = path + "M" + a.x + " " + (a.y + size) + " l0 -" + size + " l" + size + " 0 ";
  23248. // Set: Lower left
  23249. path = path + "M" + a.x + " " + (b.y - size) + " l0 " + size + " l" + size + " 0 ";
  23250. // Set: Lower right
  23251. path = path + "M" + b.x + " " + (b.y - size) + " l0 " + size + " l-" + size + " 0 ";
  23252. // Set: Upper right
  23253. path = path + "M" + b.x + " " + (a.y + size) + " l0 -" + size + " l-" + size + " 0 ";
  23254. return path;
  23255. },
  23256. getPathRectangle: function(a, b, strokeWidth){
  23257. var size = ORYX.CONFIG.SELECTION_HIGHLIGHT_SIZE;
  23258. var path = ""
  23259. var offset = strokeWidth / 2.0;
  23260. // Set: Upper left
  23261. path = path + "M" + (a.x + offset) + " " + (a.y);
  23262. path = path + " L" + (a.x + offset) + " " + (b.y - offset);
  23263. path = path + " L" + (b.x - offset) + " " + (b.y - offset);
  23264. path = path + " L" + (b.x - offset) + " " + (a.y + offset);
  23265. path = path + " L" + (a.x + offset) + " " + (a.y + offset);
  23266. return path;
  23267. },
  23268. getPathEdge: function(edgeDockers) {
  23269. var length = edgeDockers.length;
  23270. var path = "M" + edgeDockers[0].bounds.center().x + " "
  23271. + edgeDockers[0].bounds.center().y;
  23272. for(i=1; i<length; i++) {
  23273. var dockerPoint = edgeDockers[i].bounds.center();
  23274. path = path + " L" + dockerPoint.x + " " + dockerPoint.y;
  23275. }
  23276. return path;
  23277. }
  23278. });
  23279. ORYX.Plugins.HighlightingSelectedShapes = Clazz.extend({
  23280. construct: function(facade) {
  23281. this.facade = facade;
  23282. this.opacityFull = 0.9;
  23283. this.opacityLow = 0.4;
  23284. // Register on Dragging-Events for show/hide of ShapeMenu
  23285. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_START, this.hide.bind(this));
  23286. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDROP_END, this.show.bind(this));
  23287. },
  23288. /**
  23289. * On the Selection-Changed
  23290. *
  23291. */
  23292. onSelectionChanged: function(event) {
  23293. if(event.elements && event.elements.length > 1) {
  23294. this.facade.raiseEvent({
  23295. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  23296. highlightId:'selection',
  23297. elements: event.elements.without(event.subSelection),
  23298. color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
  23299. opacity: !event.subSelection ? this.opacityFull : this.opacityLow
  23300. });
  23301. if(event.subSelection){
  23302. this.facade.raiseEvent({
  23303. type: ORYX.CONFIG.EVENT_HIGHLIGHT_SHOW,
  23304. highlightId:'subselection',
  23305. elements: [event.subSelection],
  23306. color: ORYX.CONFIG.SELECTION_HIGHLIGHT_COLOR,
  23307. opacity: this.opacityFull
  23308. });
  23309. } else {
  23310. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'});
  23311. }
  23312. } else {
  23313. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'selection'});
  23314. this.facade.raiseEvent({type:ORYX.CONFIG.EVENT_HIGHLIGHT_HIDE, highlightId:'subselection'});
  23315. }
  23316. }
  23317. });/**
  23318. * Copyright (c) 2008
  23319. * Willi Tscheschner
  23320. *
  23321. * Permission is hereby granted, free of charge, to any person obtaining a
  23322. * copy of this software and associated documentation files (the "Software"),
  23323. * to deal in the Software without restriction, including without limitation
  23324. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  23325. * and/or sell copies of the Software, and to permit persons to whom the
  23326. * Software is furnished to do so, subject to the following conditions:
  23327. *
  23328. * The above copyright notice and this permission notice shall be included in
  23329. * all copies or substantial portions of the Software.
  23330. *
  23331. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23332. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23333. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23334. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23335. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23336. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23337. * DEALINGS IN THE SOFTWARE.
  23338. *
  23339. * HOW to USE the OVERLAY PLUGIN:
  23340. * You can use it via the event mechanism from the editor
  23341. * by using facade.raiseEvent( <option> )
  23342. *
  23343. * As an example please have a look in the overlayexample.js
  23344. *
  23345. * The option object should/have to have following attributes:
  23346. *
  23347. * Key Value-Type Description
  23348. * ================================================================
  23349. *
  23350. * type ORYX.CONFIG.EVENT_OVERLAY_SHOW | ORYX.CONFIG.EVENT_OVERLAY_HIDE This is the type of the event
  23351. * id <String> You have to use an unified id for later on hiding this overlay
  23352. * shapes <ORYX.Core.Shape[]> The Shapes where the attributes should be changed
  23353. * attributes <Object> An object with svg-style attributes as key-value pair
  23354. * node <SVGElement> An SVG-Element could be specified for adding this to the Shape
  23355. * nodePosition "N"|"NE"|"E"|"SE"|"S"|"SW"|"W"|"NW"|"START"|"END" The position for the SVG-Element relative to the
  23356. * specified Shape. "START" and "END" are just using for a Edges, then
  23357. * the relation is the start or ending Docker of this edge.
  23358. *
  23359. *
  23360. **/
  23361. if (!ORYX.Plugins)
  23362. ORYX.Plugins = new Object();
  23363. ORYX.Plugins.Overlay = Clazz.extend({
  23364. facade: undefined,
  23365. styleNode: undefined,
  23366. construct: function(facade){
  23367. this.facade = facade;
  23368. this.changes = [];
  23369. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_SHOW, this.show.bind(this));
  23370. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_OVERLAY_HIDE, this.hide.bind(this));
  23371. this.styleNode = document.createElement('style')
  23372. this.styleNode.setAttributeNS(null, 'type', 'text/css')
  23373. document.getElementsByTagName('head')[0].appendChild( this.styleNode )
  23374. },
  23375. /**
  23376. * Show the overlay for specific nodes
  23377. * @param {Object} options
  23378. *
  23379. * String options.id - MUST - Define the id of the overlay (is needed for the hiding of this overlay)
  23380. * ORYX.Core.Shape[] options.shapes - MUST - Define the Shapes for the changes
  23381. * attr-name:value options.changes - Defines all the changes which should be shown
  23382. *
  23383. *
  23384. */
  23385. show: function( options ){
  23386. // Checks if all arguments are available
  23387. if( !options ||
  23388. !options.shapes || !options.shapes instanceof Array ||
  23389. !options.id || !options.id instanceof String || options.id.length == 0) {
  23390. return
  23391. }
  23392. //if( this.changes[options.id]){
  23393. // this.hide( options )
  23394. //}
  23395. // Checked if attributes are setted
  23396. if( options.attributes ){
  23397. // FOR EACH - Shape
  23398. options.shapes.each(function(el){
  23399. // Checks if the node is a Shape
  23400. if( !el instanceof ORYX.Core.Shape){ return }
  23401. this.setAttributes( el.node , options.attributes )
  23402. }.bind(this))
  23403. }
  23404. var isSVG = true
  23405. try {
  23406. isSVG = options.node && options.node instanceof SVGElement;
  23407. } catch(e){}
  23408. // Checks if node is setted and if this is an SVGElement
  23409. if ( options.node && isSVG) {
  23410. options["_temps"] = []
  23411. // FOR EACH - Node
  23412. options.shapes.each(function(el, index){
  23413. // Checks if the node is a Shape
  23414. if( !el instanceof ORYX.Core.Shape){ return }
  23415. var _temp = {}
  23416. _temp.svg = options.dontCloneNode ? options.node : options.node.cloneNode( true );
  23417. // Add the svg node to the ORYX-Shape
  23418. el.node.firstChild.appendChild( _temp.svg )
  23419. // If
  23420. if (el instanceof ORYX.Core.Edge && !options.nodePosition) {
  23421. options['nodePosition'] = "START"
  23422. }
  23423. // If the node position is setted, it has to be transformed
  23424. if( options.nodePosition ){
  23425. var b = el.bounds;
  23426. var p = options.nodePosition.toUpperCase();
  23427. // Check the values of START and END
  23428. if( el instanceof ORYX.Core.Node && p == "START"){
  23429. p = "NW";
  23430. } else if(el instanceof ORYX.Core.Node && p == "END"){
  23431. p = "SE";
  23432. } else if(el instanceof ORYX.Core.Edge && p == "START"){
  23433. b = el.getDockers().first().bounds
  23434. } else if(el instanceof ORYX.Core.Edge && p == "END"){
  23435. b = el.getDockers().last().bounds
  23436. }
  23437. // Create a callback for the changing the position
  23438. // depending on the position string
  23439. _temp.callback = function(){
  23440. var x = 0; var y = 0;
  23441. if( p == "NW" ){
  23442. // Do Nothing
  23443. } else if( p == "N" ) {
  23444. x = b.width() / 2;
  23445. } else if( p == "NE" ) {
  23446. x = b.width();
  23447. } else if( p == "E" ) {
  23448. x = b.width(); y = b.height() / 2;
  23449. } else if( p == "SE" ) {
  23450. x = b.width(); y = b.height();
  23451. } else if( p == "S" ) {
  23452. x = b.width() / 2; y = b.height();
  23453. } else if( p == "SW" ) {
  23454. y = b.height();
  23455. } else if( p == "W" ) {
  23456. y = b.height() / 2;
  23457. } else if( p == "START" || p == "END") {
  23458. x = b.width() / 2; y = b.height() / 2;
  23459. } else {
  23460. return
  23461. }
  23462. if( el instanceof ORYX.Core.Edge){
  23463. x += b.upperLeft().x ; y += b.upperLeft().y ;
  23464. }
  23465. _temp.svg.setAttributeNS(null, "transform", "translate(" + x + ", " + y + ")")
  23466. }.bind(this)
  23467. _temp.element = el;
  23468. _temp.callback();
  23469. b.registerCallback( _temp.callback );
  23470. }
  23471. options._temps.push( _temp )
  23472. }.bind(this))
  23473. }
  23474. // Store the changes
  23475. if( !this.changes[options.id] ){
  23476. this.changes[options.id] = [];
  23477. }
  23478. this.changes[options.id].push( options );
  23479. },
  23480. /**
  23481. * Hide the overlay with the spefic id
  23482. * @param {Object} options
  23483. */
  23484. hide: function( options ){
  23485. // Checks if all arguments are available
  23486. if( !options ||
  23487. !options.id || !options.id instanceof String || options.id.length == 0 ||
  23488. !this.changes[options.id]) {
  23489. return
  23490. }
  23491. // Delete all added attributes
  23492. // FOR EACH - Shape
  23493. this.changes[options.id].each(function(option){
  23494. option.shapes.each(function(el, index){
  23495. // Checks if the node is a Shape
  23496. if( !el instanceof ORYX.Core.Shape){ return }
  23497. this.deleteAttributes( el.node )
  23498. }.bind(this));
  23499. if( option._temps ){
  23500. option._temps.each(function(tmp){
  23501. // Delete the added Node, if there is one
  23502. if( tmp.svg && tmp.svg.parentNode ){
  23503. tmp.svg.parentNode.removeChild( tmp.svg )
  23504. }
  23505. // If
  23506. if( tmp.callback && tmp.element){
  23507. // It has to be unregistered from the edge
  23508. tmp.element.bounds.unregisterCallback( tmp.callback )
  23509. }
  23510. }.bind(this))
  23511. }
  23512. }.bind(this));
  23513. this.changes[options.id] = null;
  23514. },
  23515. /**
  23516. * Set the given css attributes to that node
  23517. * @param {HTMLElement} node
  23518. * @param {Object} attributes
  23519. */
  23520. setAttributes: function( node, attributes ) {
  23521. // Get all the childs from ME
  23522. var childs = this.getAllChilds( node.firstChild.firstChild )
  23523. var ids = []
  23524. // Add all Attributes which have relation to another node in this document and concate the pure id out of it
  23525. // This is for example important for the markers of a edge
  23526. childs.each(function(e){ ids.push( $A(e.attributes).findAll(function(attr){ return attr.nodeValue.startsWith('url(#')}) )})
  23527. ids = ids.flatten().compact();
  23528. ids = ids.collect(function(s){return s.nodeValue}).uniq();
  23529. ids = ids.collect(function(s){return s.slice(5, s.length-1)})
  23530. // Add the node ID to the id
  23531. ids.unshift( node.id + ' .me')
  23532. var attr = $H(attributes);
  23533. var attrValue = attr.toJSON().gsub(',', ';').gsub('"', '');
  23534. var attrMarkerValue = attributes.stroke ? attrValue.slice(0, attrValue.length-1) + "; fill:" + attributes.stroke + ";}" : attrValue;
  23535. var attrTextValue;
  23536. if( attributes.fill ){
  23537. var copyAttr = Object.clone(attributes);
  23538. copyAttr.fill = "black";
  23539. attrTextValue = $H(copyAttr).toJSON().gsub(',', ';').gsub('"', '');
  23540. }
  23541. // Create the CSS-Tags Style out of the ids and the attributes
  23542. csstags = ids.collect(function(s, i){return "#" + s + " * " + (!i? attrValue : attrMarkerValue) + "" + (attrTextValue ? " #" + s + " text * " + attrTextValue : "") })
  23543. // Join all the tags
  23544. var s = csstags.join(" ") + "\n"
  23545. // And add to the end of the style tag
  23546. this.styleNode.appendChild(document.createTextNode(s));
  23547. },
  23548. /**
  23549. * Deletes all attributes which are
  23550. * added in a special style sheet for that node
  23551. * @param {HTMLElement} node
  23552. */
  23553. deleteAttributes: function( node ) {
  23554. // Get all children which contains the node id
  23555. var delEl = $A(this.styleNode.childNodes)
  23556. .findAll(function(e){ return e.textContent.include( '#' + node.id ) });
  23557. // Remove all of them
  23558. delEl.each(function(el){
  23559. el.parentNode.removeChild(el);
  23560. });
  23561. },
  23562. getAllChilds: function( node ){
  23563. var childs = $A(node.childNodes)
  23564. $A(node.childNodes).each(function( e ){
  23565. childs.push( this.getAllChilds( e ) )
  23566. }.bind(this))
  23567. return childs.flatten();
  23568. }
  23569. });
  23570. /**
  23571. * Copyright (c) 2006
  23572. * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
  23573. *
  23574. * Permission is hereby granted, free of charge, to any person obtaining a
  23575. * copy of this software and associated documentation files (the "Software"),
  23576. * to deal in the Software without restriction, including without limitation
  23577. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  23578. * and/or sell copies of the Software, and to permit persons to whom the
  23579. * Software is furnished to do so, subject to the following conditions:
  23580. *
  23581. * The above copyright notice and this permission notice shall be included in
  23582. * all copies or substantial portions of the Software.
  23583. *
  23584. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  23585. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23586. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23587. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23588. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23589. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23590. * DEALINGS IN THE SOFTWARE.
  23591. **/
  23592. if (!ORYX.Plugins)
  23593. ORYX.Plugins = new Object();
  23594. ORYX.Plugins.Edit = Clazz.extend({
  23595. construct: function(facade){
  23596. this.facade = facade;
  23597. this.clipboard = new ORYX.Plugins.Edit.ClipBoard();
  23598. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this));
  23599. this.facade.offer({
  23600. name: ORYX.I18N.Edit.cut,
  23601. description: ORYX.I18N.Edit.cutDesc,
  23602. icon: ORYX.PATH + "images/cut.png",
  23603. keyCodes: [{
  23604. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  23605. keyCode: 88,
  23606. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  23607. }
  23608. ],
  23609. functionality: this.callEdit.bind(this, this.editCut),
  23610. group: ORYX.I18N.Edit.group,
  23611. index: 1,
  23612. minShape: 1
  23613. });
  23614. this.facade.offer({
  23615. name: ORYX.I18N.Edit.copy,
  23616. description: ORYX.I18N.Edit.copyDesc,
  23617. icon: ORYX.PATH + "images/page_copy.png",
  23618. keyCodes: [{
  23619. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  23620. keyCode: 67,
  23621. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  23622. }
  23623. ],
  23624. functionality: this.callEdit.bind(this, this.editCopy, [true, false]),
  23625. group: ORYX.I18N.Edit.group,
  23626. index: 2,
  23627. minShape: 1
  23628. });
  23629. this.facade.offer({
  23630. name: ORYX.I18N.Edit.paste,
  23631. description: ORYX.I18N.Edit.pasteDesc,
  23632. icon: ORYX.PATH + "images/page_paste.png",
  23633. keyCodes: [{
  23634. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  23635. keyCode: 86,
  23636. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  23637. }
  23638. ],
  23639. functionality: this.callEdit.bind(this, this.editPaste),
  23640. isEnabled: this.clipboard.isOccupied.bind(this.clipboard),
  23641. group: ORYX.I18N.Edit.group,
  23642. index: 3,
  23643. minShape: 0,
  23644. maxShape: 0
  23645. });
  23646. this.facade.offer({
  23647. name: ORYX.I18N.Edit.del,
  23648. description: ORYX.I18N.Edit.delDesc,
  23649. icon: ORYX.PATH + "images/cross.png",
  23650. keyCodes: [{
  23651. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  23652. keyCode: 8,
  23653. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  23654. },
  23655. {
  23656. keyCode: 46,
  23657. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  23658. }
  23659. ],
  23660. functionality: this.callEdit.bind(this, this.editDelete),
  23661. group: ORYX.I18N.Edit.group,
  23662. index: 4,
  23663. minShape: 1
  23664. });
  23665. },
  23666. callEdit: function(fn, args){
  23667. window.setTimeout(function(){
  23668. fn.apply(this, (args instanceof Array ? args : []));
  23669. }.bind(this), 1);
  23670. },
  23671. /**
  23672. * Handles the mouse down event and starts the copy-move-paste action, if
  23673. * control or meta key is pressed.
  23674. */
  23675. handleMouseDown: function(event) {
  23676. if(this._controlPressed) {
  23677. this._controlPressed = false;
  23678. this.editCopy();
  23679. // console.log("copiedEle: %0",this.clipboard.shapesAsJson)
  23680. // console.log("mousevent: %o",event)
  23681. this.editPaste();
  23682. event.forceExecution = true;
  23683. this.facade.raiseEvent(event, this.clipboard.shapesAsJson);
  23684. }
  23685. },
  23686. /**
  23687. * The key handler for this plugin. Every action from the set of cut, copy,
  23688. * paste and delete should be accessible trough simple keyboard shortcuts.
  23689. * This method checks whether any event triggers one of those actions.
  23690. *
  23691. * @param {Object} event The keyboard event that should be analysed for
  23692. * triggering of this plugin.
  23693. */
  23694. // keyHandler: function(event){
  23695. // //TODO document what event.which is.
  23696. //
  23697. // ORYX.Log.debug("edit.js handles a keyEvent.");
  23698. //
  23699. // // assure we have the current event.
  23700. // if (!event)
  23701. // event = window.event;
  23702. //
  23703. //
  23704. // // get the currently pressed key and state of control key.
  23705. // var pressedKey = event.which || event.keyCode;
  23706. // var ctrlPressed = event.ctrlKey;
  23707. //
  23708. // // if the object is to be deleted, do so, and return immediately.
  23709. // if ((pressedKey == ORYX.CONFIG.KEY_CODE_DELETE) ||
  23710. // ((pressedKey == ORYX.CONFIG.KEY_CODE_BACKSPACE) &&
  23711. // (event.metaKey || event.appleMetaKey))) {
  23712. //
  23713. // ORYX.Log.debug("edit.js deletes the shape.");
  23714. // this.editDelete();
  23715. // return;
  23716. // }
  23717. //
  23718. // // if control key is not pressed, we're not interested anymore.
  23719. // if (!ctrlPressed)
  23720. // return;
  23721. //
  23722. // // when ctrl is pressed, switch trough the possibilities.
  23723. // switch (pressedKey) {
  23724. //
  23725. // // cut.
  23726. // case ORYX.CONFIG.KEY_CODE_X:
  23727. // this.editCut();
  23728. // break;
  23729. //
  23730. // // copy.
  23731. // case ORYX.CONFIG.KEY_CODE_C:
  23732. // this.editCopy();
  23733. // break;
  23734. //
  23735. // // paste.
  23736. // case ORYX.CONFIG.KEY_CODE_V:
  23737. // this.editPaste();
  23738. // break;
  23739. // }
  23740. // },
  23741. /**
  23742. * Returns a list of shapes which should be considered while copying.
  23743. * Besides the shapes of given ones, edges and attached nodes are added to the result set.
  23744. * If one of the given shape is a child of another given shape, it is not put into the result.
  23745. */
  23746. getAllShapesToConsider: function(shapes){
  23747. var shapesToConsider = []; // only top-level shapes
  23748. var childShapesToConsider = []; // all child shapes of top-level shapes
  23749. shapes.each(function(shape){
  23750. //Throw away these shapes which have a parent in given shapes
  23751. isChildShapeOfAnother = shapes.any(function(s2){
  23752. return s2.hasChildShape(shape);
  23753. });
  23754. if(isChildShapeOfAnother) return;
  23755. // This shape should be considered
  23756. shapesToConsider.push(shape);
  23757. // Consider attached nodes (e.g. intermediate events)
  23758. if (shape instanceof ORYX.Core.Node) {
  23759. var attached = shape.getOutgoingNodes();
  23760. attached = attached.findAll(function(a){ return !shapes.include(a) });
  23761. shapesToConsider = shapesToConsider.concat(attached);
  23762. }
  23763. childShapesToConsider = childShapesToConsider.concat(shape.getChildShapes(true));
  23764. }.bind(this));
  23765. // All edges between considered child shapes should be considered
  23766. // Look for these edges having incoming and outgoing in childShapesToConsider
  23767. var edgesToConsider = this.facade.getCanvas().getChildEdges().select(function(edge){
  23768. // Ignore if already added
  23769. if(shapesToConsider.include(edge)) return false;
  23770. // Ignore if there are no docked shapes
  23771. if(edge.getAllDockedShapes().size() === 0) return false;
  23772. // True if all docked shapes are in considered child shapes
  23773. return edge.getAllDockedShapes().all(function(shape){
  23774. // Remember: Edges can have other edges on outgoing, that is why edges must not be included in childShapesToConsider
  23775. return shape instanceof ORYX.Core.Edge || childShapesToConsider.include(shape);
  23776. });
  23777. });
  23778. shapesToConsider = shapesToConsider.concat(edgesToConsider);
  23779. return shapesToConsider;
  23780. },
  23781. /**
  23782. * Performs the cut operation by first copy-ing and then deleting the
  23783. * current selection.
  23784. */
  23785. editCut: function(){
  23786. //TODO document why this returns false.
  23787. //TODO document what the magic boolean parameters are supposed to do.
  23788. this.editCopy(false, true);
  23789. this.editDelete(true);
  23790. return false;
  23791. },
  23792. /**
  23793. * Performs the copy operation.
  23794. * @param {Object} will_not_update ??
  23795. */
  23796. editCopy: function( will_update, useNoOffset ){
  23797. var selection = this.facade.getSelection();
  23798. //if the selection is empty, do not remove the previously copied elements
  23799. if(selection.length == 0) return;
  23800. this.clipboard.refresh(selection, this.getAllShapesToConsider(selection), this.facade.getCanvas().getStencil().stencilSet().namespace(), useNoOffset);
  23801. if( will_update ) this.facade.updateSelection();
  23802. },
  23803. /**
  23804. * Performs the paste operation.
  23805. */
  23806. editPaste: function(){
  23807. // Create a new canvas with childShapes
  23808. //and stencilset namespace to be JSON Import conform
  23809. var canvas = {
  23810. childShapes: this.clipboard.shapesAsJson,
  23811. stencilset:{
  23812. namespace:this.clipboard.SSnamespace
  23813. }
  23814. }
  23815. // Apply json helper to iterate over json object
  23816. Ext.apply(canvas, ORYX.Core.AbstractShape.JSONHelper);
  23817. var childShapeResourceIds = canvas.getChildShapes(true).pluck("resourceId");
  23818. var outgoings = {};
  23819. // Iterate over all shapes
  23820. canvas.eachChild(function(shape, parent){
  23821. // Throw away these references where referenced shape isn't copied
  23822. shape.outgoing = shape.outgoing.select(function(out){
  23823. return childShapeResourceIds.include(out.resourceId);
  23824. });
  23825. shape.outgoing.each(function(out){
  23826. if (!outgoings[out.resourceId]){ outgoings[out.resourceId] = [] }
  23827. outgoings[out.resourceId].push(shape)
  23828. });
  23829. return shape;
  23830. }.bind(this), true, true);
  23831. // Iterate over all shapes
  23832. canvas.eachChild(function(shape, parent){
  23833. // Check if there has a valid target
  23834. if(shape.target && !(childShapeResourceIds.include(shape.target.resourceId))){
  23835. shape.target = undefined;
  23836. shape.targetRemoved = true;
  23837. }
  23838. // Check if the first docker is removed
  23839. if( shape.dockers &&
  23840. shape.dockers.length >= 1 &&
  23841. shape.dockers[0].getDocker &&
  23842. ((shape.dockers[0].getDocker().getDockedShape() &&
  23843. !childShapeResourceIds.include(shape.dockers[0].getDocker().getDockedShape().resourceId)) ||
  23844. !shape.getShape().dockers[0].getDockedShape()&&!outgoings[shape.resourceId])) {
  23845. shape.sourceRemoved = true;
  23846. }
  23847. return shape;
  23848. }.bind(this), true, true);
  23849. // Iterate over top-level shapes
  23850. canvas.eachChild(function(shape, parent){
  23851. // All top-level shapes should get an offset in their bounds
  23852. // Move the shape occording to COPY_MOVE_OFFSET
  23853. if (this.clipboard.useOffset) {
  23854. shape.bounds = {
  23855. lowerRight: {
  23856. x: shape.bounds.lowerRight.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23857. y: shape.bounds.lowerRight.y + ORYX.CONFIG.COPY_MOVE_OFFSET
  23858. },
  23859. upperLeft: {
  23860. x: shape.bounds.upperLeft.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23861. y: shape.bounds.upperLeft.y + ORYX.CONFIG.COPY_MOVE_OFFSET
  23862. }
  23863. };
  23864. }
  23865. // Only apply offset to shapes with a target
  23866. if (shape.dockers){
  23867. shape.dockers = shape.dockers.map(function(docker, i){
  23868. // If shape had a target but the copied does not have anyone anymore,
  23869. // migrate the relative dockers to absolute ones.
  23870. if( (shape.targetRemoved === true && i == shape.dockers.length - 1&&docker.getDocker) ||
  23871. (shape.sourceRemoved === true && i == 0&&docker.getDocker)){
  23872. docker = docker.getDocker().bounds.center();
  23873. }
  23874. // If it is the first docker and it has a docked shape,
  23875. // just return the coordinates
  23876. if ((i == 0 && docker.getDocker instanceof Function &&
  23877. shape.sourceRemoved !== true && (docker.getDocker().getDockedShape() || ((outgoings[shape.resourceId]||[]).length > 0 && (!(shape.getShape() instanceof ORYX.Core.Node) || outgoings[shape.resourceId][0].getShape() instanceof ORYX.Core.Node)))) ||
  23878. (i == shape.dockers.length - 1 && docker.getDocker instanceof Function &&
  23879. shape.targetRemoved !== true && (docker.getDocker().getDockedShape() || shape.target))){
  23880. return {
  23881. x: docker.x,
  23882. y: docker.y,
  23883. getDocker: docker.getDocker
  23884. }
  23885. } else if (this.clipboard.useOffset) {
  23886. return {
  23887. x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23888. y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23889. getDocker: docker.getDocker
  23890. };
  23891. } else {
  23892. return {
  23893. x: docker.x,
  23894. y: docker.y,
  23895. getDocker: docker.getDocker
  23896. };
  23897. }
  23898. }.bind(this));
  23899. } else if (shape.getShape() instanceof ORYX.Core.Node && shape.dockers && shape.dockers.length > 0 && (!shape.dockers.first().getDocker || shape.sourceRemoved === true || !(shape.dockers.first().getDocker().getDockedShape() || outgoings[shape.resourceId]))){
  23900. shape.dockers = shape.dockers.map(function(docker, i){
  23901. if((shape.sourceRemoved === true && i == 0&&docker.getDocker)){
  23902. docker = docker.getDocker().bounds.center();
  23903. }
  23904. if (this.clipboard.useOffset) {
  23905. return {
  23906. x: docker.x + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23907. y: docker.y + ORYX.CONFIG.COPY_MOVE_OFFSET,
  23908. getDocker: docker.getDocker
  23909. };
  23910. } else {
  23911. return {
  23912. x: docker.x,
  23913. y: docker.y,
  23914. getDocker: docker.getDocker
  23915. };
  23916. }
  23917. }.bind(this));
  23918. }
  23919. return shape;
  23920. }.bind(this), false, true);
  23921. this.clipboard.useOffset = true;
  23922. this.facade.importJSON(canvas);
  23923. },
  23924. /**
  23925. * Performs the delete operation. No more asking.
  23926. */
  23927. editDelete: function(){
  23928. var selection = this.facade.getSelection();
  23929. var clipboard = new ORYX.Plugins.Edit.ClipBoard();
  23930. clipboard.refresh(selection, this.getAllShapesToConsider(selection));
  23931. var command = new ORYX.Plugins.Edit.DeleteCommand(clipboard , this.facade);
  23932. this.facade.executeCommands([command]);
  23933. }
  23934. });
  23935. ORYX.Plugins.Edit.ClipBoard = Clazz.extend({
  23936. construct: function(){
  23937. this.shapesAsJson = [];
  23938. this.selection = [];
  23939. this.SSnamespace="";
  23940. this.useOffset=true;
  23941. },
  23942. isOccupied: function(){
  23943. return this.shapesAsJson.length > 0;
  23944. },
  23945. refresh: function(selection, shapes, namespace, useNoOffset){
  23946. this.selection = selection;
  23947. this.SSnamespace=namespace;
  23948. // Store outgoings, targets and parents to restore them later on
  23949. this.outgoings = {};
  23950. this.parents = {};
  23951. this.targets = {};
  23952. this.useOffset = useNoOffset !== true;
  23953. this.shapesAsJson = shapes.map(function(shape){
  23954. var s = shape.toJSON();
  23955. s.parent = {resourceId : shape.getParentShape().resourceId};
  23956. s.parentIndex = shape.getParentShape().getChildShapes().indexOf(shape)
  23957. return s;
  23958. });
  23959. }
  23960. });
  23961. ORYX.Plugins.Edit.DeleteCommand = ORYX.Core.Command.extend({
  23962. construct: function(clipboard, facade){
  23963. this.clipboard = clipboard;
  23964. this.shapesAsJson = clipboard.shapesAsJson;
  23965. this.facade = facade;
  23966. // Store dockers of deleted shapes to restore connections
  23967. this.dockers = this.shapesAsJson.map(function(shapeAsJson){
  23968. var shape = shapeAsJson.getShape();
  23969. var incomingDockers = shape.getIncomingShapes().map(function(s){return s.getDockers().last()})
  23970. var outgoingDockers = shape.getOutgoingShapes().map(function(s){return s.getDockers().first()})
  23971. var dockers = shape.getDockers().concat(incomingDockers, outgoingDockers).compact().map(function(docker){
  23972. return {
  23973. object: docker,
  23974. referencePoint: docker.referencePoint,
  23975. dockedShape: docker.getDockedShape()
  23976. };
  23977. });
  23978. return dockers;
  23979. }).flatten();
  23980. },
  23981. execute: function(){
  23982. this.shapesAsJson.each(function(shapeAsJson){
  23983. // Delete shape
  23984. this.facade.deleteShape(shapeAsJson.getShape());
  23985. }.bind(this));
  23986. this.facade.setSelection([]);
  23987. this.facade.getCanvas().update();
  23988. this.facade.updateSelection();
  23989. },
  23990. rollback: function(){
  23991. this.shapesAsJson.each(function(shapeAsJson) {
  23992. var shape = shapeAsJson.getShape();
  23993. var parent = this.facade.getCanvas().getChildShapeByResourceId(shapeAsJson.parent.resourceId) || this.facade.getCanvas();
  23994. parent.add(shape, shape.parentIndex);
  23995. }.bind(this));
  23996. //reconnect shapes
  23997. this.dockers.each(function(d) {
  23998. d.object.setDockedShape(d.dockedShape);
  23999. d.object.setReferencePoint(d.referencePoint);
  24000. }.bind(this));
  24001. this.facade.setSelection(this.selectedShapes);
  24002. this.facade.getCanvas().update();
  24003. this.facade.updateSelection();
  24004. }
  24005. });/**
  24006. * Copyright (c) 2009
  24007. * Jan-Felix Schwarz
  24008. *
  24009. * Permission is hereby granted, free of charge, to any person obtaining a
  24010. * copy of this software and associated documentation files (the "Software"),
  24011. * to deal in the Software without restriction, including without limitation
  24012. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  24013. * and/or sell copies of the Software, and to permit persons to whom the
  24014. * Software is furnished to do so, subject to the following conditions:
  24015. *
  24016. * The above copyright notice and this permission notice shall be included in
  24017. * all copies or substantial portions of the Software.
  24018. *
  24019. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24020. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24021. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24022. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24023. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24024. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24025. * DEALINGS IN THE SOFTWARE.
  24026. **/
  24027. if (!ORYX.Plugins)
  24028. ORYX.Plugins = new Object();
  24029. ORYX.Plugins.KeysMove = ORYX.Plugins.AbstractPlugin.extend({
  24030. facade: undefined,
  24031. construct: function(facade){
  24032. this.facade = facade;
  24033. this.copyElements = [];
  24034. //this.facade.registerOnEvent(ORYX.CONFIG.EVENT_KEYDOWN, this.keyHandler.bind(this));
  24035. // SELECT ALL
  24036. this.facade.offer({
  24037. keyCodes: [{
  24038. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  24039. keyCode: 65,
  24040. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24041. }
  24042. ],
  24043. functionality: this.selectAll.bind(this)
  24044. });
  24045. // MOVE LEFT SMALL
  24046. this.facade.offer({
  24047. keyCodes: [{
  24048. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  24049. keyCode: ORYX.CONFIG.KEY_CODE_LEFT,
  24050. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24051. }
  24052. ],
  24053. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, false)
  24054. });
  24055. // MOVE LEFT
  24056. this.facade.offer({
  24057. keyCodes: [{
  24058. keyCode: ORYX.CONFIG.KEY_CODE_LEFT,
  24059. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24060. }
  24061. ],
  24062. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_LEFT, true)
  24063. });
  24064. // MOVE RIGHT SMALL
  24065. this.facade.offer({
  24066. keyCodes: [{
  24067. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  24068. keyCode: ORYX.CONFIG.KEY_CODE_RIGHT,
  24069. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24070. }
  24071. ],
  24072. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, false)
  24073. });
  24074. // MOVE RIGHT
  24075. this.facade.offer({
  24076. keyCodes: [{
  24077. keyCode: ORYX.CONFIG.KEY_CODE_RIGHT,
  24078. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24079. }
  24080. ],
  24081. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_RIGHT, true)
  24082. });
  24083. // MOVE UP SMALL
  24084. this.facade.offer({
  24085. keyCodes: [{
  24086. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  24087. keyCode: ORYX.CONFIG.KEY_CODE_UP,
  24088. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24089. }
  24090. ],
  24091. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, false)
  24092. });
  24093. // MOVE UP
  24094. this.facade.offer({
  24095. keyCodes: [{
  24096. keyCode: ORYX.CONFIG.KEY_CODE_UP,
  24097. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24098. }
  24099. ],
  24100. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_UP, true)
  24101. });
  24102. // MOVE DOWN SMALL
  24103. this.facade.offer({
  24104. keyCodes: [{
  24105. metaKeys: [ORYX.CONFIG.META_KEY_META_CTRL],
  24106. keyCode: ORYX.CONFIG.KEY_CODE_DOWN,
  24107. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24108. }
  24109. ],
  24110. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, false)
  24111. });
  24112. // MOVE DOWN
  24113. this.facade.offer({
  24114. keyCodes: [{
  24115. keyCode: ORYX.CONFIG.KEY_CODE_DOWN,
  24116. keyAction: ORYX.CONFIG.KEY_ACTION_DOWN
  24117. }
  24118. ],
  24119. functionality: this.move.bind(this, ORYX.CONFIG.KEY_CODE_DOWN, true)
  24120. });
  24121. },
  24122. /**
  24123. * Select all shapes in the editor
  24124. *
  24125. */
  24126. selectAll: function(e){
  24127. Event.stop(e.event);
  24128. this.facade.setSelection(this.facade.getCanvas().getChildShapes(true))
  24129. },
  24130. move: function(key, far, e) {
  24131. Event.stop(e.event);
  24132. // calculate the distance to move the objects and get the selection.
  24133. var distance = far? 20 : 5;
  24134. var selection = this.facade.getSelection();
  24135. var currentSelection = this.facade.getSelection();
  24136. var p = {x: 0, y: 0};
  24137. // switch on the key pressed and populate the point to move by.
  24138. switch(key) {
  24139. case ORYX.CONFIG.KEY_CODE_LEFT:
  24140. p.x = -1*distance;
  24141. break;
  24142. case ORYX.CONFIG.KEY_CODE_RIGHT:
  24143. p.x = distance;
  24144. break;
  24145. case ORYX.CONFIG.KEY_CODE_UP:
  24146. p.y = -1*distance;
  24147. break;
  24148. case ORYX.CONFIG.KEY_CODE_DOWN:
  24149. p.y = distance;
  24150. break;
  24151. }
  24152. // move each shape in the selection by the point calculated and update it.
  24153. selection = selection.findAll(function(shape){
  24154. // Check if this shape is docked to an shape in the selection
  24155. if(shape instanceof ORYX.Core.Node && shape.dockers.length == 1 && selection.include( shape.dockers.first().getDockedShape() )){
  24156. return false
  24157. }
  24158. // Check if any of the parent shape is included in the selection
  24159. var s = shape.parent;
  24160. do{
  24161. if(selection.include(s)){
  24162. return false
  24163. }
  24164. }while(s = s.parent);
  24165. // Otherwise, return true
  24166. return true;
  24167. });
  24168. /* Edges must not be movable, if only edges are selected and at least
  24169. * one of them is docked.
  24170. */
  24171. var edgesMovable = true;
  24172. var onlyEdgesSelected = selection.all(function(shape) {
  24173. if(shape instanceof ORYX.Core.Edge) {
  24174. if(shape.isDocked()) {
  24175. edgesMovable = false;
  24176. }
  24177. return true;
  24178. }
  24179. return false;
  24180. });
  24181. if(onlyEdgesSelected && !edgesMovable) {
  24182. /* Abort moving shapes */
  24183. return;
  24184. }
  24185. selection = selection.map(function(shape){
  24186. if( shape instanceof ORYX.Core.Node ){
  24187. /*if( shape.dockers.length == 1 ){
  24188. return shape.dockers.first()
  24189. } else {*/
  24190. return shape
  24191. //}
  24192. } else if( shape instanceof ORYX.Core.Edge ) {
  24193. var dockers = shape.dockers;
  24194. if( selection.include( shape.dockers.first().getDockedShape() ) ){
  24195. dockers = dockers.without( shape.dockers.first() )
  24196. }
  24197. if( selection.include( shape.dockers.last().getDockedShape() ) ){
  24198. dockers = dockers.without( shape.dockers.last() )
  24199. }
  24200. return dockers
  24201. } else {
  24202. return null
  24203. }
  24204. }).flatten().compact();
  24205. if (selection.size() > 0) {
  24206. //Stop moving at canvas borders
  24207. var selectionBounds = [ this.facade.getCanvas().bounds.lowerRight().x,
  24208. this.facade.getCanvas().bounds.lowerRight().y,
  24209. 0,
  24210. 0 ];
  24211. selection.each(function(s) {
  24212. selectionBounds[0] = Math.min(selectionBounds[0], s.bounds.upperLeft().x);
  24213. selectionBounds[1] = Math.min(selectionBounds[1], s.bounds.upperLeft().y);
  24214. selectionBounds[2] = Math.max(selectionBounds[2], s.bounds.lowerRight().x);
  24215. selectionBounds[3] = Math.max(selectionBounds[3], s.bounds.lowerRight().y);
  24216. });
  24217. if(selectionBounds[0]+p.x < 0)
  24218. p.x = -selectionBounds[0];
  24219. if(selectionBounds[1]+p.y < 0)
  24220. p.y = -selectionBounds[1];
  24221. if(selectionBounds[2]+p.x > this.facade.getCanvas().bounds.lowerRight().x)
  24222. p.x = this.facade.getCanvas().bounds.lowerRight().x - selectionBounds[2];
  24223. if(selectionBounds[3]+p.y > this.facade.getCanvas().bounds.lowerRight().y)
  24224. p.y = this.facade.getCanvas().bounds.lowerRight().y - selectionBounds[3];
  24225. if(p.x!=0 || p.y!=0) {
  24226. // Instantiate the moveCommand
  24227. var commands = [new ORYX.Core.Command.Move(selection, p, null, currentSelection, this)];
  24228. // Execute the commands
  24229. this.facade.executeCommands(commands);
  24230. }
  24231. }
  24232. },
  24233. getUndockedCommant: function(shapes){
  24234. var undockEdgeCommand = ORYX.Core.Command.extend({
  24235. construct: function(moveShapes){
  24236. this.dockers = moveShapes.collect(function(shape){ return shape instanceof ORYX.Core.Controls.Docker ? {docker:shape, dockedShape:shape.getDockedShape(), refPoint:shape.referencePoint} : undefined }).compact();
  24237. },
  24238. execute: function(){
  24239. this.dockers.each(function(el){
  24240. el.docker.setDockedShape(undefined);
  24241. })
  24242. },
  24243. rollback: function(){
  24244. this.dockers.each(function(el){
  24245. el.docker.setDockedShape(el.dockedShape);
  24246. el.docker.setReferencePoint(el.refPoint);
  24247. //el.docker.update();
  24248. })
  24249. }
  24250. });
  24251. command = new undockEdgeCommand( shapes );
  24252. command.execute();
  24253. return command;
  24254. },
  24255. // /**
  24256. // * The key handler for this plugin. Every action from the set of cut, copy,
  24257. // * paste and delete should be accessible trough simple keyboard shortcuts.
  24258. // * This method checks whether any event triggers one of those actions.
  24259. // *
  24260. // * @param {Object} event The keyboard event that should be analysed for
  24261. // * triggering of this plugin.
  24262. // */
  24263. // keyHandler: function(event){
  24264. // //TODO document what event.which is.
  24265. //
  24266. // ORYX.Log.debug("keysMove.js handles a keyEvent.");
  24267. //
  24268. // // assure we have the current event.
  24269. // if (!event)
  24270. // event = window.event;
  24271. //
  24272. // // get the currently pressed key and state of control key.
  24273. // var pressedKey = event.which || event.keyCode;
  24274. // var ctrlPressed = event.ctrlKey;
  24275. //
  24276. // // if the key is one of the arrow keys, forward to move and return.
  24277. // if ([ORYX.CONFIG.KEY_CODE_LEFT, ORYX.CONFIG.KEY_CODE_RIGHT,
  24278. // ORYX.CONFIG.KEY_CODE_UP, ORYX.CONFIG.KEY_CODE_DOWN].include(pressedKey)) {
  24279. //
  24280. // this.move(pressedKey, !ctrlPressed);
  24281. // return;
  24282. // }
  24283. //
  24284. // }
  24285. });
  24286. /**
  24287. * Copyright (c) 2009
  24288. * Willi Tscheschner
  24289. *
  24290. * Permission is hereby granted, free of charge, to any person obtaining a
  24291. * copy of this software and associated documentation files (the "Software"),
  24292. * to deal in the Software without restriction, including without limitation
  24293. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  24294. * and/or sell copies of the Software, and to permit persons to whom the
  24295. * Software is furnished to do so, subject to the following conditions:
  24296. *
  24297. * The above copyright notice and this permission notice shall be included in
  24298. * all copies or substantial portions of the Software.
  24299. *
  24300. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24301. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24302. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24303. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24304. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24305. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24306. * DEALINGS IN THE SOFTWARE.
  24307. **/
  24308. if(!ORYX.Plugins) { ORYX.Plugins = {} }
  24309. if(!ORYX.Plugins.Layouter) { ORYX.Plugins.Layouter = {} }
  24310. new function(){
  24311. /**
  24312. * Edge layouter is an implementation to layout an edge
  24313. * @class ORYX.Plugins.Layouter.EdgeLayouter
  24314. * @author Willi Tscheschner
  24315. */
  24316. ORYX.Plugins.Layouter.EdgeLayouter = ORYX.Plugins.AbstractLayouter.extend({
  24317. /**
  24318. * Layout only Edges
  24319. */
  24320. layouted : [ "http://b3mn.org/stencilset/bpmn1.1#SequenceFlow",
  24321. "http://b3mn.org/stencilset/bpmn1.1#MessageFlow",
  24322. "http://b3mn.org/stencilset/timjpdl3#SequenceFlow",
  24323. "http://b3mn.org/stencilset/jbpm4#SequenceFlow",
  24324. "http://b3mn.org/stencilset/bpmn2.0#MessageFlow",
  24325. "http://b3mn.org/stencilset/bpmn2.0#SequenceFlow",
  24326. "http://b3mn.org/stencilset/bpmn2.0choreography#MessageFlow",
  24327. "http://b3mn.org/stencilset/bpmn2.0choreography#SequenceFlow",
  24328. "http://b3mn.org/stencilset/bpmn2.0conversation#ConversationLink",
  24329. "http://b3mn.org/stencilset/epc#ControlFlow",
  24330. "http://www.signavio.com/stencilsets/processmap#ProcessLink",
  24331. "http://www.signavio.com/stencilsets/organigram#connection"],
  24332. /**
  24333. * Layout a set on edges
  24334. * @param {Object} edges
  24335. */
  24336. layout: function(edges){
  24337. edges.each(function(edge){
  24338. this.doLayout(edge)
  24339. }.bind(this))
  24340. },
  24341. /**
  24342. * Layout one edge
  24343. * @param {Object} edge
  24344. */
  24345. doLayout: function(edge){
  24346. // Get from and to node
  24347. var from = edge.getIncomingNodes()[0];
  24348. var to = edge.getOutgoingNodes()[0];
  24349. // Return if one is null
  24350. if (!from || !to) { return }
  24351. var positions = this.getPositions(from, to, edge);
  24352. if (positions.length > 0){
  24353. this.setDockers(edge, positions[0].a, positions[0].b);
  24354. }
  24355. },
  24356. /**
  24357. * Returns a set on positions which are not containt either
  24358. * in the bounds in from or to.
  24359. * @param {Object} from Shape where the edge is come from
  24360. * @param {Object} to Shape where the edge is leading to
  24361. * @param {Object} edge Edge between from and to
  24362. */
  24363. getPositions : function(from, to, edge){
  24364. // Get absolute bounds
  24365. var ab = from.absoluteBounds();
  24366. var bb = to.absoluteBounds();
  24367. // Get center from and to
  24368. var a = ab.center();
  24369. var b = bb.center();
  24370. var am = ab.midPoint();
  24371. var bm = bb.midPoint();
  24372. // Get first and last reference point
  24373. var first = Object.clone(edge.dockers.first().referencePoint);
  24374. var last = Object.clone(edge.dockers.last().referencePoint);
  24375. // Get the absolute one
  24376. var aFirst = edge.dockers.first().getAbsoluteReferencePoint();
  24377. var aLast = edge.dockers.last().getAbsoluteReferencePoint();
  24378. // IF ------>
  24379. // or |
  24380. // V
  24381. // Do nothing
  24382. if (Math.abs(aFirst.x-aLast.x) < 1 || Math.abs(aFirst.y-aLast.y) < 1) {
  24383. return []
  24384. }
  24385. // Calc center position, between a and b
  24386. // depending on there weight
  24387. var m = {}
  24388. m.x = a.x < b.x ?
  24389. (((b.x - bb.width()/2) - (a.x + ab.width()/2))/2) + (a.x + ab.width()/2):
  24390. (((a.x - ab.width()/2) - (b.x + bb.width()/2))/2) + (b.x + bb.width()/2);
  24391. m.y = a.y < b.y ?
  24392. (((b.y - bb.height()/2) - (a.y + ab.height()/2))/2) + (a.y + ab.height()/2):
  24393. (((a.y - ab.height()/2) - (b.y + bb.height()/2))/2) + (b.y + bb.height()/2);
  24394. // Enlarge both bounds with 10
  24395. ab.widen(5); // Wide the from less than
  24396. bb.widen(20);// the to because of the arrow from the edge
  24397. var positions = [];
  24398. var off = this.getOffset.bind(this);
  24399. // Checks ----+
  24400. // |
  24401. // V
  24402. if (!ab.isIncluded(b.x, a.y)&&!bb.isIncluded(b.x, a.y)) {
  24403. positions.push({
  24404. a : {x:b.x+off(last,bm,"x"),y:a.y+off(first,am,"y")},
  24405. z : this.getWeight(from, a.x < b.x ? "r" : "l", to, a.y < b.y ? "t" : "b", edge)
  24406. });
  24407. }
  24408. // Checks |
  24409. // +--->
  24410. if (!ab.isIncluded(a.x, b.y)&&!bb.isIncluded(a.x, b.y)) {
  24411. positions.push({
  24412. a : {x:a.x+off(first,am,"x"),y:b.y+off(last,bm,"y")},
  24413. z : this.getWeight(from, a.y < b.y ? "b" : "t", to, a.x < b.x ? "l" : "r", edge)
  24414. });
  24415. }
  24416. // Checks --+
  24417. // |
  24418. // +--->
  24419. if (!ab.isIncluded(m.x, a.y)&&!bb.isIncluded(m.x, b.y)) {
  24420. positions.push({
  24421. a : {x:m.x,y:a.y+off(first,am,"y")},
  24422. b : {x:m.x,y:b.y+off(last,bm,"y")},
  24423. z : this.getWeight(from, "r", to, "l", edge, a.x > b.x)
  24424. });
  24425. }
  24426. // Checks |
  24427. // +---+
  24428. // |
  24429. // V
  24430. if (!ab.isIncluded(a.x, m.y)&&!bb.isIncluded(b.x, m.y)) {
  24431. positions.push({
  24432. a : {x:a.x+off(first,am,"x"),y:m.y},
  24433. b : {x:b.x+off(last,bm,"x"),y:m.y},
  24434. z : this.getWeight(from, "b", to, "t", edge, a.y > b.y)
  24435. });
  24436. }
  24437. // Sort DESC of weights
  24438. return positions.sort(function(a,b){ return a.z < b.z ? 1 : (a.z == b.z ? -1 : -1)});
  24439. },
  24440. /**
  24441. * Returns a offset for the pos to the center of the bounds
  24442. *
  24443. * @param {Object} val
  24444. * @param {Object} pos2
  24445. * @param {String} dir Direction x|y
  24446. */
  24447. getOffset: function(pos, pos2, dir){
  24448. return pos[dir] - pos2[dir];
  24449. },
  24450. /**
  24451. * Returns a value which shows the weight for this configuration
  24452. *
  24453. * @param {Object} from Shape which is coming from
  24454. * @param {String} d1 Direction where is goes
  24455. * @param {Object} to Shape which goes to
  24456. * @param {String} d2 Direction where it comes to
  24457. * @param {Object} edge Edge between from and to
  24458. * @param {Boolean} reverse Reverse the direction (e.g. "r" -> "l")
  24459. */
  24460. getWeight: function(from, d1, to, d2, edge, reverse){
  24461. d1 = (d1||"").toLowerCase();
  24462. d2 = (d2||"").toLowerCase();
  24463. if (!["t","r","b","l"].include(d1)){ d1 = "r"}
  24464. if (!["t","r","b","l"].include(d2)){ d1 = "l"}
  24465. // If reverse is set
  24466. if (reverse) {
  24467. // Reverse d1 and d2
  24468. d1 = d1=="t"?"b":(d1=="r"?"l":(d1=="b"?"t":(d1=="l"?"r":"r")))
  24469. d2 = d2=="t"?"b":(d2=="r"?"l":(d2=="b"?"t":(d2=="l"?"r":"r")))
  24470. }
  24471. var weight = 0;
  24472. // Get rules for from "out" and to "in"
  24473. var dr1 = this.facade.getRules().getLayoutingRules(from, edge)["out"];
  24474. var dr2 = this.facade.getRules().getLayoutingRules(to, edge)["in"];
  24475. var fromWeight = dr1[d1];
  24476. var toWeight = dr2[d2];
  24477. /**
  24478. * Return a true if the center 1 is in the same direction than center 2
  24479. * @param {Object} direction
  24480. * @param {Object} center1
  24481. * @param {Object} center2
  24482. */
  24483. var sameDirection = function(direction, center1, center2){
  24484. switch(direction){
  24485. case "t": return Math.abs(center1.x - center2.x) < 2 && center1.y < center2.y
  24486. case "r": return center1.x > center2.x && Math.abs(center1.y - center2.y) < 2
  24487. case "b": return Math.abs(center1.x - center2.x) < 2 && center1.y > center2.y
  24488. case "l": return center1.x < center2.x && Math.abs(center1.y - center2.y) < 2
  24489. default: return false;
  24490. }
  24491. }
  24492. // Check if there are same incoming edges from 'from'
  24493. var sameIncomingFrom = from
  24494. .getIncomingShapes()
  24495. .findAll(function(a){ return a instanceof ORYX.Core.Edge})
  24496. .any(function(e){
  24497. return sameDirection(d1, e.dockers[e.dockers.length-2].bounds.center(), e.dockers.last().bounds.center());
  24498. });
  24499. // Check if there are same outgoing edges from 'to'
  24500. var sameOutgoingTo = to
  24501. .getOutgoingShapes()
  24502. .findAll(function(a){ return a instanceof ORYX.Core.Edge})
  24503. .any(function(e){
  24504. return sameDirection(d2, e.dockers[1].bounds.center(), e.dockers.first().bounds.center());
  24505. });
  24506. // If there are equivalent edges, set 0
  24507. //fromWeight = sameIncomingFrom ? 0 : fromWeight;
  24508. //toWeight = sameOutgoingTo ? 0 : toWeight;
  24509. // Get the sum of "out" and the direction plus "in" and the direction
  24510. return (sameIncomingFrom||sameOutgoingTo?0:fromWeight+toWeight);
  24511. },
  24512. /**
  24513. * Removes all current dockers from the node
  24514. * (except the start and end) and adds two new
  24515. * dockers, on the position a and b.
  24516. * @param {Object} edge
  24517. * @param {Object} a
  24518. * @param {Object} b
  24519. */
  24520. setDockers: function(edge, a, b){
  24521. if (!edge){ return }
  24522. // Remove all dockers (implicit,
  24523. // start and end dockers will not removed)
  24524. edge.dockers.each(function(r){
  24525. edge.removeDocker(r);
  24526. });
  24527. // For a and b (if exists), create
  24528. // a new docker and set position
  24529. [a, b].compact().each(function(pos){
  24530. var docker = edge.createDocker(undefined, pos);
  24531. docker.bounds.centerMoveTo(pos);
  24532. });
  24533. // Update all dockers from the edge
  24534. edge.dockers.each(function(docker){
  24535. docker.update()
  24536. })
  24537. // Update edge
  24538. //edge.refresh();
  24539. edge._update(true);
  24540. }
  24541. });
  24542. }()
  24543. /**
  24544. * Copyright (c) 2009
  24545. * Sven Wagner-Boysen, Willi Tscheschner
  24546. *
  24547. * Permission is hereby granted, free of charge, to any person obtaining a
  24548. * copy of this software and associated documentation files (the "Software"),
  24549. * to deal in the Software without restriction, including without limitation
  24550. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  24551. * and/or sell copies of the Software, and to permit persons to whom the
  24552. * Software is furnished to do so, subject to the following conditions:
  24553. *
  24554. * The above copyright notice and this permission notice shall be included in
  24555. * all copies or substantial portions of the Software.
  24556. *
  24557. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  24558. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  24559. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24560. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24561. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24562. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24563. * DEALINGS IN THE SOFTWARE.
  24564. **/
  24565. if(!ORYX.Plugins)
  24566. ORYX.Plugins = new Object();
  24567. new function(){
  24568. ORYX.Plugins.BPMN2_0 = {
  24569. /**
  24570. * Constructor
  24571. * @param {Object} Facade: The Facade of the Editor
  24572. */
  24573. construct: function(facade){
  24574. this.facade = facade;
  24575. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_DRAGDOCKER_DOCKED, this.handleDockerDocked.bind(this));
  24576. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PROPWINDOW_PROP_CHANGED, this.handlePropertyChanged.bind(this));
  24577. this.facade.registerOnEvent('layout.bpmn2_0.subprocess', this.handleSubProcess.bind(this));
  24578. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_SHAPEREMOVED, this.handleShapeRemove.bind(this));
  24579. this.facade.registerOnEvent(ORYX.CONFIG.EVENT_LOADED, this.afterLoad.bind(this));
  24580. this.namespace = undefined;
  24581. },
  24582. hashedSubProcesses: {},
  24583. hashChildShapes: function(shape){
  24584. var children = shape.getChildNodes();
  24585. children.each(function(child){
  24586. if (this.hashedSubProcesses[child.id]){
  24587. this.hashedSubProcesses[child.id] = child.absoluteXY();
  24588. this.hashedSubProcesses[child.id].width = child.bounds.width();
  24589. this.hashedSubProcesses[child.id].height = child.bounds.height();
  24590. this.hashChildShapes(child);
  24591. }
  24592. }.bind(this));
  24593. },
  24594. /**
  24595. * Handle the layouting of a sub process.
  24596. * Mainly to adjust the child dockers of a sub process.
  24597. *
  24598. */
  24599. handleSubProcess : function(option) {
  24600. var sh = option.shape;
  24601. if (!this.hashedSubProcesses[sh.id]) {
  24602. this.hashedSubProcesses[sh.id] = sh.absoluteXY();
  24603. this.hashedSubProcesses[sh.id].width = sh.bounds.width();
  24604. this.hashedSubProcesses[sh.id].height = sh.bounds.height();
  24605. return;
  24606. }
  24607. var offset = sh.absoluteXY();
  24608. offset.x -= this.hashedSubProcesses[sh.id].x;
  24609. offset.y -= this.hashedSubProcesses[sh.id].y;
  24610. var resized = this.hashedSubProcesses[sh.id].width !== sh.bounds.width() || this.hashedSubProcesses[sh.id].height !== sh.bounds.height();
  24611. this.hashedSubProcesses[sh.id] = sh.absoluteXY();
  24612. this.hashedSubProcesses[sh.id].width = sh.bounds.width();
  24613. this.hashedSubProcesses[sh.id].height = sh.bounds.height();
  24614. this.hashChildShapes(sh);
  24615. // Move dockers only if currently is not resizing
  24616. if (this.facade.isExecutingCommands()&&!resized) {
  24617. this.moveChildDockers(sh, offset);
  24618. }
  24619. },
  24620. moveChildDockers: function(shape, offset){
  24621. if (!offset.x && !offset.y) {
  24622. return;
  24623. }
  24624. var children = shape.getChildNodes(true);
  24625. // Get all nodes
  24626. var dockers = children
  24627. // Get all incoming and outgoing edges
  24628. .map(function(node){
  24629. return [].concat(node.getIncomingShapes())
  24630. .concat(node.getOutgoingShapes())
  24631. })
  24632. // Flatten all including arrays into one
  24633. .flatten()
  24634. // Get every edge only once
  24635. .uniq()
  24636. // Get all dockers
  24637. .map(function(edge){
  24638. return edge.dockers.length > 2 ?
  24639. edge.dockers.slice(1, edge.dockers.length-1) :
  24640. [];
  24641. })
  24642. // Flatten the dockers lists
  24643. .flatten();
  24644. var abs = shape.absoluteBounds();
  24645. abs.moveBy(-offset.x, -offset.y)
  24646. var obj = {};
  24647. dockers.each(function(docker){
  24648. if (docker.isChanged){
  24649. return;
  24650. }
  24651. var off = Object.clone(offset);
  24652. if (!abs.isIncluded(docker.bounds.center())){
  24653. var index = docker.parent.dockers.indexOf(docker);
  24654. var size = docker.parent.dockers.length;
  24655. var from = docker.parent.getSource();
  24656. var to = docker.parent.getTarget();
  24657. var bothAreIncluded = children.include(from) && children.include(to);
  24658. if (!bothAreIncluded){
  24659. var previousIsOver = index !== 0 ? abs.isIncluded(docker.parent.dockers[index-1].bounds.center()) : false;
  24660. var nextIsOver = index !== size-1 ? abs.isIncluded(docker.parent.dockers[index+1].bounds.center()) : false;
  24661. if (!previousIsOver && !nextIsOver){ return; }
  24662. var ref = docker.parent.dockers[previousIsOver ? index-1 : index+1];
  24663. if (Math.abs(-Math.abs(ref.bounds.center().x-docker.bounds.center().x)) < 2){
  24664. off.y = 0;
  24665. } else if(Math.abs(-Math.abs(ref.bounds.center().y-docker.bounds.center().y)) < 2){
  24666. off.x = 0;
  24667. } else {
  24668. return;
  24669. }
  24670. }
  24671. }
  24672. obj[docker.getId()] = {
  24673. docker:docker,
  24674. offset:off
  24675. }
  24676. })
  24677. // Set dockers
  24678. this.facade.executeCommands([new ORYX.Core.MoveDockersCommand(obj)]);
  24679. },
  24680. /**
  24681. * DragDocker.Docked Handler
  24682. *
  24683. */
  24684. handleDockerDocked: function(options) {
  24685. var namespace = this.getNamespace();
  24686. var edge = options.parent;
  24687. var edgeSource = options.target;
  24688. if(edge.getStencil().id() === namespace + "SequenceFlow") {
  24689. var isGateway = edgeSource.getStencil().groups().find(function(group) {
  24690. if(group == "Gateways")
  24691. return group;
  24692. });
  24693. if(!isGateway && (edge.properties["oryx-conditiontype"] == "Expression"))
  24694. // show diamond on edge source
  24695. edge.setProperty("oryx-showdiamondmarker", true);
  24696. else
  24697. // do not show diamond on edge source
  24698. edge.setProperty("oryx-showdiamondmarker", false);
  24699. // update edge rendering
  24700. //edge.update();
  24701. this.facade.getCanvas().update();
  24702. }
  24703. },
  24704. /**
  24705. * PropertyWindow.PropertyChanged Handler
  24706. */
  24707. handlePropertyChanged: function(option) {
  24708. var namespace = this.getNamespace();
  24709. var shapes = option.elements;
  24710. var propertyKey = option.key;
  24711. var propertyValue = option.value;
  24712. var changed = false;
  24713. shapes.each(function(shape){
  24714. if((shape.getStencil().id() === namespace + "SequenceFlow") &&
  24715. (propertyKey === "oryx-conditiontype")) {
  24716. if(propertyValue != "Expression")
  24717. // Do not show the Diamond
  24718. shape.setProperty("oryx-showdiamondmarker", false);
  24719. else {
  24720. var incomingShapes = shape.getIncomingShapes();
  24721. if(!incomingShapes) {
  24722. shape.setProperty("oryx-showdiamondmarker", true);
  24723. }
  24724. var incomingGateway = incomingShapes.find(function(aShape) {
  24725. var foundGateway = aShape.getStencil().groups().find(function(group) {
  24726. if(group == "Gateways")
  24727. return group;
  24728. });
  24729. if(foundGateway)
  24730. return foundGateway;
  24731. });
  24732. if(!incomingGateway)
  24733. // show diamond on edge source
  24734. shape.setProperty("oryx-showdiamondmarker", true);
  24735. else
  24736. // do not show diamond
  24737. shape.setProperty("oryx-showdiamondmarker", false);
  24738. }
  24739. changed = true;
  24740. }
  24741. }.bind(this));
  24742. if(changed) {this.facade.getCanvas().update();}
  24743. },
  24744. hashedPoolPositions : {},
  24745. hashedLaneDepth : {},
  24746. hashedBounds : {},
  24747. hashedPositions: {},
  24748. isResized: function(shape, bounds){
  24749. if (!bounds||!shape){
  24750. return false;
  24751. }
  24752. var oldB = bounds;
  24753. //var oldXY = oldB.upperLeft();
  24754. //var xy = shape.absoluteXY();
  24755. return Math.round(oldB.width() - shape.bounds.width()) !== 0 || Math.round(oldB.height() - shape.bounds.height()) !== 0
  24756. },
  24757. getDepth: function(child, parent){
  24758. var i=0;
  24759. while(child && child.parent && child !== parent){
  24760. child = child.parent;
  24761. ++i
  24762. }
  24763. return i;
  24764. },
  24765. updateDepth: function(lane, fromDepth, toDepth){
  24766. var xOffset = (fromDepth - toDepth) * 30;
  24767. lane.getChildNodes().each(function(shape){
  24768. shape.bounds.moveBy(xOffset, 0);
  24769. [].concat(children[j].getIncomingShapes())
  24770. .concat(children[j].getOutgoingShapes())
  24771. })
  24772. },
  24773. moveBy: function(pos, offset){
  24774. pos.x += offset.x;
  24775. pos.y += offset.y;
  24776. return pos;
  24777. },
  24778. getHashedBounds: function(shape){
  24779. return this.currentPool && this.hashedBounds[this.currentPool.id][shape.id] ? this.hashedBounds[this.currentPool.id][shape.id] : shape.absoluteBounds();
  24780. },
  24781. getNamespace: function() {
  24782. if(!this.namespace) {
  24783. var stencilsets = this.facade.getStencilSets();
  24784. if(stencilsets.keys()) {
  24785. this.namespace = stencilsets.keys()[0];
  24786. } else {
  24787. return undefined;
  24788. }
  24789. }
  24790. return this.namespace;
  24791. }
  24792. };
  24793. ORYX.Plugins.BPMN2_0 = ORYX.Plugins.AbstractPlugin.extend(ORYX.Plugins.BPMN2_0);
  24794. }()