menu-debug.js 249 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871
  1. /*
  2. Copyright (c) 2009, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 2.8.0r4
  6. */
  7. /**
  8. * @module menu
  9. * @description <p>The Menu family of components features a collection of
  10. * controls that make it easy to add menus to your website or web application.
  11. * With the Menu Controls you can create website fly-out menus, customized
  12. * context menus, or application-style menu bars with just a small amount of
  13. * scripting.</p><p>The Menu family of controls features:</p>
  14. * <ul>
  15. * <li>Keyboard and mouse navigation.</li>
  16. * <li>A rich event model that provides access to all of a menu's
  17. * interesting moments.</li>
  18. * <li>Support for
  19. * <a href="http://en.wikipedia.org/wiki/Progressive_Enhancement">Progressive
  20. * Enhancement</a>; Menus can be created from simple,
  21. * semantic markup on the page or purely through JavaScript.</li>
  22. * </ul>
  23. * @title Menu
  24. * @namespace YAHOO.widget
  25. * @requires Event, Dom, Container
  26. */
  27. (function () {
  28. var UA = YAHOO.env.ua,
  29. Dom = YAHOO.util.Dom,
  30. Event = YAHOO.util.Event,
  31. Lang = YAHOO.lang,
  32. _DIV = "DIV",
  33. _HD = "hd",
  34. _BD = "bd",
  35. _FT = "ft",
  36. _LI = "LI",
  37. _DISABLED = "disabled",
  38. _MOUSEOVER = "mouseover",
  39. _MOUSEOUT = "mouseout",
  40. _MOUSEDOWN = "mousedown",
  41. _MOUSEUP = "mouseup",
  42. _CLICK = "click",
  43. _KEYDOWN = "keydown",
  44. _KEYUP = "keyup",
  45. _KEYPRESS = "keypress",
  46. _CLICK_TO_HIDE = "clicktohide",
  47. _POSITION = "position",
  48. _DYNAMIC = "dynamic",
  49. _SHOW_DELAY = "showdelay",
  50. _SELECTED = "selected",
  51. _VISIBLE = "visible",
  52. _UL = "UL",
  53. _MENUMANAGER = "MenuManager";
  54. /**
  55. * Singleton that manages a collection of all menus and menu items. Listens
  56. * for DOM events at the document level and dispatches the events to the
  57. * corresponding menu or menu item.
  58. *
  59. * @namespace YAHOO.widget
  60. * @class MenuManager
  61. * @static
  62. */
  63. YAHOO.widget.MenuManager = function () {
  64. // Private member variables
  65. // Flag indicating if the DOM event handlers have been attached
  66. var m_bInitializedEventHandlers = false,
  67. // Collection of menus
  68. m_oMenus = {},
  69. // Collection of visible menus
  70. m_oVisibleMenus = {},
  71. // Collection of menu items
  72. m_oItems = {},
  73. // Map of DOM event types to their equivalent CustomEvent types
  74. m_oEventTypes = {
  75. "click": "clickEvent",
  76. "mousedown": "mouseDownEvent",
  77. "mouseup": "mouseUpEvent",
  78. "mouseover": "mouseOverEvent",
  79. "mouseout": "mouseOutEvent",
  80. "keydown": "keyDownEvent",
  81. "keyup": "keyUpEvent",
  82. "keypress": "keyPressEvent",
  83. "focus": "focusEvent",
  84. "focusin": "focusEvent",
  85. "blur": "blurEvent",
  86. "focusout": "blurEvent"
  87. },
  88. m_oFocusedMenuItem = null;
  89. // Private methods
  90. /**
  91. * @method getMenuRootElement
  92. * @description Finds the root DIV node of a menu or the root LI node of
  93. * a menu item.
  94. * @private
  95. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  96. * level-one-html.html#ID-58190037">HTMLElement</a>} p_oElement Object
  97. * specifying an HTML element.
  98. */
  99. function getMenuRootElement(p_oElement) {
  100. var oParentNode,
  101. returnVal;
  102. if (p_oElement && p_oElement.tagName) {
  103. switch (p_oElement.tagName.toUpperCase()) {
  104. case _DIV:
  105. oParentNode = p_oElement.parentNode;
  106. // Check if the DIV is the inner "body" node of a menu
  107. if ((
  108. Dom.hasClass(p_oElement, _HD) ||
  109. Dom.hasClass(p_oElement, _BD) ||
  110. Dom.hasClass(p_oElement, _FT)
  111. ) &&
  112. oParentNode &&
  113. oParentNode.tagName &&
  114. oParentNode.tagName.toUpperCase() == _DIV) {
  115. returnVal = oParentNode;
  116. }
  117. else {
  118. returnVal = p_oElement;
  119. }
  120. break;
  121. case _LI:
  122. returnVal = p_oElement;
  123. break;
  124. default:
  125. oParentNode = p_oElement.parentNode;
  126. if (oParentNode) {
  127. returnVal = getMenuRootElement(oParentNode);
  128. }
  129. break;
  130. }
  131. }
  132. return returnVal;
  133. }
  134. // Private event handlers
  135. /**
  136. * @method onDOMEvent
  137. * @description Generic, global event handler for all of a menu's
  138. * DOM-based events. This listens for events against the document
  139. * object. If the target of a given event is a member of a menu or
  140. * menu item's DOM, the instance's corresponding Custom Event is fired.
  141. * @private
  142. * @param {Event} p_oEvent Object representing the DOM event object
  143. * passed back by the event utility (YAHOO.util.Event).
  144. */
  145. function onDOMEvent(p_oEvent) {
  146. // Get the target node of the DOM event
  147. var oTarget = Event.getTarget(p_oEvent),
  148. // See if the target of the event was a menu, or a menu item
  149. oElement = getMenuRootElement(oTarget),
  150. bFireEvent = true,
  151. sEventType = p_oEvent.type,
  152. sCustomEventType,
  153. sTagName,
  154. sId,
  155. oMenuItem,
  156. oMenu;
  157. if (oElement) {
  158. sTagName = oElement.tagName.toUpperCase();
  159. if (sTagName == _LI) {
  160. sId = oElement.id;
  161. if (sId && m_oItems[sId]) {
  162. oMenuItem = m_oItems[sId];
  163. oMenu = oMenuItem.parent;
  164. }
  165. }
  166. else if (sTagName == _DIV) {
  167. if (oElement.id) {
  168. oMenu = m_oMenus[oElement.id];
  169. }
  170. }
  171. }
  172. if (oMenu) {
  173. sCustomEventType = m_oEventTypes[sEventType];
  174. /*
  175. There is an inconsistency between Firefox for Mac OS X and
  176. Firefox Windows & Linux regarding the triggering of the
  177. display of the browser's context menu and the subsequent
  178. firing of the "click" event. In Firefox for Windows & Linux,
  179. when the user triggers the display of the browser's context
  180. menu the "click" event also fires for the document object,
  181. even though the "click" event did not fire for the element
  182. that was the original target of the "contextmenu" event.
  183. This is unique to Firefox on Windows & Linux. For all
  184. other A-Grade browsers, including Firefox for Mac OS X, the
  185. "click" event doesn't fire for the document object.
  186. This bug in Firefox for Windows affects Menu, as Menu
  187. instances listen for events at the document level and
  188. dispatches Custom Events of the same name. Therefore users
  189. of Menu will get an unwanted firing of the "click"
  190. custom event. The following line fixes this bug.
  191. */
  192. if (sEventType == "click" &&
  193. (UA.gecko && oMenu.platform != "mac") &&
  194. p_oEvent.button > 0) {
  195. bFireEvent = false;
  196. }
  197. // Fire the Custom Event that corresponds the current DOM event
  198. if (bFireEvent && oMenuItem && !oMenuItem.cfg.getProperty(_DISABLED)) {
  199. oMenuItem[sCustomEventType].fire(p_oEvent);
  200. }
  201. if (bFireEvent) {
  202. oMenu[sCustomEventType].fire(p_oEvent, oMenuItem);
  203. }
  204. }
  205. else if (sEventType == _MOUSEDOWN) {
  206. /*
  207. If the target of the event wasn't a menu, hide all
  208. dynamically positioned menus
  209. */
  210. for (var i in m_oVisibleMenus) {
  211. if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
  212. oMenu = m_oVisibleMenus[i];
  213. if (oMenu.cfg.getProperty(_CLICK_TO_HIDE) &&
  214. !(oMenu instanceof YAHOO.widget.MenuBar) &&
  215. oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
  216. oMenu.hide();
  217. // In IE when the user mouses down on a focusable
  218. // element that element will be focused and become
  219. // the "activeElement".
  220. // (http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx)
  221. // However, there is a bug in IE where if there is
  222. // a positioned element with a focused descendant
  223. // that is hidden in response to the mousedown
  224. // event, the target of the mousedown event will
  225. // appear to have focus, but will not be set as
  226. // the activeElement. This will result in the
  227. // element not firing key events, even though it
  228. // appears to have focus. The following call to
  229. // "setActive" fixes this bug.
  230. if (UA.ie && oTarget.focus) {
  231. oTarget.setActive();
  232. }
  233. }
  234. else {
  235. if (oMenu.cfg.getProperty(_SHOW_DELAY) > 0) {
  236. oMenu._cancelShowDelay();
  237. }
  238. if (oMenu.activeItem) {
  239. oMenu.activeItem.blur();
  240. oMenu.activeItem.cfg.setProperty(_SELECTED, false);
  241. oMenu.activeItem = null;
  242. }
  243. }
  244. }
  245. }
  246. }
  247. }
  248. /**
  249. * @method onMenuDestroy
  250. * @description "destroy" event handler for a menu.
  251. * @private
  252. * @param {String} p_sType String representing the name of the event
  253. * that was fired.
  254. * @param {Array} p_aArgs Array of arguments sent when the event
  255. * was fired.
  256. * @param {YAHOO.widget.Menu} p_oMenu The menu that fired the event.
  257. */
  258. function onMenuDestroy(p_sType, p_aArgs, p_oMenu) {
  259. if (m_oMenus[p_oMenu.id]) {
  260. this.removeMenu(p_oMenu);
  261. }
  262. }
  263. /**
  264. * @method onMenuFocus
  265. * @description "focus" event handler for a MenuItem instance.
  266. * @private
  267. * @param {String} p_sType String representing the name of the event
  268. * that was fired.
  269. * @param {Array} p_aArgs Array of arguments sent when the event
  270. * was fired.
  271. */
  272. function onMenuFocus(p_sType, p_aArgs) {
  273. var oItem = p_aArgs[1];
  274. if (oItem) {
  275. m_oFocusedMenuItem = oItem;
  276. }
  277. }
  278. /**
  279. * @method onMenuBlur
  280. * @description "blur" event handler for a MenuItem instance.
  281. * @private
  282. * @param {String} p_sType String representing the name of the event
  283. * that was fired.
  284. * @param {Array} p_aArgs Array of arguments sent when the event
  285. * was fired.
  286. */
  287. function onMenuBlur(p_sType, p_aArgs) {
  288. m_oFocusedMenuItem = null;
  289. }
  290. /**
  291. * @method onMenuVisibleConfigChange
  292. * @description Event handler for when the "visible" configuration
  293. * property of a Menu instance changes.
  294. * @private
  295. * @param {String} p_sType String representing the name of the event
  296. * that was fired.
  297. * @param {Array} p_aArgs Array of arguments sent when the event
  298. * was fired.
  299. */
  300. function onMenuVisibleConfigChange(p_sType, p_aArgs) {
  301. var bVisible = p_aArgs[0],
  302. sId = this.id;
  303. if (bVisible) {
  304. m_oVisibleMenus[sId] = this;
  305. YAHOO.log(this + " added to the collection of visible menus.",
  306. "info", _MENUMANAGER);
  307. }
  308. else if (m_oVisibleMenus[sId]) {
  309. delete m_oVisibleMenus[sId];
  310. YAHOO.log(this + " removed from the collection of visible menus.",
  311. "info", _MENUMANAGER);
  312. }
  313. }
  314. /**
  315. * @method onItemDestroy
  316. * @description "destroy" event handler for a MenuItem instance.
  317. * @private
  318. * @param {String} p_sType String representing the name of the event
  319. * that was fired.
  320. * @param {Array} p_aArgs Array of arguments sent when the event
  321. * was fired.
  322. */
  323. function onItemDestroy(p_sType, p_aArgs) {
  324. removeItem(this);
  325. }
  326. /**
  327. * @method removeItem
  328. * @description Removes a MenuItem instance from the MenuManager's collection of MenuItems.
  329. * @private
  330. * @param {MenuItem} p_oMenuItem The MenuItem instance to be removed.
  331. */
  332. function removeItem(p_oMenuItem) {
  333. var sId = p_oMenuItem.id;
  334. if (sId && m_oItems[sId]) {
  335. if (m_oFocusedMenuItem == p_oMenuItem) {
  336. m_oFocusedMenuItem = null;
  337. }
  338. delete m_oItems[sId];
  339. p_oMenuItem.destroyEvent.unsubscribe(onItemDestroy);
  340. YAHOO.log(p_oMenuItem + " successfully unregistered.", "info", _MENUMANAGER);
  341. }
  342. }
  343. /**
  344. * @method onItemAdded
  345. * @description "itemadded" event handler for a Menu instance.
  346. * @private
  347. * @param {String} p_sType String representing the name of the event
  348. * that was fired.
  349. * @param {Array} p_aArgs Array of arguments sent when the event
  350. * was fired.
  351. */
  352. function onItemAdded(p_sType, p_aArgs) {
  353. var oItem = p_aArgs[0],
  354. sId;
  355. if (oItem instanceof YAHOO.widget.MenuItem) {
  356. sId = oItem.id;
  357. if (!m_oItems[sId]) {
  358. m_oItems[sId] = oItem;
  359. oItem.destroyEvent.subscribe(onItemDestroy);
  360. YAHOO.log(oItem + " successfully registered.", "info", _MENUMANAGER);
  361. }
  362. }
  363. }
  364. return {
  365. // Privileged methods
  366. /**
  367. * @method addMenu
  368. * @description Adds a menu to the collection of known menus.
  369. * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
  370. * instance to be added.
  371. */
  372. addMenu: function (p_oMenu) {
  373. var oDoc;
  374. if (p_oMenu instanceof YAHOO.widget.Menu && p_oMenu.id &&
  375. !m_oMenus[p_oMenu.id]) {
  376. m_oMenus[p_oMenu.id] = p_oMenu;
  377. if (!m_bInitializedEventHandlers) {
  378. oDoc = document;
  379. Event.on(oDoc, _MOUSEOVER, onDOMEvent, this, true);
  380. Event.on(oDoc, _MOUSEOUT, onDOMEvent, this, true);
  381. Event.on(oDoc, _MOUSEDOWN, onDOMEvent, this, true);
  382. Event.on(oDoc, _MOUSEUP, onDOMEvent, this, true);
  383. Event.on(oDoc, _CLICK, onDOMEvent, this, true);
  384. Event.on(oDoc, _KEYDOWN, onDOMEvent, this, true);
  385. Event.on(oDoc, _KEYUP, onDOMEvent, this, true);
  386. Event.on(oDoc, _KEYPRESS, onDOMEvent, this, true);
  387. Event.onFocus(oDoc, onDOMEvent, this, true);
  388. Event.onBlur(oDoc, onDOMEvent, this, true);
  389. m_bInitializedEventHandlers = true;
  390. YAHOO.log("DOM event handlers initialized.", "info", _MENUMANAGER);
  391. }
  392. p_oMenu.cfg.subscribeToConfigEvent(_VISIBLE, onMenuVisibleConfigChange);
  393. p_oMenu.destroyEvent.subscribe(onMenuDestroy, p_oMenu, this);
  394. p_oMenu.itemAddedEvent.subscribe(onItemAdded);
  395. p_oMenu.focusEvent.subscribe(onMenuFocus);
  396. p_oMenu.blurEvent.subscribe(onMenuBlur);
  397. YAHOO.log(p_oMenu + " successfully registered.", "info", _MENUMANAGER);
  398. }
  399. },
  400. /**
  401. * @method removeMenu
  402. * @description Removes a menu from the collection of known menus.
  403. * @param {YAHOO.widget.Menu} p_oMenu Object specifying the Menu
  404. * instance to be removed.
  405. */
  406. removeMenu: function (p_oMenu) {
  407. var sId,
  408. aItems,
  409. i;
  410. if (p_oMenu) {
  411. sId = p_oMenu.id;
  412. if ((sId in m_oMenus) && (m_oMenus[sId] == p_oMenu)) {
  413. // Unregister each menu item
  414. aItems = p_oMenu.getItems();
  415. if (aItems && aItems.length > 0) {
  416. i = aItems.length - 1;
  417. do {
  418. removeItem(aItems[i]);
  419. }
  420. while (i--);
  421. }
  422. // Unregister the menu
  423. delete m_oMenus[sId];
  424. YAHOO.log(p_oMenu + " successfully unregistered.", "info", _MENUMANAGER);
  425. /*
  426. Unregister the menu from the collection of
  427. visible menus
  428. */
  429. if ((sId in m_oVisibleMenus) && (m_oVisibleMenus[sId] == p_oMenu)) {
  430. delete m_oVisibleMenus[sId];
  431. YAHOO.log(p_oMenu + " unregistered from the" +
  432. " collection of visible menus.", "info", _MENUMANAGER);
  433. }
  434. // Unsubscribe event listeners
  435. if (p_oMenu.cfg) {
  436. p_oMenu.cfg.unsubscribeFromConfigEvent(_VISIBLE,
  437. onMenuVisibleConfigChange);
  438. }
  439. p_oMenu.destroyEvent.unsubscribe(onMenuDestroy,
  440. p_oMenu);
  441. p_oMenu.itemAddedEvent.unsubscribe(onItemAdded);
  442. p_oMenu.focusEvent.unsubscribe(onMenuFocus);
  443. p_oMenu.blurEvent.unsubscribe(onMenuBlur);
  444. }
  445. }
  446. },
  447. /**
  448. * @method hideVisible
  449. * @description Hides all visible, dynamically positioned menus
  450. * (excluding instances of YAHOO.widget.MenuBar).
  451. */
  452. hideVisible: function () {
  453. var oMenu;
  454. for (var i in m_oVisibleMenus) {
  455. if (Lang.hasOwnProperty(m_oVisibleMenus, i)) {
  456. oMenu = m_oVisibleMenus[i];
  457. if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
  458. oMenu.cfg.getProperty(_POSITION) == _DYNAMIC) {
  459. oMenu.hide();
  460. }
  461. }
  462. }
  463. },
  464. /**
  465. * @method getVisible
  466. * @description Returns a collection of all visible menus registered
  467. * with the menu manger.
  468. * @return {Object}
  469. */
  470. getVisible: function () {
  471. return m_oVisibleMenus;
  472. },
  473. /**
  474. * @method getMenus
  475. * @description Returns a collection of all menus registered with the
  476. * menu manger.
  477. * @return {Object}
  478. */
  479. getMenus: function () {
  480. return m_oMenus;
  481. },
  482. /**
  483. * @method getMenu
  484. * @description Returns a menu with the specified id.
  485. * @param {String} p_sId String specifying the id of the
  486. * <code>&#60;div&#62;</code> element representing the menu to
  487. * be retrieved.
  488. * @return {YAHOO.widget.Menu}
  489. */
  490. getMenu: function (p_sId) {
  491. var returnVal;
  492. if (p_sId in m_oMenus) {
  493. returnVal = m_oMenus[p_sId];
  494. }
  495. return returnVal;
  496. },
  497. /**
  498. * @method getMenuItem
  499. * @description Returns a menu item with the specified id.
  500. * @param {String} p_sId String specifying the id of the
  501. * <code>&#60;li&#62;</code> element representing the menu item to
  502. * be retrieved.
  503. * @return {YAHOO.widget.MenuItem}
  504. */
  505. getMenuItem: function (p_sId) {
  506. var returnVal;
  507. if (p_sId in m_oItems) {
  508. returnVal = m_oItems[p_sId];
  509. }
  510. return returnVal;
  511. },
  512. /**
  513. * @method getMenuItemGroup
  514. * @description Returns an array of menu item instances whose
  515. * corresponding <code>&#60;li&#62;</code> elements are child
  516. * nodes of the <code>&#60;ul&#62;</code> element with the
  517. * specified id.
  518. * @param {String} p_sId String specifying the id of the
  519. * <code>&#60;ul&#62;</code> element representing the group of
  520. * menu items to be retrieved.
  521. * @return {Array}
  522. */
  523. getMenuItemGroup: function (p_sId) {
  524. var oUL = Dom.get(p_sId),
  525. aItems,
  526. oNode,
  527. oItem,
  528. sId,
  529. returnVal;
  530. if (oUL && oUL.tagName && oUL.tagName.toUpperCase() == _UL) {
  531. oNode = oUL.firstChild;
  532. if (oNode) {
  533. aItems = [];
  534. do {
  535. sId = oNode.id;
  536. if (sId) {
  537. oItem = this.getMenuItem(sId);
  538. if (oItem) {
  539. aItems[aItems.length] = oItem;
  540. }
  541. }
  542. }
  543. while ((oNode = oNode.nextSibling));
  544. if (aItems.length > 0) {
  545. returnVal = aItems;
  546. }
  547. }
  548. }
  549. return returnVal;
  550. },
  551. /**
  552. * @method getFocusedMenuItem
  553. * @description Returns a reference to the menu item that currently
  554. * has focus.
  555. * @return {YAHOO.widget.MenuItem}
  556. */
  557. getFocusedMenuItem: function () {
  558. return m_oFocusedMenuItem;
  559. },
  560. /**
  561. * @method getFocusedMenu
  562. * @description Returns a reference to the menu that currently
  563. * has focus.
  564. * @return {YAHOO.widget.Menu}
  565. */
  566. getFocusedMenu: function () {
  567. var returnVal;
  568. if (m_oFocusedMenuItem) {
  569. returnVal = m_oFocusedMenuItem.parent.getRoot();
  570. }
  571. return returnVal;
  572. },
  573. /**
  574. * @method toString
  575. * @description Returns a string representing the menu manager.
  576. * @return {String}
  577. */
  578. toString: function () {
  579. return _MENUMANAGER;
  580. }
  581. };
  582. }();
  583. })();
  584. (function () {
  585. var Lang = YAHOO.lang,
  586. // String constants
  587. _MENU = "Menu",
  588. _DIV_UPPERCASE = "DIV",
  589. _DIV_LOWERCASE = "div",
  590. _ID = "id",
  591. _SELECT = "SELECT",
  592. _XY = "xy",
  593. _Y = "y",
  594. _UL_UPPERCASE = "UL",
  595. _UL_LOWERCASE = "ul",
  596. _FIRST_OF_TYPE = "first-of-type",
  597. _LI = "LI",
  598. _OPTGROUP = "OPTGROUP",
  599. _OPTION = "OPTION",
  600. _DISABLED = "disabled",
  601. _NONE = "none",
  602. _SELECTED = "selected",
  603. _GROUP_INDEX = "groupindex",
  604. _INDEX = "index",
  605. _SUBMENU = "submenu",
  606. _VISIBLE = "visible",
  607. _HIDE_DELAY = "hidedelay",
  608. _POSITION = "position",
  609. _DYNAMIC = "dynamic",
  610. _STATIC = "static",
  611. _DYNAMIC_STATIC = _DYNAMIC + "," + _STATIC,
  612. _URL = "url",
  613. _HASH = "#",
  614. _TARGET = "target",
  615. _MAX_HEIGHT = "maxheight",
  616. _TOP_SCROLLBAR = "topscrollbar",
  617. _BOTTOM_SCROLLBAR = "bottomscrollbar",
  618. _UNDERSCORE = "_",
  619. _TOP_SCROLLBAR_DISABLED = _TOP_SCROLLBAR + _UNDERSCORE + _DISABLED,
  620. _BOTTOM_SCROLLBAR_DISABLED = _BOTTOM_SCROLLBAR + _UNDERSCORE + _DISABLED,
  621. _MOUSEMOVE = "mousemove",
  622. _SHOW_DELAY = "showdelay",
  623. _SUBMENU_HIDE_DELAY = "submenuhidedelay",
  624. _IFRAME = "iframe",
  625. _CONSTRAIN_TO_VIEWPORT = "constraintoviewport",
  626. _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
  627. _SUBMENU_ALIGNMENT = "submenualignment",
  628. _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
  629. _CLICK_TO_HIDE = "clicktohide",
  630. _CONTAINER = "container",
  631. _SCROLL_INCREMENT = "scrollincrement",
  632. _MIN_SCROLL_HEIGHT = "minscrollheight",
  633. _CLASSNAME = "classname",
  634. _SHADOW = "shadow",
  635. _KEEP_OPEN = "keepopen",
  636. _HD = "hd",
  637. _HAS_TITLE = "hastitle",
  638. _CONTEXT = "context",
  639. _EMPTY_STRING = "",
  640. _MOUSEDOWN = "mousedown",
  641. _KEYDOWN = "keydown",
  642. _HEIGHT = "height",
  643. _WIDTH = "width",
  644. _PX = "px",
  645. _EFFECT = "effect",
  646. _MONITOR_RESIZE = "monitorresize",
  647. _DISPLAY = "display",
  648. _BLOCK = "block",
  649. _VISIBILITY = "visibility",
  650. _ABSOLUTE = "absolute",
  651. _ZINDEX = "zindex",
  652. _YUI_MENU_BODY_SCROLLED = "yui-menu-body-scrolled",
  653. _NON_BREAKING_SPACE = "&#32;",
  654. _SPACE = " ",
  655. _MOUSEOVER = "mouseover",
  656. _MOUSEOUT = "mouseout",
  657. _ITEM_ADDED = "itemAdded",
  658. _ITEM_REMOVED = "itemRemoved",
  659. _HIDDEN = "hidden",
  660. _YUI_MENU_SHADOW = "yui-menu-shadow",
  661. _YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + "-visible",
  662. _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE = _YUI_MENU_SHADOW + _SPACE + _YUI_MENU_SHADOW_VISIBLE;
  663. /**
  664. * The Menu class creates a container that holds a vertical list representing
  665. * a set of options or commands. Menu is the base class for all
  666. * menu containers.
  667. * @param {String} p_oElement String specifying the id attribute of the
  668. * <code>&#60;div&#62;</code> element of the menu.
  669. * @param {String} p_oElement String specifying the id attribute of the
  670. * <code>&#60;select&#62;</code> element to be used as the data source
  671. * for the menu.
  672. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  673. * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
  674. * specifying the <code>&#60;div&#62;</code> element of the menu.
  675. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  676. * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
  677. * Object specifying the <code>&#60;select&#62;</code> element to be used as
  678. * the data source for the menu.
  679. * @param {Object} p_oConfig Optional. Object literal specifying the
  680. * configuration for the menu. See configuration class documentation for
  681. * more details.
  682. * @namespace YAHOO.widget
  683. * @class Menu
  684. * @constructor
  685. * @extends YAHOO.widget.Overlay
  686. */
  687. YAHOO.widget.Menu = function (p_oElement, p_oConfig) {
  688. if (p_oConfig) {
  689. this.parent = p_oConfig.parent;
  690. this.lazyLoad = p_oConfig.lazyLoad || p_oConfig.lazyload;
  691. this.itemData = p_oConfig.itemData || p_oConfig.itemdata;
  692. }
  693. YAHOO.widget.Menu.superclass.constructor.call(this, p_oElement, p_oConfig);
  694. };
  695. /**
  696. * @method checkPosition
  697. * @description Checks to make sure that the value of the "position" property
  698. * is one of the supported strings. Returns true if the position is supported.
  699. * @private
  700. * @param {Object} p_sPosition String specifying the position of the menu.
  701. * @return {Boolean}
  702. */
  703. function checkPosition(p_sPosition) {
  704. var returnVal = false;
  705. if (Lang.isString(p_sPosition)) {
  706. returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
  707. }
  708. return returnVal;
  709. }
  710. var Dom = YAHOO.util.Dom,
  711. Event = YAHOO.util.Event,
  712. Module = YAHOO.widget.Module,
  713. Overlay = YAHOO.widget.Overlay,
  714. Menu = YAHOO.widget.Menu,
  715. MenuManager = YAHOO.widget.MenuManager,
  716. CustomEvent = YAHOO.util.CustomEvent,
  717. UA = YAHOO.env.ua,
  718. m_oShadowTemplate,
  719. bFocusListenerInitialized = false,
  720. oFocusedElement,
  721. EVENT_TYPES = [
  722. ["mouseOverEvent", _MOUSEOVER],
  723. ["mouseOutEvent", _MOUSEOUT],
  724. ["mouseDownEvent", _MOUSEDOWN],
  725. ["mouseUpEvent", "mouseup"],
  726. ["clickEvent", "click"],
  727. ["keyPressEvent", "keypress"],
  728. ["keyDownEvent", _KEYDOWN],
  729. ["keyUpEvent", "keyup"],
  730. ["focusEvent", "focus"],
  731. ["blurEvent", "blur"],
  732. ["itemAddedEvent", _ITEM_ADDED],
  733. ["itemRemovedEvent", _ITEM_REMOVED]
  734. ],
  735. VISIBLE_CONFIG = {
  736. key: _VISIBLE,
  737. value: false,
  738. validator: Lang.isBoolean
  739. },
  740. CONSTRAIN_TO_VIEWPORT_CONFIG = {
  741. key: _CONSTRAIN_TO_VIEWPORT,
  742. value: true,
  743. validator: Lang.isBoolean,
  744. supercedes: [_IFRAME,"x",_Y,_XY]
  745. },
  746. PREVENT_CONTEXT_OVERLAP_CONFIG = {
  747. key: _PREVENT_CONTEXT_OVERLAP,
  748. value: true,
  749. validator: Lang.isBoolean,
  750. supercedes: [_CONSTRAIN_TO_VIEWPORT]
  751. },
  752. POSITION_CONFIG = {
  753. key: _POSITION,
  754. value: _DYNAMIC,
  755. validator: checkPosition,
  756. supercedes: [_VISIBLE, _IFRAME]
  757. },
  758. SUBMENU_ALIGNMENT_CONFIG = {
  759. key: _SUBMENU_ALIGNMENT,
  760. value: ["tl","tr"]
  761. },
  762. AUTO_SUBMENU_DISPLAY_CONFIG = {
  763. key: _AUTO_SUBMENU_DISPLAY,
  764. value: true,
  765. validator: Lang.isBoolean,
  766. suppressEvent: true
  767. },
  768. SHOW_DELAY_CONFIG = {
  769. key: _SHOW_DELAY,
  770. value: 250,
  771. validator: Lang.isNumber,
  772. suppressEvent: true
  773. },
  774. HIDE_DELAY_CONFIG = {
  775. key: _HIDE_DELAY,
  776. value: 0,
  777. validator: Lang.isNumber,
  778. suppressEvent: true
  779. },
  780. SUBMENU_HIDE_DELAY_CONFIG = {
  781. key: _SUBMENU_HIDE_DELAY,
  782. value: 250,
  783. validator: Lang.isNumber,
  784. suppressEvent: true
  785. },
  786. CLICK_TO_HIDE_CONFIG = {
  787. key: _CLICK_TO_HIDE,
  788. value: true,
  789. validator: Lang.isBoolean,
  790. suppressEvent: true
  791. },
  792. CONTAINER_CONFIG = {
  793. key: _CONTAINER,
  794. suppressEvent: true
  795. },
  796. SCROLL_INCREMENT_CONFIG = {
  797. key: _SCROLL_INCREMENT,
  798. value: 1,
  799. validator: Lang.isNumber,
  800. supercedes: [_MAX_HEIGHT],
  801. suppressEvent: true
  802. },
  803. MIN_SCROLL_HEIGHT_CONFIG = {
  804. key: _MIN_SCROLL_HEIGHT,
  805. value: 90,
  806. validator: Lang.isNumber,
  807. supercedes: [_MAX_HEIGHT],
  808. suppressEvent: true
  809. },
  810. MAX_HEIGHT_CONFIG = {
  811. key: _MAX_HEIGHT,
  812. value: 0,
  813. validator: Lang.isNumber,
  814. supercedes: [_IFRAME],
  815. suppressEvent: true
  816. },
  817. CLASS_NAME_CONFIG = {
  818. key: _CLASSNAME,
  819. value: null,
  820. validator: Lang.isString,
  821. suppressEvent: true
  822. },
  823. DISABLED_CONFIG = {
  824. key: _DISABLED,
  825. value: false,
  826. validator: Lang.isBoolean,
  827. suppressEvent: true
  828. },
  829. SHADOW_CONFIG = {
  830. key: _SHADOW,
  831. value: true,
  832. validator: Lang.isBoolean,
  833. suppressEvent: true,
  834. supercedes: [_VISIBLE]
  835. },
  836. KEEP_OPEN_CONFIG = {
  837. key: _KEEP_OPEN,
  838. value: false,
  839. validator: Lang.isBoolean
  840. };
  841. function onDocFocus(event) {
  842. oFocusedElement = Event.getTarget(event);
  843. }
  844. YAHOO.lang.extend(Menu, Overlay, {
  845. // Constants
  846. /**
  847. * @property CSS_CLASS_NAME
  848. * @description String representing the CSS class(es) to be applied to the
  849. * menu's <code>&#60;div&#62;</code> element.
  850. * @default "yuimenu"
  851. * @final
  852. * @type String
  853. */
  854. CSS_CLASS_NAME: "yuimenu",
  855. /**
  856. * @property ITEM_TYPE
  857. * @description Object representing the type of menu item to instantiate and
  858. * add when parsing the child nodes (either <code>&#60;li&#62;</code> element,
  859. * <code>&#60;optgroup&#62;</code> element or <code>&#60;option&#62;</code>)
  860. * of the menu's source HTML element.
  861. * @default YAHOO.widget.MenuItem
  862. * @final
  863. * @type YAHOO.widget.MenuItem
  864. */
  865. ITEM_TYPE: null,
  866. /**
  867. * @property GROUP_TITLE_TAG_NAME
  868. * @description String representing the tagname of the HTML element used to
  869. * title the menu's item groups.
  870. * @default H6
  871. * @final
  872. * @type String
  873. */
  874. GROUP_TITLE_TAG_NAME: "h6",
  875. /**
  876. * @property OFF_SCREEN_POSITION
  877. * @description Array representing the default x and y position that a menu
  878. * should have when it is positioned outside the viewport by the
  879. * "poistionOffScreen" method.
  880. * @default "-999em"
  881. * @final
  882. * @type String
  883. */
  884. OFF_SCREEN_POSITION: "-999em",
  885. // Private properties
  886. /**
  887. * @property _useHideDelay
  888. * @description Boolean indicating if the "mouseover" and "mouseout" event
  889. * handlers used for hiding the menu via a call to "YAHOO.lang.later" have
  890. * already been assigned.
  891. * @default false
  892. * @private
  893. * @type Boolean
  894. */
  895. _useHideDelay: false,
  896. /**
  897. * @property _bHandledMouseOverEvent
  898. * @description Boolean indicating the current state of the menu's
  899. * "mouseover" event.
  900. * @default false
  901. * @private
  902. * @type Boolean
  903. */
  904. _bHandledMouseOverEvent: false,
  905. /**
  906. * @property _bHandledMouseOutEvent
  907. * @description Boolean indicating the current state of the menu's
  908. * "mouseout" event.
  909. * @default false
  910. * @private
  911. * @type Boolean
  912. */
  913. _bHandledMouseOutEvent: false,
  914. /**
  915. * @property _aGroupTitleElements
  916. * @description Array of HTML element used to title groups of menu items.
  917. * @default []
  918. * @private
  919. * @type Array
  920. */
  921. _aGroupTitleElements: null,
  922. /**
  923. * @property _aItemGroups
  924. * @description Multi-dimensional Array representing the menu items as they
  925. * are grouped in the menu.
  926. * @default []
  927. * @private
  928. * @type Array
  929. */
  930. _aItemGroups: null,
  931. /**
  932. * @property _aListElements
  933. * @description Array of <code>&#60;ul&#62;</code> elements, each of which is
  934. * the parent node for each item's <code>&#60;li&#62;</code> element.
  935. * @default []
  936. * @private
  937. * @type Array
  938. */
  939. _aListElements: null,
  940. /**
  941. * @property _nCurrentMouseX
  942. * @description The current x coordinate of the mouse inside the area of
  943. * the menu.
  944. * @default 0
  945. * @private
  946. * @type Number
  947. */
  948. _nCurrentMouseX: 0,
  949. /**
  950. * @property _bStopMouseEventHandlers
  951. * @description Stops "mouseover," "mouseout," and "mousemove" event handlers
  952. * from executing.
  953. * @default false
  954. * @private
  955. * @type Boolean
  956. */
  957. _bStopMouseEventHandlers: false,
  958. /**
  959. * @property _sClassName
  960. * @description The current value of the "classname" configuration attribute.
  961. * @default null
  962. * @private
  963. * @type String
  964. */
  965. _sClassName: null,
  966. // Public properties
  967. /**
  968. * @property lazyLoad
  969. * @description Boolean indicating if the menu's "lazy load" feature is
  970. * enabled. If set to "true," initialization and rendering of the menu's
  971. * items will be deferred until the first time it is made visible. This
  972. * property should be set via the constructor using the configuration
  973. * object literal.
  974. * @default false
  975. * @type Boolean
  976. */
  977. lazyLoad: false,
  978. /**
  979. * @property itemData
  980. * @description Array of items to be added to the menu. The array can contain
  981. * strings representing the text for each item to be created, object literals
  982. * representing the menu item configuration properties, or MenuItem instances.
  983. * This property should be set via the constructor using the configuration
  984. * object literal.
  985. * @default null
  986. * @type Array
  987. */
  988. itemData: null,
  989. /**
  990. * @property activeItem
  991. * @description Object reference to the item in the menu that has is selected.
  992. * @default null
  993. * @type YAHOO.widget.MenuItem
  994. */
  995. activeItem: null,
  996. /**
  997. * @property parent
  998. * @description Object reference to the menu's parent menu or menu item.
  999. * This property can be set via the constructor using the configuration
  1000. * object literal.
  1001. * @default null
  1002. * @type YAHOO.widget.MenuItem
  1003. */
  1004. parent: null,
  1005. /**
  1006. * @property srcElement
  1007. * @description Object reference to the HTML element (either
  1008. * <code>&#60;select&#62;</code> or <code>&#60;div&#62;</code>) used to
  1009. * create the menu.
  1010. * @default null
  1011. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  1012. * level-one-html.html#ID-94282980">HTMLSelectElement</a>|<a
  1013. * href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.
  1014. * html#ID-22445964">HTMLDivElement</a>
  1015. */
  1016. srcElement: null,
  1017. // Events
  1018. /**
  1019. * @event mouseOverEvent
  1020. * @description Fires when the mouse has entered the menu. Passes back
  1021. * the DOM Event object as an argument.
  1022. */
  1023. /**
  1024. * @event mouseOutEvent
  1025. * @description Fires when the mouse has left the menu. Passes back the DOM
  1026. * Event object as an argument.
  1027. * @type YAHOO.util.CustomEvent
  1028. */
  1029. /**
  1030. * @event mouseDownEvent
  1031. * @description Fires when the user mouses down on the menu. Passes back the
  1032. * DOM Event object as an argument.
  1033. * @type YAHOO.util.CustomEvent
  1034. */
  1035. /**
  1036. * @event mouseUpEvent
  1037. * @description Fires when the user releases a mouse button while the mouse is
  1038. * over the menu. Passes back the DOM Event object as an argument.
  1039. * @type YAHOO.util.CustomEvent
  1040. */
  1041. /**
  1042. * @event clickEvent
  1043. * @description Fires when the user clicks the on the menu. Passes back the
  1044. * DOM Event object as an argument.
  1045. * @type YAHOO.util.CustomEvent
  1046. */
  1047. /**
  1048. * @event keyPressEvent
  1049. * @description Fires when the user presses an alphanumeric key when one of the
  1050. * menu's items has focus. Passes back the DOM Event object as an argument.
  1051. * @type YAHOO.util.CustomEvent
  1052. */
  1053. /**
  1054. * @event keyDownEvent
  1055. * @description Fires when the user presses a key when one of the menu's items
  1056. * has focus. Passes back the DOM Event object as an argument.
  1057. * @type YAHOO.util.CustomEvent
  1058. */
  1059. /**
  1060. * @event keyUpEvent
  1061. * @description Fires when the user releases a key when one of the menu's items
  1062. * has focus. Passes back the DOM Event object as an argument.
  1063. * @type YAHOO.util.CustomEvent
  1064. */
  1065. /**
  1066. * @event itemAddedEvent
  1067. * @description Fires when an item is added to the menu.
  1068. * @type YAHOO.util.CustomEvent
  1069. */
  1070. /**
  1071. * @event itemRemovedEvent
  1072. * @description Fires when an item is removed to the menu.
  1073. * @type YAHOO.util.CustomEvent
  1074. */
  1075. /**
  1076. * @method init
  1077. * @description The Menu class's initialization method. This method is
  1078. * automatically called by the constructor, and sets up all DOM references
  1079. * for pre-existing markup, and creates required markup if it is not
  1080. * already present.
  1081. * @param {String} p_oElement String specifying the id attribute of the
  1082. * <code>&#60;div&#62;</code> element of the menu.
  1083. * @param {String} p_oElement String specifying the id attribute of the
  1084. * <code>&#60;select&#62;</code> element to be used as the data source
  1085. * for the menu.
  1086. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  1087. * level-one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object
  1088. * specifying the <code>&#60;div&#62;</code> element of the menu.
  1089. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  1090. * level-one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement
  1091. * Object specifying the <code>&#60;select&#62;</code> element to be used as
  1092. * the data source for the menu.
  1093. * @param {Object} p_oConfig Optional. Object literal specifying the
  1094. * configuration for the menu. See configuration class documentation for
  1095. * more details.
  1096. */
  1097. init: function (p_oElement, p_oConfig) {
  1098. this._aItemGroups = [];
  1099. this._aListElements = [];
  1100. this._aGroupTitleElements = [];
  1101. if (!this.ITEM_TYPE) {
  1102. this.ITEM_TYPE = YAHOO.widget.MenuItem;
  1103. }
  1104. var oElement;
  1105. if (Lang.isString(p_oElement)) {
  1106. oElement = Dom.get(p_oElement);
  1107. }
  1108. else if (p_oElement.tagName) {
  1109. oElement = p_oElement;
  1110. }
  1111. if (oElement && oElement.tagName) {
  1112. switch(oElement.tagName.toUpperCase()) {
  1113. case _DIV_UPPERCASE:
  1114. this.srcElement = oElement;
  1115. if (!oElement.id) {
  1116. oElement.setAttribute(_ID, Dom.generateId());
  1117. }
  1118. /*
  1119. Note: we don't pass the user config in here yet
  1120. because we only want it executed once, at the lowest
  1121. subclass level.
  1122. */
  1123. Menu.superclass.init.call(this, oElement);
  1124. this.beforeInitEvent.fire(Menu);
  1125. YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
  1126. break;
  1127. case _SELECT:
  1128. this.srcElement = oElement;
  1129. /*
  1130. The source element is not something that we can use
  1131. outright, so we need to create a new Overlay
  1132. Note: we don't pass the user config in here yet
  1133. because we only want it executed once, at the lowest
  1134. subclass level.
  1135. */
  1136. Menu.superclass.init.call(this, Dom.generateId());
  1137. this.beforeInitEvent.fire(Menu);
  1138. YAHOO.log("Source element: " + this.srcElement.tagName, "info", this.toString());
  1139. break;
  1140. }
  1141. }
  1142. else {
  1143. /*
  1144. Note: we don't pass the user config in here yet
  1145. because we only want it executed once, at the lowest
  1146. subclass level.
  1147. */
  1148. Menu.superclass.init.call(this, p_oElement);
  1149. this.beforeInitEvent.fire(Menu);
  1150. YAHOO.log("No source element found. Created element with id: " + this.id, "info", this.toString());
  1151. }
  1152. if (this.element) {
  1153. Dom.addClass(this.element, this.CSS_CLASS_NAME);
  1154. // Subscribe to Custom Events
  1155. this.initEvent.subscribe(this._onInit);
  1156. this.beforeRenderEvent.subscribe(this._onBeforeRender);
  1157. this.renderEvent.subscribe(this._onRender);
  1158. this.beforeShowEvent.subscribe(this._onBeforeShow);
  1159. this.hideEvent.subscribe(this._onHide);
  1160. this.showEvent.subscribe(this._onShow);
  1161. this.beforeHideEvent.subscribe(this._onBeforeHide);
  1162. this.mouseOverEvent.subscribe(this._onMouseOver);
  1163. this.mouseOutEvent.subscribe(this._onMouseOut);
  1164. this.clickEvent.subscribe(this._onClick);
  1165. this.keyDownEvent.subscribe(this._onKeyDown);
  1166. this.keyPressEvent.subscribe(this._onKeyPress);
  1167. this.blurEvent.subscribe(this._onBlur);
  1168. if (!bFocusListenerInitialized) {
  1169. Event.onFocus(document, onDocFocus);
  1170. bFocusListenerInitialized = true;
  1171. }
  1172. // Fixes an issue in Firefox 2 and Webkit where Dom's "getX" and "getY"
  1173. // methods return values that don't take scrollTop into consideration
  1174. if ((UA.gecko && UA.gecko < 1.9) || UA.webkit) {
  1175. this.cfg.subscribeToConfigEvent(_Y, this._onYChange);
  1176. }
  1177. if (p_oConfig) {
  1178. this.cfg.applyConfig(p_oConfig, true);
  1179. }
  1180. // Register the Menu instance with the MenuManager
  1181. MenuManager.addMenu(this);
  1182. this.initEvent.fire(Menu);
  1183. }
  1184. },
  1185. // Private methods
  1186. /**
  1187. * @method _initSubTree
  1188. * @description Iterates the childNodes of the source element to find nodes
  1189. * used to instantiate menu and menu items.
  1190. * @private
  1191. */
  1192. _initSubTree: function () {
  1193. var oSrcElement = this.srcElement,
  1194. sSrcElementTagName,
  1195. nGroup,
  1196. sGroupTitleTagName,
  1197. oNode,
  1198. aListElements,
  1199. nListElements,
  1200. i;
  1201. if (oSrcElement) {
  1202. sSrcElementTagName =
  1203. (oSrcElement.tagName && oSrcElement.tagName.toUpperCase());
  1204. if (sSrcElementTagName == _DIV_UPPERCASE) {
  1205. // Populate the collection of item groups and item group titles
  1206. oNode = this.body.firstChild;
  1207. if (oNode) {
  1208. nGroup = 0;
  1209. sGroupTitleTagName = this.GROUP_TITLE_TAG_NAME.toUpperCase();
  1210. do {
  1211. if (oNode && oNode.tagName) {
  1212. switch (oNode.tagName.toUpperCase()) {
  1213. case sGroupTitleTagName:
  1214. this._aGroupTitleElements[nGroup] = oNode;
  1215. break;
  1216. case _UL_UPPERCASE:
  1217. this._aListElements[nGroup] = oNode;
  1218. this._aItemGroups[nGroup] = [];
  1219. nGroup++;
  1220. break;
  1221. }
  1222. }
  1223. }
  1224. while ((oNode = oNode.nextSibling));
  1225. /*
  1226. Apply the "first-of-type" class to the first UL to mimic
  1227. the ":first-of-type" CSS3 psuedo class.
  1228. */
  1229. if (this._aListElements[0]) {
  1230. Dom.addClass(this._aListElements[0], _FIRST_OF_TYPE);
  1231. }
  1232. }
  1233. }
  1234. oNode = null;
  1235. YAHOO.log("Searching DOM for items to initialize.", "info", this.toString());
  1236. if (sSrcElementTagName) {
  1237. switch (sSrcElementTagName) {
  1238. case _DIV_UPPERCASE:
  1239. aListElements = this._aListElements;
  1240. nListElements = aListElements.length;
  1241. if (nListElements > 0) {
  1242. YAHOO.log("Found " + nListElements + " item groups to initialize.",
  1243. "info", this.toString());
  1244. i = nListElements - 1;
  1245. do {
  1246. oNode = aListElements[i].firstChild;
  1247. if (oNode) {
  1248. YAHOO.log("Scanning " +
  1249. aListElements[i].childNodes.length +
  1250. " child nodes for items to initialize.", "info", this.toString());
  1251. do {
  1252. if (oNode && oNode.tagName &&
  1253. oNode.tagName.toUpperCase() == _LI) {
  1254. YAHOO.log("Initializing " +
  1255. oNode.tagName + " node.", "info", this.toString());
  1256. this.addItem(new this.ITEM_TYPE(oNode,
  1257. { parent: this }), i);
  1258. }
  1259. }
  1260. while ((oNode = oNode.nextSibling));
  1261. }
  1262. }
  1263. while (i--);
  1264. }
  1265. break;
  1266. case _SELECT:
  1267. YAHOO.log("Scanning " +
  1268. oSrcElement.childNodes.length +
  1269. " child nodes for items to initialize.", "info", this.toString());
  1270. oNode = oSrcElement.firstChild;
  1271. do {
  1272. if (oNode && oNode.tagName) {
  1273. switch (oNode.tagName.toUpperCase()) {
  1274. case _OPTGROUP:
  1275. case _OPTION:
  1276. YAHOO.log("Initializing " +
  1277. oNode.tagName + " node.", "info", this.toString());
  1278. this.addItem(
  1279. new this.ITEM_TYPE(
  1280. oNode,
  1281. { parent: this }
  1282. )
  1283. );
  1284. break;
  1285. }
  1286. }
  1287. }
  1288. while ((oNode = oNode.nextSibling));
  1289. break;
  1290. }
  1291. }
  1292. }
  1293. },
  1294. /**
  1295. * @method _getFirstEnabledItem
  1296. * @description Returns the first enabled item in the menu.
  1297. * @return {YAHOO.widget.MenuItem}
  1298. * @private
  1299. */
  1300. _getFirstEnabledItem: function () {
  1301. var aItems = this.getItems(),
  1302. nItems = aItems.length,
  1303. oItem,
  1304. returnVal;
  1305. for(var i=0; i<nItems; i++) {
  1306. oItem = aItems[i];
  1307. if (oItem && !oItem.cfg.getProperty(_DISABLED) && oItem.element.style.display != _NONE) {
  1308. returnVal = oItem;
  1309. break;
  1310. }
  1311. }
  1312. return returnVal;
  1313. },
  1314. /**
  1315. * @method _addItemToGroup
  1316. * @description Adds a menu item to a group.
  1317. * @private
  1318. * @param {Number} p_nGroupIndex Number indicating the group to which the
  1319. * item belongs.
  1320. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  1321. * instance to be added to the menu.
  1322. * @param {String} p_oItem String specifying the text of the item to be added
  1323. * to the menu.
  1324. * @param {Object} p_oItem Object literal containing a set of menu item
  1325. * configuration properties.
  1326. * @param {Number} p_nItemIndex Optional. Number indicating the index at
  1327. * which the menu item should be added.
  1328. * @return {YAHOO.widget.MenuItem}
  1329. */
  1330. _addItemToGroup: function (p_nGroupIndex, p_oItem, p_nItemIndex) {
  1331. var oItem,
  1332. nGroupIndex,
  1333. aGroup,
  1334. oGroupItem,
  1335. bAppend,
  1336. oNextItemSibling,
  1337. nItemIndex,
  1338. returnVal;
  1339. function getNextItemSibling(p_aArray, p_nStartIndex) {
  1340. return (p_aArray[p_nStartIndex] || getNextItemSibling(p_aArray, (p_nStartIndex+1)));
  1341. }
  1342. if (p_oItem instanceof this.ITEM_TYPE) {
  1343. oItem = p_oItem;
  1344. oItem.parent = this;
  1345. }
  1346. else if (Lang.isString(p_oItem)) {
  1347. oItem = new this.ITEM_TYPE(p_oItem, { parent: this });
  1348. }
  1349. else if (Lang.isObject(p_oItem)) {
  1350. p_oItem.parent = this;
  1351. oItem = new this.ITEM_TYPE(p_oItem.text, p_oItem);
  1352. }
  1353. if (oItem) {
  1354. if (oItem.cfg.getProperty(_SELECTED)) {
  1355. this.activeItem = oItem;
  1356. }
  1357. nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
  1358. aGroup = this._getItemGroup(nGroupIndex);
  1359. if (!aGroup) {
  1360. aGroup = this._createItemGroup(nGroupIndex);
  1361. }
  1362. if (Lang.isNumber(p_nItemIndex)) {
  1363. bAppend = (p_nItemIndex >= aGroup.length);
  1364. if (aGroup[p_nItemIndex]) {
  1365. aGroup.splice(p_nItemIndex, 0, oItem);
  1366. }
  1367. else {
  1368. aGroup[p_nItemIndex] = oItem;
  1369. }
  1370. oGroupItem = aGroup[p_nItemIndex];
  1371. if (oGroupItem) {
  1372. if (bAppend && (!oGroupItem.element.parentNode ||
  1373. oGroupItem.element.parentNode.nodeType == 11)) {
  1374. this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
  1375. }
  1376. else {
  1377. oNextItemSibling = getNextItemSibling(aGroup, (p_nItemIndex+1));
  1378. if (oNextItemSibling && (!oGroupItem.element.parentNode ||
  1379. oGroupItem.element.parentNode.nodeType == 11)) {
  1380. this._aListElements[nGroupIndex].insertBefore(
  1381. oGroupItem.element, oNextItemSibling.element);
  1382. }
  1383. }
  1384. oGroupItem.parent = this;
  1385. this._subscribeToItemEvents(oGroupItem);
  1386. this._configureSubmenu(oGroupItem);
  1387. this._updateItemProperties(nGroupIndex);
  1388. YAHOO.log("Item inserted." +
  1389. " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
  1390. " Index: " + oGroupItem.index + ", " +
  1391. " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
  1392. this.itemAddedEvent.fire(oGroupItem);
  1393. this.changeContentEvent.fire();
  1394. returnVal = oGroupItem;
  1395. }
  1396. }
  1397. else {
  1398. nItemIndex = aGroup.length;
  1399. aGroup[nItemIndex] = oItem;
  1400. oGroupItem = aGroup[nItemIndex];
  1401. if (oGroupItem) {
  1402. if (!Dom.isAncestor(this._aListElements[nGroupIndex], oGroupItem.element)) {
  1403. this._aListElements[nGroupIndex].appendChild(oGroupItem.element);
  1404. }
  1405. oGroupItem.element.setAttribute(_GROUP_INDEX, nGroupIndex);
  1406. oGroupItem.element.setAttribute(_INDEX, nItemIndex);
  1407. oGroupItem.parent = this;
  1408. oGroupItem.index = nItemIndex;
  1409. oGroupItem.groupIndex = nGroupIndex;
  1410. this._subscribeToItemEvents(oGroupItem);
  1411. this._configureSubmenu(oGroupItem);
  1412. if (nItemIndex === 0) {
  1413. Dom.addClass(oGroupItem.element, _FIRST_OF_TYPE);
  1414. }
  1415. YAHOO.log("Item added." +
  1416. " Text: " + oGroupItem.cfg.getProperty("text") + ", " +
  1417. " Index: " + oGroupItem.index + ", " +
  1418. " Group Index: " + oGroupItem.groupIndex, "info", this.toString());
  1419. this.itemAddedEvent.fire(oGroupItem);
  1420. this.changeContentEvent.fire();
  1421. returnVal = oGroupItem;
  1422. }
  1423. }
  1424. }
  1425. return returnVal;
  1426. },
  1427. /**
  1428. * @method _removeItemFromGroupByIndex
  1429. * @description Removes a menu item from a group by index. Returns the menu
  1430. * item that was removed.
  1431. * @private
  1432. * @param {Number} p_nGroupIndex Number indicating the group to which the menu
  1433. * item belongs.
  1434. * @param {Number} p_nItemIndex Number indicating the index of the menu item
  1435. * to be removed.
  1436. * @return {YAHOO.widget.MenuItem}
  1437. */
  1438. _removeItemFromGroupByIndex: function (p_nGroupIndex, p_nItemIndex) {
  1439. var nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0,
  1440. aGroup = this._getItemGroup(nGroupIndex),
  1441. aArray,
  1442. oItem,
  1443. oUL;
  1444. if (aGroup) {
  1445. aArray = aGroup.splice(p_nItemIndex, 1);
  1446. oItem = aArray[0];
  1447. if (oItem) {
  1448. // Update the index and className properties of each member
  1449. this._updateItemProperties(nGroupIndex);
  1450. if (aGroup.length === 0) {
  1451. // Remove the UL
  1452. oUL = this._aListElements[nGroupIndex];
  1453. if (this.body && oUL) {
  1454. this.body.removeChild(oUL);
  1455. }
  1456. // Remove the group from the array of items
  1457. this._aItemGroups.splice(nGroupIndex, 1);
  1458. // Remove the UL from the array of ULs
  1459. this._aListElements.splice(nGroupIndex, 1);
  1460. /*
  1461. Assign the "first-of-type" class to the new first UL
  1462. in the collection
  1463. */
  1464. oUL = this._aListElements[0];
  1465. if (oUL) {
  1466. Dom.addClass(oUL, _FIRST_OF_TYPE);
  1467. }
  1468. }
  1469. this.itemRemovedEvent.fire(oItem);
  1470. this.changeContentEvent.fire();
  1471. }
  1472. }
  1473. // Return a reference to the item that was removed
  1474. return oItem;
  1475. },
  1476. /**
  1477. * @method _removeItemFromGroupByValue
  1478. * @description Removes a menu item from a group by reference. Returns the
  1479. * menu item that was removed.
  1480. * @private
  1481. * @param {Number} p_nGroupIndex Number indicating the group to which the
  1482. * menu item belongs.
  1483. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  1484. * instance to be removed.
  1485. * @return {YAHOO.widget.MenuItem}
  1486. */
  1487. _removeItemFromGroupByValue: function (p_nGroupIndex, p_oItem) {
  1488. var aGroup = this._getItemGroup(p_nGroupIndex),
  1489. nItems,
  1490. nItemIndex,
  1491. returnVal,
  1492. i;
  1493. if (aGroup) {
  1494. nItems = aGroup.length;
  1495. nItemIndex = -1;
  1496. if (nItems > 0) {
  1497. i = nItems-1;
  1498. do {
  1499. if (aGroup[i] == p_oItem) {
  1500. nItemIndex = i;
  1501. break;
  1502. }
  1503. }
  1504. while (i--);
  1505. if (nItemIndex > -1) {
  1506. returnVal = this._removeItemFromGroupByIndex(p_nGroupIndex, nItemIndex);
  1507. }
  1508. }
  1509. }
  1510. return returnVal;
  1511. },
  1512. /**
  1513. * @method _updateItemProperties
  1514. * @description Updates the "index," "groupindex," and "className" properties
  1515. * of the menu items in the specified group.
  1516. * @private
  1517. * @param {Number} p_nGroupIndex Number indicating the group of items to update.
  1518. */
  1519. _updateItemProperties: function (p_nGroupIndex) {
  1520. var aGroup = this._getItemGroup(p_nGroupIndex),
  1521. nItems = aGroup.length,
  1522. oItem,
  1523. oLI,
  1524. i;
  1525. if (nItems > 0) {
  1526. i = nItems - 1;
  1527. // Update the index and className properties of each member
  1528. do {
  1529. oItem = aGroup[i];
  1530. if (oItem) {
  1531. oLI = oItem.element;
  1532. oItem.index = i;
  1533. oItem.groupIndex = p_nGroupIndex;
  1534. oLI.setAttribute(_GROUP_INDEX, p_nGroupIndex);
  1535. oLI.setAttribute(_INDEX, i);
  1536. Dom.removeClass(oLI, _FIRST_OF_TYPE);
  1537. }
  1538. }
  1539. while (i--);
  1540. if (oLI) {
  1541. Dom.addClass(oLI, _FIRST_OF_TYPE);
  1542. }
  1543. }
  1544. },
  1545. /**
  1546. * @method _createItemGroup
  1547. * @description Creates a new menu item group (array) and its associated
  1548. * <code>&#60;ul&#62;</code> element. Returns an aray of menu item groups.
  1549. * @private
  1550. * @param {Number} p_nIndex Number indicating the group to create.
  1551. * @return {Array}
  1552. */
  1553. _createItemGroup: function (p_nIndex) {
  1554. var oUL,
  1555. returnVal;
  1556. if (!this._aItemGroups[p_nIndex]) {
  1557. this._aItemGroups[p_nIndex] = [];
  1558. oUL = document.createElement(_UL_LOWERCASE);
  1559. this._aListElements[p_nIndex] = oUL;
  1560. returnVal = this._aItemGroups[p_nIndex];
  1561. }
  1562. return returnVal;
  1563. },
  1564. /**
  1565. * @method _getItemGroup
  1566. * @description Returns the menu item group at the specified index.
  1567. * @private
  1568. * @param {Number} p_nIndex Number indicating the index of the menu item group
  1569. * to be retrieved.
  1570. * @return {Array}
  1571. */
  1572. _getItemGroup: function (p_nIndex) {
  1573. var nIndex = Lang.isNumber(p_nIndex) ? p_nIndex : 0,
  1574. aGroups = this._aItemGroups,
  1575. returnVal;
  1576. if (nIndex in aGroups) {
  1577. returnVal = aGroups[nIndex];
  1578. }
  1579. return returnVal;
  1580. },
  1581. /**
  1582. * @method _configureSubmenu
  1583. * @description Subscribes the menu item's submenu to its parent menu's events.
  1584. * @private
  1585. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  1586. * instance with the submenu to be configured.
  1587. */
  1588. _configureSubmenu: function (p_oItem) {
  1589. var oSubmenu = p_oItem.cfg.getProperty(_SUBMENU);
  1590. if (oSubmenu) {
  1591. /*
  1592. Listen for configuration changes to the parent menu
  1593. so they they can be applied to the submenu.
  1594. */
  1595. this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange, oSubmenu, true);
  1596. this.renderEvent.subscribe(this._onParentMenuRender, oSubmenu, true);
  1597. }
  1598. },
  1599. /**
  1600. * @method _subscribeToItemEvents
  1601. * @description Subscribes a menu to a menu item's event.
  1602. * @private
  1603. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  1604. * instance whose events should be subscribed to.
  1605. */
  1606. _subscribeToItemEvents: function (p_oItem) {
  1607. p_oItem.destroyEvent.subscribe(this._onMenuItemDestroy, p_oItem, this);
  1608. p_oItem.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange, p_oItem, this);
  1609. },
  1610. /**
  1611. * @method _onVisibleChange
  1612. * @description Change event handler for the the menu's "visible" configuration
  1613. * property.
  1614. * @private
  1615. * @param {String} p_sType String representing the name of the event that
  1616. * was fired.
  1617. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  1618. */
  1619. _onVisibleChange: function (p_sType, p_aArgs) {
  1620. var bVisible = p_aArgs[0];
  1621. if (bVisible) {
  1622. Dom.addClass(this.element, _VISIBLE);
  1623. }
  1624. else {
  1625. Dom.removeClass(this.element, _VISIBLE);
  1626. }
  1627. },
  1628. /**
  1629. * @method _cancelHideDelay
  1630. * @description Cancels the call to "hideMenu."
  1631. * @private
  1632. */
  1633. _cancelHideDelay: function () {
  1634. var oTimer = this.getRoot()._hideDelayTimer;
  1635. if (oTimer) {
  1636. oTimer.cancel();
  1637. }
  1638. },
  1639. /**
  1640. * @method _execHideDelay
  1641. * @description Hides the menu after the number of milliseconds specified by
  1642. * the "hidedelay" configuration property.
  1643. * @private
  1644. */
  1645. _execHideDelay: function () {
  1646. this._cancelHideDelay();
  1647. var oRoot = this.getRoot();
  1648. oRoot._hideDelayTimer = Lang.later(oRoot.cfg.getProperty(_HIDE_DELAY), this, function () {
  1649. if (oRoot.activeItem) {
  1650. if (oRoot.hasFocus()) {
  1651. oRoot.activeItem.focus();
  1652. }
  1653. oRoot.clearActiveItem();
  1654. }
  1655. if (oRoot == this && !(this instanceof YAHOO.widget.MenuBar) &&
  1656. this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  1657. this.hide();
  1658. }
  1659. });
  1660. },
  1661. /**
  1662. * @method _cancelShowDelay
  1663. * @description Cancels the call to the "showMenu."
  1664. * @private
  1665. */
  1666. _cancelShowDelay: function () {
  1667. var oTimer = this.getRoot()._showDelayTimer;
  1668. if (oTimer) {
  1669. oTimer.cancel();
  1670. }
  1671. },
  1672. /**
  1673. * @method _execSubmenuHideDelay
  1674. * @description Hides a submenu after the number of milliseconds specified by
  1675. * the "submenuhidedelay" configuration property have ellapsed.
  1676. * @private
  1677. * @param {YAHOO.widget.Menu} p_oSubmenu Object specifying the submenu that
  1678. * should be hidden.
  1679. * @param {Number} p_nMouseX The x coordinate of the mouse when it left
  1680. * the specified submenu's parent menu item.
  1681. * @param {Number} p_nHideDelay The number of milliseconds that should ellapse
  1682. * before the submenu is hidden.
  1683. */
  1684. _execSubmenuHideDelay: function (p_oSubmenu, p_nMouseX, p_nHideDelay) {
  1685. p_oSubmenu._submenuHideDelayTimer = Lang.later(50, this, function () {
  1686. if (this._nCurrentMouseX > (p_nMouseX + 10)) {
  1687. p_oSubmenu._submenuHideDelayTimer = Lang.later(p_nHideDelay, p_oSubmenu, function () {
  1688. this.hide();
  1689. });
  1690. }
  1691. else {
  1692. p_oSubmenu.hide();
  1693. }
  1694. });
  1695. },
  1696. // Protected methods
  1697. /**
  1698. * @method _disableScrollHeader
  1699. * @description Disables the header used for scrolling the body of the menu.
  1700. * @protected
  1701. */
  1702. _disableScrollHeader: function () {
  1703. if (!this._bHeaderDisabled) {
  1704. Dom.addClass(this.header, _TOP_SCROLLBAR_DISABLED);
  1705. this._bHeaderDisabled = true;
  1706. }
  1707. },
  1708. /**
  1709. * @method _disableScrollFooter
  1710. * @description Disables the footer used for scrolling the body of the menu.
  1711. * @protected
  1712. */
  1713. _disableScrollFooter: function () {
  1714. if (!this._bFooterDisabled) {
  1715. Dom.addClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
  1716. this._bFooterDisabled = true;
  1717. }
  1718. },
  1719. /**
  1720. * @method _enableScrollHeader
  1721. * @description Enables the header used for scrolling the body of the menu.
  1722. * @protected
  1723. */
  1724. _enableScrollHeader: function () {
  1725. if (this._bHeaderDisabled) {
  1726. Dom.removeClass(this.header, _TOP_SCROLLBAR_DISABLED);
  1727. this._bHeaderDisabled = false;
  1728. }
  1729. },
  1730. /**
  1731. * @method _enableScrollFooter
  1732. * @description Enables the footer used for scrolling the body of the menu.
  1733. * @protected
  1734. */
  1735. _enableScrollFooter: function () {
  1736. if (this._bFooterDisabled) {
  1737. Dom.removeClass(this.footer, _BOTTOM_SCROLLBAR_DISABLED);
  1738. this._bFooterDisabled = false;
  1739. }
  1740. },
  1741. /**
  1742. * @method _onMouseOver
  1743. * @description "mouseover" event handler for the menu.
  1744. * @protected
  1745. * @param {String} p_sType String representing the name of the event that
  1746. * was fired.
  1747. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  1748. */
  1749. _onMouseOver: function (p_sType, p_aArgs) {
  1750. var oEvent = p_aArgs[0],
  1751. oItem = p_aArgs[1],
  1752. oTarget = Event.getTarget(oEvent),
  1753. oRoot = this.getRoot(),
  1754. oSubmenuHideDelayTimer = this._submenuHideDelayTimer,
  1755. oParentMenu,
  1756. nShowDelay,
  1757. bShowDelay,
  1758. oActiveItem,
  1759. oItemCfg,
  1760. oSubmenu;
  1761. var showSubmenu = function () {
  1762. if (this.parent.cfg.getProperty(_SELECTED)) {
  1763. this.show();
  1764. }
  1765. };
  1766. if (!this._bStopMouseEventHandlers) {
  1767. if (!this._bHandledMouseOverEvent && (oTarget == this.element ||
  1768. Dom.isAncestor(this.element, oTarget))) {
  1769. // Menu mouseover logic
  1770. if (this._useHideDelay) {
  1771. this._cancelHideDelay();
  1772. }
  1773. this._nCurrentMouseX = 0;
  1774. Event.on(this.element, _MOUSEMOVE, this._onMouseMove, this, true);
  1775. /*
  1776. If the mouse is moving from the submenu back to its corresponding menu item,
  1777. don't hide the submenu or clear the active MenuItem.
  1778. */
  1779. if (!(oItem && Dom.isAncestor(oItem.element, Event.getRelatedTarget(oEvent)))) {
  1780. this.clearActiveItem();
  1781. }
  1782. if (this.parent && oSubmenuHideDelayTimer) {
  1783. oSubmenuHideDelayTimer.cancel();
  1784. this.parent.cfg.setProperty(_SELECTED, true);
  1785. oParentMenu = this.parent.parent;
  1786. oParentMenu._bHandledMouseOutEvent = true;
  1787. oParentMenu._bHandledMouseOverEvent = false;
  1788. }
  1789. this._bHandledMouseOverEvent = true;
  1790. this._bHandledMouseOutEvent = false;
  1791. }
  1792. if (oItem && !oItem.handledMouseOverEvent && !oItem.cfg.getProperty(_DISABLED) &&
  1793. (oTarget == oItem.element || Dom.isAncestor(oItem.element, oTarget))) {
  1794. // Menu Item mouseover logic
  1795. nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
  1796. bShowDelay = (nShowDelay > 0);
  1797. if (bShowDelay) {
  1798. this._cancelShowDelay();
  1799. }
  1800. oActiveItem = this.activeItem;
  1801. if (oActiveItem) {
  1802. oActiveItem.cfg.setProperty(_SELECTED, false);
  1803. }
  1804. oItemCfg = oItem.cfg;
  1805. // Select and focus the current menu item
  1806. oItemCfg.setProperty(_SELECTED, true);
  1807. if (this.hasFocus() || oRoot._hasFocus) {
  1808. oItem.focus();
  1809. oRoot._hasFocus = false;
  1810. }
  1811. if (this.cfg.getProperty(_AUTO_SUBMENU_DISPLAY)) {
  1812. // Show the submenu this menu item
  1813. oSubmenu = oItemCfg.getProperty(_SUBMENU);
  1814. if (oSubmenu) {
  1815. if (bShowDelay) {
  1816. oRoot._showDelayTimer =
  1817. Lang.later(oRoot.cfg.getProperty(_SHOW_DELAY), oSubmenu, showSubmenu);
  1818. }
  1819. else {
  1820. oSubmenu.show();
  1821. }
  1822. }
  1823. }
  1824. oItem.handledMouseOverEvent = true;
  1825. oItem.handledMouseOutEvent = false;
  1826. }
  1827. }
  1828. },
  1829. /**
  1830. * @method _onMouseOut
  1831. * @description "mouseout" event handler for the menu.
  1832. * @protected
  1833. * @param {String} p_sType String representing the name of the event that
  1834. * was fired.
  1835. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  1836. */
  1837. _onMouseOut: function (p_sType, p_aArgs) {
  1838. var oEvent = p_aArgs[0],
  1839. oItem = p_aArgs[1],
  1840. oRelatedTarget = Event.getRelatedTarget(oEvent),
  1841. bMovingToSubmenu = false,
  1842. oItemCfg,
  1843. oSubmenu,
  1844. nSubmenuHideDelay,
  1845. nShowDelay;
  1846. if (!this._bStopMouseEventHandlers) {
  1847. if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
  1848. oItemCfg = oItem.cfg;
  1849. oSubmenu = oItemCfg.getProperty(_SUBMENU);
  1850. if (oSubmenu && (oRelatedTarget == oSubmenu.element ||
  1851. Dom.isAncestor(oSubmenu.element, oRelatedTarget))) {
  1852. bMovingToSubmenu = true;
  1853. }
  1854. if (!oItem.handledMouseOutEvent && ((oRelatedTarget != oItem.element &&
  1855. !Dom.isAncestor(oItem.element, oRelatedTarget)) || bMovingToSubmenu)) {
  1856. // Menu Item mouseout logic
  1857. if (!bMovingToSubmenu) {
  1858. oItem.cfg.setProperty(_SELECTED, false);
  1859. if (oSubmenu) {
  1860. nSubmenuHideDelay = this.cfg.getProperty(_SUBMENU_HIDE_DELAY);
  1861. nShowDelay = this.cfg.getProperty(_SHOW_DELAY);
  1862. if (!(this instanceof YAHOO.widget.MenuBar) && nSubmenuHideDelay > 0 &&
  1863. nShowDelay >= nSubmenuHideDelay) {
  1864. this._execSubmenuHideDelay(oSubmenu, Event.getPageX(oEvent),
  1865. nSubmenuHideDelay);
  1866. }
  1867. else {
  1868. oSubmenu.hide();
  1869. }
  1870. }
  1871. }
  1872. oItem.handledMouseOutEvent = true;
  1873. oItem.handledMouseOverEvent = false;
  1874. }
  1875. }
  1876. if (!this._bHandledMouseOutEvent && ((oRelatedTarget != this.element &&
  1877. !Dom.isAncestor(this.element, oRelatedTarget)) || bMovingToSubmenu)) {
  1878. // Menu mouseout logic
  1879. if (this._useHideDelay) {
  1880. this._execHideDelay();
  1881. }
  1882. Event.removeListener(this.element, _MOUSEMOVE, this._onMouseMove);
  1883. this._nCurrentMouseX = Event.getPageX(oEvent);
  1884. this._bHandledMouseOutEvent = true;
  1885. this._bHandledMouseOverEvent = false;
  1886. }
  1887. }
  1888. },
  1889. /**
  1890. * @method _onMouseMove
  1891. * @description "click" event handler for the menu.
  1892. * @protected
  1893. * @param {Event} p_oEvent Object representing the DOM event object passed
  1894. * back by the event utility (YAHOO.util.Event).
  1895. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  1896. * fired the event.
  1897. */
  1898. _onMouseMove: function (p_oEvent, p_oMenu) {
  1899. if (!this._bStopMouseEventHandlers) {
  1900. this._nCurrentMouseX = Event.getPageX(p_oEvent);
  1901. }
  1902. },
  1903. /**
  1904. * @method _onClick
  1905. * @description "click" event handler for the menu.
  1906. * @protected
  1907. * @param {String} p_sType String representing the name of the event that
  1908. * was fired.
  1909. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  1910. */
  1911. _onClick: function (p_sType, p_aArgs) {
  1912. var oEvent = p_aArgs[0],
  1913. oItem = p_aArgs[1],
  1914. bInMenuAnchor = false,
  1915. oSubmenu,
  1916. oMenu,
  1917. oRoot,
  1918. sId,
  1919. sURL,
  1920. nHashPos,
  1921. nLen;
  1922. var hide = function () {
  1923. oRoot = this.getRoot();
  1924. if (oRoot instanceof YAHOO.widget.MenuBar ||
  1925. oRoot.cfg.getProperty(_POSITION) == _STATIC) {
  1926. oRoot.clearActiveItem();
  1927. }
  1928. else {
  1929. oRoot.hide();
  1930. }
  1931. };
  1932. if (oItem) {
  1933. if (oItem.cfg.getProperty(_DISABLED)) {
  1934. Event.preventDefault(oEvent);
  1935. hide.call(this);
  1936. }
  1937. else {
  1938. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  1939. /*
  1940. Check if the URL of the anchor is pointing to an element that is
  1941. a child of the menu.
  1942. */
  1943. sURL = oItem.cfg.getProperty(_URL);
  1944. if (sURL) {
  1945. nHashPos = sURL.indexOf(_HASH);
  1946. nLen = sURL.length;
  1947. if (nHashPos != -1) {
  1948. sURL = sURL.substr(nHashPos, nLen);
  1949. nLen = sURL.length;
  1950. if (nLen > 1) {
  1951. sId = sURL.substr(1, nLen);
  1952. oMenu = YAHOO.widget.MenuManager.getMenu(sId);
  1953. if (oMenu) {
  1954. bInMenuAnchor =
  1955. (this.getRoot() === oMenu.getRoot());
  1956. }
  1957. }
  1958. else if (nLen === 1) {
  1959. bInMenuAnchor = true;
  1960. }
  1961. }
  1962. }
  1963. if (bInMenuAnchor && !oItem.cfg.getProperty(_TARGET)) {
  1964. Event.preventDefault(oEvent);
  1965. if (UA.webkit) {
  1966. oItem.focus();
  1967. }
  1968. else {
  1969. oItem.focusEvent.fire();
  1970. }
  1971. }
  1972. if (!oSubmenu && !this.cfg.getProperty(_KEEP_OPEN)) {
  1973. hide.call(this);
  1974. }
  1975. }
  1976. }
  1977. },
  1978. /**
  1979. * @method _onKeyDown
  1980. * @description "keydown" event handler for the menu.
  1981. * @protected
  1982. * @param {String} p_sType String representing the name of the event that
  1983. * was fired.
  1984. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  1985. */
  1986. _onKeyDown: function (p_sType, p_aArgs) {
  1987. var oEvent = p_aArgs[0],
  1988. oItem = p_aArgs[1],
  1989. oSubmenu,
  1990. oItemCfg,
  1991. oParentItem,
  1992. oRoot,
  1993. oNextItem,
  1994. oBody,
  1995. nBodyScrollTop,
  1996. nBodyOffsetHeight,
  1997. aItems,
  1998. nItems,
  1999. nNextItemOffsetTop,
  2000. nScrollTarget,
  2001. oParentMenu,
  2002. oFocusedEl;
  2003. if (this._useHideDelay) {
  2004. this._cancelHideDelay();
  2005. }
  2006. /*
  2007. This function is called to prevent a bug in Firefox. In Firefox,
  2008. moving a DOM element into a stationary mouse pointer will cause the
  2009. browser to fire mouse events. This can result in the menu mouse
  2010. event handlers being called uncessarily, especially when menus are
  2011. moved into a stationary mouse pointer as a result of a
  2012. key event handler.
  2013. */
  2014. function stopMouseEventHandlers() {
  2015. this._bStopMouseEventHandlers = true;
  2016. Lang.later(10, this, function () {
  2017. this._bStopMouseEventHandlers = false;
  2018. });
  2019. }
  2020. if (oItem && !oItem.cfg.getProperty(_DISABLED)) {
  2021. oItemCfg = oItem.cfg;
  2022. oParentItem = this.parent;
  2023. switch(oEvent.keyCode) {
  2024. case 38: // Up arrow
  2025. case 40: // Down arrow
  2026. oNextItem = (oEvent.keyCode == 38) ?
  2027. oItem.getPreviousEnabledSibling() :
  2028. oItem.getNextEnabledSibling();
  2029. if (oNextItem) {
  2030. this.clearActiveItem();
  2031. oNextItem.cfg.setProperty(_SELECTED, true);
  2032. oNextItem.focus();
  2033. if (this.cfg.getProperty(_MAX_HEIGHT) > 0) {
  2034. oBody = this.body;
  2035. nBodyScrollTop = oBody.scrollTop;
  2036. nBodyOffsetHeight = oBody.offsetHeight;
  2037. aItems = this.getItems();
  2038. nItems = aItems.length - 1;
  2039. nNextItemOffsetTop = oNextItem.element.offsetTop;
  2040. if (oEvent.keyCode == 40 ) { // Down
  2041. if (nNextItemOffsetTop >= (nBodyOffsetHeight + nBodyScrollTop)) {
  2042. oBody.scrollTop = nNextItemOffsetTop - nBodyOffsetHeight;
  2043. }
  2044. else if (nNextItemOffsetTop <= nBodyScrollTop) {
  2045. oBody.scrollTop = 0;
  2046. }
  2047. if (oNextItem == aItems[nItems]) {
  2048. oBody.scrollTop = oNextItem.element.offsetTop;
  2049. }
  2050. }
  2051. else { // Up
  2052. if (nNextItemOffsetTop <= nBodyScrollTop) {
  2053. oBody.scrollTop = nNextItemOffsetTop - oNextItem.element.offsetHeight;
  2054. }
  2055. else if (nNextItemOffsetTop >= (nBodyScrollTop + nBodyOffsetHeight)) {
  2056. oBody.scrollTop = nNextItemOffsetTop;
  2057. }
  2058. if (oNextItem == aItems[0]) {
  2059. oBody.scrollTop = 0;
  2060. }
  2061. }
  2062. nBodyScrollTop = oBody.scrollTop;
  2063. nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
  2064. if (nBodyScrollTop === 0) {
  2065. this._disableScrollHeader();
  2066. this._enableScrollFooter();
  2067. }
  2068. else if (nBodyScrollTop == nScrollTarget) {
  2069. this._enableScrollHeader();
  2070. this._disableScrollFooter();
  2071. }
  2072. else {
  2073. this._enableScrollHeader();
  2074. this._enableScrollFooter();
  2075. }
  2076. }
  2077. }
  2078. Event.preventDefault(oEvent);
  2079. stopMouseEventHandlers();
  2080. break;
  2081. case 39: // Right arrow
  2082. oSubmenu = oItemCfg.getProperty(_SUBMENU);
  2083. if (oSubmenu) {
  2084. if (!oItemCfg.getProperty(_SELECTED)) {
  2085. oItemCfg.setProperty(_SELECTED, true);
  2086. }
  2087. oSubmenu.show();
  2088. oSubmenu.setInitialFocus();
  2089. oSubmenu.setInitialSelection();
  2090. }
  2091. else {
  2092. oRoot = this.getRoot();
  2093. if (oRoot instanceof YAHOO.widget.MenuBar) {
  2094. oNextItem = oRoot.activeItem.getNextEnabledSibling();
  2095. if (oNextItem) {
  2096. oRoot.clearActiveItem();
  2097. oNextItem.cfg.setProperty(_SELECTED, true);
  2098. oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
  2099. if (oSubmenu) {
  2100. oSubmenu.show();
  2101. oSubmenu.setInitialFocus();
  2102. }
  2103. else {
  2104. oNextItem.focus();
  2105. }
  2106. }
  2107. }
  2108. }
  2109. Event.preventDefault(oEvent);
  2110. stopMouseEventHandlers();
  2111. break;
  2112. case 37: // Left arrow
  2113. if (oParentItem) {
  2114. oParentMenu = oParentItem.parent;
  2115. if (oParentMenu instanceof YAHOO.widget.MenuBar) {
  2116. oNextItem =
  2117. oParentMenu.activeItem.getPreviousEnabledSibling();
  2118. if (oNextItem) {
  2119. oParentMenu.clearActiveItem();
  2120. oNextItem.cfg.setProperty(_SELECTED, true);
  2121. oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
  2122. if (oSubmenu) {
  2123. oSubmenu.show();
  2124. oSubmenu.setInitialFocus();
  2125. }
  2126. else {
  2127. oNextItem.focus();
  2128. }
  2129. }
  2130. }
  2131. else {
  2132. this.hide();
  2133. oParentItem.focus();
  2134. }
  2135. }
  2136. Event.preventDefault(oEvent);
  2137. stopMouseEventHandlers();
  2138. break;
  2139. }
  2140. }
  2141. if (oEvent.keyCode == 27) { // Esc key
  2142. if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  2143. this.hide();
  2144. if (this.parent) {
  2145. this.parent.focus();
  2146. }
  2147. else {
  2148. // Focus the element that previously had focus
  2149. oFocusedEl = this._focusedElement;
  2150. if (oFocusedEl && oFocusedEl.focus) {
  2151. try {
  2152. oFocusedEl.focus();
  2153. }
  2154. catch(ex) {
  2155. }
  2156. }
  2157. }
  2158. }
  2159. else if (this.activeItem) {
  2160. oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
  2161. if (oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
  2162. oSubmenu.hide();
  2163. this.activeItem.focus();
  2164. }
  2165. else {
  2166. this.activeItem.blur();
  2167. this.activeItem.cfg.setProperty(_SELECTED, false);
  2168. }
  2169. }
  2170. Event.preventDefault(oEvent);
  2171. }
  2172. },
  2173. /**
  2174. * @method _onKeyPress
  2175. * @description "keypress" event handler for a Menu instance.
  2176. * @protected
  2177. * @param {String} p_sType The name of the event that was fired.
  2178. * @param {Array} p_aArgs Collection of arguments sent when the event
  2179. * was fired.
  2180. */
  2181. _onKeyPress: function (p_sType, p_aArgs) {
  2182. var oEvent = p_aArgs[0];
  2183. if (oEvent.keyCode == 40 || oEvent.keyCode == 38) {
  2184. Event.preventDefault(oEvent);
  2185. }
  2186. },
  2187. /**
  2188. * @method _onBlur
  2189. * @description "blur" event handler for a Menu instance.
  2190. * @protected
  2191. * @param {String} p_sType The name of the event that was fired.
  2192. * @param {Array} p_aArgs Collection of arguments sent when the event
  2193. * was fired.
  2194. */
  2195. _onBlur: function (p_sType, p_aArgs) {
  2196. if (this._hasFocus) {
  2197. this._hasFocus = false;
  2198. }
  2199. },
  2200. /**
  2201. * @method _onYChange
  2202. * @description "y" event handler for a Menu instance.
  2203. * @protected
  2204. * @param {String} p_sType The name of the event that was fired.
  2205. * @param {Array} p_aArgs Collection of arguments sent when the event
  2206. * was fired.
  2207. */
  2208. _onYChange: function (p_sType, p_aArgs) {
  2209. var oParent = this.parent,
  2210. nScrollTop,
  2211. oIFrame,
  2212. nY;
  2213. if (oParent) {
  2214. nScrollTop = oParent.parent.body.scrollTop;
  2215. if (nScrollTop > 0) {
  2216. nY = (this.cfg.getProperty(_Y) - nScrollTop);
  2217. Dom.setY(this.element, nY);
  2218. oIFrame = this.iframe;
  2219. if (oIFrame) {
  2220. Dom.setY(oIFrame, nY);
  2221. }
  2222. this.cfg.setProperty(_Y, nY, true);
  2223. }
  2224. }
  2225. },
  2226. /**
  2227. * @method _onScrollTargetMouseOver
  2228. * @description "mouseover" event handler for the menu's "header" and "footer"
  2229. * elements. Used to scroll the body of the menu up and down when the
  2230. * menu's "maxheight" configuration property is set to a value greater than 0.
  2231. * @protected
  2232. * @param {Event} p_oEvent Object representing the DOM event object passed
  2233. * back by the event utility (YAHOO.util.Event).
  2234. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2235. * fired the event.
  2236. */
  2237. _onScrollTargetMouseOver: function (p_oEvent, p_oMenu) {
  2238. var oBodyScrollTimer = this._bodyScrollTimer;
  2239. if (oBodyScrollTimer) {
  2240. oBodyScrollTimer.cancel();
  2241. }
  2242. this._cancelHideDelay();
  2243. var oTarget = Event.getTarget(p_oEvent),
  2244. oBody = this.body,
  2245. nScrollIncrement = this.cfg.getProperty(_SCROLL_INCREMENT),
  2246. nScrollTarget,
  2247. fnScrollFunction;
  2248. function scrollBodyDown() {
  2249. var nScrollTop = oBody.scrollTop;
  2250. if (nScrollTop < nScrollTarget) {
  2251. oBody.scrollTop = (nScrollTop + nScrollIncrement);
  2252. this._enableScrollHeader();
  2253. }
  2254. else {
  2255. oBody.scrollTop = nScrollTarget;
  2256. this._bodyScrollTimer.cancel();
  2257. this._disableScrollFooter();
  2258. }
  2259. }
  2260. function scrollBodyUp() {
  2261. var nScrollTop = oBody.scrollTop;
  2262. if (nScrollTop > 0) {
  2263. oBody.scrollTop = (nScrollTop - nScrollIncrement);
  2264. this._enableScrollFooter();
  2265. }
  2266. else {
  2267. oBody.scrollTop = 0;
  2268. this._bodyScrollTimer.cancel();
  2269. this._disableScrollHeader();
  2270. }
  2271. }
  2272. if (Dom.hasClass(oTarget, _HD)) {
  2273. fnScrollFunction = scrollBodyUp;
  2274. }
  2275. else {
  2276. nScrollTarget = oBody.scrollHeight - oBody.offsetHeight;
  2277. fnScrollFunction = scrollBodyDown;
  2278. }
  2279. this._bodyScrollTimer = Lang.later(10, this, fnScrollFunction, null, true);
  2280. },
  2281. /**
  2282. * @method _onScrollTargetMouseOut
  2283. * @description "mouseout" event handler for the menu's "header" and "footer"
  2284. * elements. Used to stop scrolling the body of the menu up and down when the
  2285. * menu's "maxheight" configuration property is set to a value greater than 0.
  2286. * @protected
  2287. * @param {Event} p_oEvent Object representing the DOM event object passed
  2288. * back by the event utility (YAHOO.util.Event).
  2289. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2290. * fired the event.
  2291. */
  2292. _onScrollTargetMouseOut: function (p_oEvent, p_oMenu) {
  2293. var oBodyScrollTimer = this._bodyScrollTimer;
  2294. if (oBodyScrollTimer) {
  2295. oBodyScrollTimer.cancel();
  2296. }
  2297. this._cancelHideDelay();
  2298. },
  2299. // Private methods
  2300. /**
  2301. * @method _onInit
  2302. * @description "init" event handler for the menu.
  2303. * @private
  2304. * @param {String} p_sType String representing the name of the event that
  2305. * was fired.
  2306. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2307. */
  2308. _onInit: function (p_sType, p_aArgs) {
  2309. this.cfg.subscribeToConfigEvent(_VISIBLE, this._onVisibleChange);
  2310. var bRootMenu = !this.parent,
  2311. bLazyLoad = this.lazyLoad;
  2312. /*
  2313. Automatically initialize a menu's subtree if:
  2314. 1) This is the root menu and lazyload is off
  2315. 2) This is the root menu, lazyload is on, but the menu is
  2316. already visible
  2317. 3) This menu is a submenu and lazyload is off
  2318. */
  2319. if (((bRootMenu && !bLazyLoad) ||
  2320. (bRootMenu && (this.cfg.getProperty(_VISIBLE) ||
  2321. this.cfg.getProperty(_POSITION) == _STATIC)) ||
  2322. (!bRootMenu && !bLazyLoad)) && this.getItemGroups().length === 0) {
  2323. if (this.srcElement) {
  2324. this._initSubTree();
  2325. }
  2326. if (this.itemData) {
  2327. this.addItems(this.itemData);
  2328. }
  2329. }
  2330. else if (bLazyLoad) {
  2331. this.cfg.fireQueue();
  2332. }
  2333. },
  2334. /**
  2335. * @method _onBeforeRender
  2336. * @description "beforerender" event handler for the menu. Appends all of the
  2337. * <code>&#60;ul&#62;</code>, <code>&#60;li&#62;</code> and their accompanying
  2338. * title elements to the body element of the menu.
  2339. * @private
  2340. * @param {String} p_sType String representing the name of the event that
  2341. * was fired.
  2342. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2343. */
  2344. _onBeforeRender: function (p_sType, p_aArgs) {
  2345. var oEl = this.element,
  2346. nListElements = this._aListElements.length,
  2347. bFirstList = true,
  2348. i = 0,
  2349. oUL,
  2350. oGroupTitle;
  2351. if (nListElements > 0) {
  2352. do {
  2353. oUL = this._aListElements[i];
  2354. if (oUL) {
  2355. if (bFirstList) {
  2356. Dom.addClass(oUL, _FIRST_OF_TYPE);
  2357. bFirstList = false;
  2358. }
  2359. if (!Dom.isAncestor(oEl, oUL)) {
  2360. this.appendToBody(oUL);
  2361. }
  2362. oGroupTitle = this._aGroupTitleElements[i];
  2363. if (oGroupTitle) {
  2364. if (!Dom.isAncestor(oEl, oGroupTitle)) {
  2365. oUL.parentNode.insertBefore(oGroupTitle, oUL);
  2366. }
  2367. Dom.addClass(oUL, _HAS_TITLE);
  2368. }
  2369. }
  2370. i++;
  2371. }
  2372. while (i < nListElements);
  2373. }
  2374. },
  2375. /**
  2376. * @method _onRender
  2377. * @description "render" event handler for the menu.
  2378. * @private
  2379. * @param {String} p_sType String representing the name of the event that
  2380. * was fired.
  2381. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2382. */
  2383. _onRender: function (p_sType, p_aArgs) {
  2384. if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  2385. if (!this.cfg.getProperty(_VISIBLE)) {
  2386. this.positionOffScreen();
  2387. }
  2388. }
  2389. },
  2390. /**
  2391. * @method _onBeforeShow
  2392. * @description "beforeshow" event handler for the menu.
  2393. * @private
  2394. * @param {String} p_sType String representing the name of the event that
  2395. * was fired.
  2396. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2397. */
  2398. _onBeforeShow: function (p_sType, p_aArgs) {
  2399. var nOptions,
  2400. n,
  2401. oSrcElement,
  2402. oContainer = this.cfg.getProperty(_CONTAINER);
  2403. if (this.lazyLoad && this.getItemGroups().length === 0) {
  2404. if (this.srcElement) {
  2405. this._initSubTree();
  2406. }
  2407. if (this.itemData) {
  2408. if (this.parent && this.parent.parent &&
  2409. this.parent.parent.srcElement &&
  2410. this.parent.parent.srcElement.tagName.toUpperCase() ==
  2411. _SELECT) {
  2412. nOptions = this.itemData.length;
  2413. for(n=0; n<nOptions; n++) {
  2414. if (this.itemData[n].tagName) {
  2415. this.addItem((new this.ITEM_TYPE(this.itemData[n])));
  2416. }
  2417. }
  2418. }
  2419. else {
  2420. this.addItems(this.itemData);
  2421. }
  2422. }
  2423. oSrcElement = this.srcElement;
  2424. if (oSrcElement) {
  2425. if (oSrcElement.tagName.toUpperCase() == _SELECT) {
  2426. if (Dom.inDocument(oSrcElement)) {
  2427. this.render(oSrcElement.parentNode);
  2428. }
  2429. else {
  2430. this.render(oContainer);
  2431. }
  2432. }
  2433. else {
  2434. this.render();
  2435. }
  2436. }
  2437. else {
  2438. if (this.parent) {
  2439. this.render(this.parent.element);
  2440. }
  2441. else {
  2442. this.render(oContainer);
  2443. }
  2444. }
  2445. }
  2446. var oParent = this.parent,
  2447. aAlignment;
  2448. if (!oParent && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  2449. this.cfg.refireEvent(_XY);
  2450. }
  2451. if (oParent) {
  2452. aAlignment = oParent.parent.cfg.getProperty(_SUBMENU_ALIGNMENT);
  2453. this.cfg.setProperty(_CONTEXT, [oParent.element, aAlignment[0], aAlignment[1]]);
  2454. this.align();
  2455. }
  2456. },
  2457. getConstrainedY: function (y) {
  2458. var oMenu = this,
  2459. aContext = oMenu.cfg.getProperty(_CONTEXT),
  2460. nInitialMaxHeight = oMenu.cfg.getProperty(_MAX_HEIGHT),
  2461. nMaxHeight,
  2462. oOverlapPositions = {
  2463. "trbr": true,
  2464. "tlbl": true,
  2465. "bltl": true,
  2466. "brtr": true
  2467. },
  2468. bPotentialContextOverlap = (aContext && oOverlapPositions[aContext[1] + aContext[2]]),
  2469. oMenuEl = oMenu.element,
  2470. nMenuOffsetHeight = oMenuEl.offsetHeight,
  2471. nViewportOffset = Overlay.VIEWPORT_OFFSET,
  2472. viewPortHeight = Dom.getViewportHeight(),
  2473. scrollY = Dom.getDocumentScrollTop(),
  2474. bCanConstrain =
  2475. (oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) + nViewportOffset < viewPortHeight),
  2476. nAvailableHeight,
  2477. oContextEl,
  2478. nContextElY,
  2479. nContextElHeight,
  2480. bFlipped = false,
  2481. nTopRegionHeight,
  2482. nBottomRegionHeight,
  2483. topConstraint = scrollY + nViewportOffset,
  2484. bottomConstraint = scrollY + viewPortHeight - nMenuOffsetHeight - nViewportOffset,
  2485. yNew = y;
  2486. var flipVertical = function () {
  2487. var nNewY;
  2488. // The Menu is below the context element, flip it above
  2489. if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
  2490. nNewY = (nContextElY - nMenuOffsetHeight);
  2491. }
  2492. else { // The Menu is above the context element, flip it below
  2493. nNewY = (nContextElY + nContextElHeight);
  2494. }
  2495. oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
  2496. return nNewY;
  2497. };
  2498. /*
  2499. Uses the context element's position to calculate the availble height
  2500. above and below it to display its corresponding Menu.
  2501. */
  2502. var getDisplayRegionHeight = function () {
  2503. // The Menu is below the context element
  2504. if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
  2505. return (nBottomRegionHeight - nViewportOffset);
  2506. }
  2507. else { // The Menu is above the context element
  2508. return (nTopRegionHeight - nViewportOffset);
  2509. }
  2510. };
  2511. /*
  2512. Sets the Menu's "y" configuration property to the correct value based on its
  2513. current orientation.
  2514. */
  2515. var alignY = function () {
  2516. var nNewY;
  2517. if ((oMenu.cfg.getProperty(_Y) - scrollY) > nContextElY) {
  2518. nNewY = (nContextElY + nContextElHeight);
  2519. }
  2520. else {
  2521. nNewY = (nContextElY - oMenuEl.offsetHeight);
  2522. }
  2523. oMenu.cfg.setProperty(_Y, (nNewY + scrollY), true);
  2524. };
  2525. // Resets the maxheight of the Menu to the value set by the user
  2526. var resetMaxHeight = function () {
  2527. oMenu._setScrollHeight(this.cfg.getProperty(_MAX_HEIGHT));
  2528. oMenu.hideEvent.unsubscribe(resetMaxHeight);
  2529. };
  2530. /*
  2531. Trys to place the Menu in the best possible position (either above or
  2532. below its corresponding context element).
  2533. */
  2534. var setVerticalPosition = function () {
  2535. var nDisplayRegionHeight = getDisplayRegionHeight(),
  2536. bMenuHasItems = (oMenu.getItems().length > 0),
  2537. nMenuMinScrollHeight,
  2538. fnReturnVal;
  2539. if (nMenuOffsetHeight > nDisplayRegionHeight) {
  2540. nMenuMinScrollHeight =
  2541. bMenuHasItems ? oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT) : nMenuOffsetHeight;
  2542. if ((nDisplayRegionHeight > nMenuMinScrollHeight) && bMenuHasItems) {
  2543. nMaxHeight = nDisplayRegionHeight;
  2544. }
  2545. else {
  2546. nMaxHeight = nInitialMaxHeight;
  2547. }
  2548. oMenu._setScrollHeight(nMaxHeight);
  2549. oMenu.hideEvent.subscribe(resetMaxHeight);
  2550. // Re-align the Menu since its height has just changed
  2551. // as a result of the setting of the maxheight property.
  2552. alignY();
  2553. if (nDisplayRegionHeight < nMenuMinScrollHeight) {
  2554. if (bFlipped) {
  2555. /*
  2556. All possible positions and values for the "maxheight"
  2557. configuration property have been tried, but none were
  2558. successful, so fall back to the original size and position.
  2559. */
  2560. flipVertical();
  2561. }
  2562. else {
  2563. flipVertical();
  2564. bFlipped = true;
  2565. fnReturnVal = setVerticalPosition();
  2566. }
  2567. }
  2568. }
  2569. else if (nMaxHeight && (nMaxHeight !== nInitialMaxHeight)) {
  2570. oMenu._setScrollHeight(nInitialMaxHeight);
  2571. oMenu.hideEvent.subscribe(resetMaxHeight);
  2572. // Re-align the Menu since its height has just changed
  2573. // as a result of the setting of the maxheight property.
  2574. alignY();
  2575. }
  2576. return fnReturnVal;
  2577. };
  2578. // Determine if the current value for the Menu's "y" configuration property will
  2579. // result in the Menu being positioned outside the boundaries of the viewport
  2580. if (y < topConstraint || y > bottomConstraint) {
  2581. // The current value for the Menu's "y" configuration property WILL
  2582. // result in the Menu being positioned outside the boundaries of the viewport
  2583. if (bCanConstrain) {
  2584. if (oMenu.cfg.getProperty(_PREVENT_CONTEXT_OVERLAP) && bPotentialContextOverlap) {
  2585. // SOLUTION #1:
  2586. // If the "preventcontextoverlap" configuration property is set to "true",
  2587. // try to flip and/or scroll the Menu to both keep it inside the boundaries of the
  2588. // viewport AND from overlaping its context element (MenuItem or MenuBarItem).
  2589. oContextEl = aContext[0];
  2590. nContextElHeight = oContextEl.offsetHeight;
  2591. nContextElY = (Dom.getY(oContextEl) - scrollY);
  2592. nTopRegionHeight = nContextElY;
  2593. nBottomRegionHeight = (viewPortHeight - (nContextElY + nContextElHeight));
  2594. setVerticalPosition();
  2595. yNew = oMenu.cfg.getProperty(_Y);
  2596. }
  2597. else if (!(oMenu instanceof YAHOO.widget.MenuBar) &&
  2598. nMenuOffsetHeight >= viewPortHeight) {
  2599. // SOLUTION #2:
  2600. // If the Menu exceeds the height of the viewport, introduce scroll bars
  2601. // to keep the Menu inside the boundaries of the viewport
  2602. nAvailableHeight = (viewPortHeight - (nViewportOffset * 2));
  2603. if (nAvailableHeight > oMenu.cfg.getProperty(_MIN_SCROLL_HEIGHT)) {
  2604. oMenu._setScrollHeight(nAvailableHeight);
  2605. oMenu.hideEvent.subscribe(resetMaxHeight);
  2606. alignY();
  2607. yNew = oMenu.cfg.getProperty(_Y);
  2608. }
  2609. }
  2610. else {
  2611. // SOLUTION #3:
  2612. if (y < topConstraint) {
  2613. yNew = topConstraint;
  2614. } else if (y > bottomConstraint) {
  2615. yNew = bottomConstraint;
  2616. }
  2617. }
  2618. }
  2619. else {
  2620. // The "y" configuration property cannot be set to a value that will keep
  2621. // entire Menu inside the boundary of the viewport. Therefore, set
  2622. // the "y" configuration property to scrollY to keep as much of the
  2623. // Menu inside the viewport as possible.
  2624. yNew = nViewportOffset + scrollY;
  2625. }
  2626. }
  2627. return yNew;
  2628. },
  2629. /**
  2630. * @method _onHide
  2631. * @description "hide" event handler for the menu.
  2632. * @private
  2633. * @param {String} p_sType String representing the name of the event that
  2634. * was fired.
  2635. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2636. */
  2637. _onHide: function (p_sType, p_aArgs) {
  2638. if (this.cfg.getProperty(_POSITION) === _DYNAMIC) {
  2639. this.positionOffScreen();
  2640. }
  2641. },
  2642. /**
  2643. * @method _onShow
  2644. * @description "show" event handler for the menu.
  2645. * @private
  2646. * @param {String} p_sType String representing the name of the event that
  2647. * was fired.
  2648. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2649. */
  2650. _onShow: function (p_sType, p_aArgs) {
  2651. var oParent = this.parent,
  2652. oParentMenu,
  2653. oElement,
  2654. nOffsetWidth,
  2655. sWidth;
  2656. function disableAutoSubmenuDisplay(p_oEvent) {
  2657. var oTarget;
  2658. if (p_oEvent.type == _MOUSEDOWN || (p_oEvent.type == _KEYDOWN && p_oEvent.keyCode == 27)) {
  2659. /*
  2660. Set the "autosubmenudisplay" to "false" if the user
  2661. clicks outside the menu bar.
  2662. */
  2663. oTarget = Event.getTarget(p_oEvent);
  2664. if (oTarget != oParentMenu.element || !Dom.isAncestor(oParentMenu.element, oTarget)) {
  2665. oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
  2666. Event.removeListener(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
  2667. Event.removeListener(document, _KEYDOWN, disableAutoSubmenuDisplay);
  2668. }
  2669. }
  2670. }
  2671. function onSubmenuHide(p_sType, p_aArgs, p_sWidth) {
  2672. this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
  2673. this.hideEvent.unsubscribe(onSubmenuHide, p_sWidth);
  2674. }
  2675. if (oParent) {
  2676. oParentMenu = oParent.parent;
  2677. if (!oParentMenu.cfg.getProperty(_AUTO_SUBMENU_DISPLAY) &&
  2678. (oParentMenu instanceof YAHOO.widget.MenuBar ||
  2679. oParentMenu.cfg.getProperty(_POSITION) == _STATIC)) {
  2680. oParentMenu.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, true);
  2681. Event.on(document, _MOUSEDOWN, disableAutoSubmenuDisplay);
  2682. Event.on(document, _KEYDOWN, disableAutoSubmenuDisplay);
  2683. }
  2684. // The following fixes an issue with the selected state of a MenuItem
  2685. // not rendering correctly when a submenu is aligned to the left of
  2686. // its parent Menu instance.
  2687. if ((this.cfg.getProperty("x") < oParentMenu.cfg.getProperty("x")) &&
  2688. (UA.gecko && UA.gecko < 1.9) && !this.cfg.getProperty(_WIDTH)) {
  2689. oElement = this.element;
  2690. nOffsetWidth = oElement.offsetWidth;
  2691. /*
  2692. Measuring the difference of the offsetWidth before and after
  2693. setting the "width" style attribute allows us to compute the
  2694. about of padding and borders applied to the element, which in
  2695. turn allows us to set the "width" property correctly.
  2696. */
  2697. oElement.style.width = nOffsetWidth + _PX;
  2698. sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
  2699. this.cfg.setProperty(_WIDTH, sWidth);
  2700. this.hideEvent.subscribe(onSubmenuHide, sWidth);
  2701. }
  2702. }
  2703. /*
  2704. Dynamically positioned, root Menus focus themselves when visible, and
  2705. will then, when hidden, restore focus to the UI control that had focus
  2706. before the Menu was made visible.
  2707. */
  2708. if (this === this.getRoot() && this.cfg.getProperty(_POSITION) === _DYNAMIC) {
  2709. this._focusedElement = oFocusedElement;
  2710. this.focus();
  2711. }
  2712. },
  2713. /**
  2714. * @method _onBeforeHide
  2715. * @description "beforehide" event handler for the menu.
  2716. * @private
  2717. * @param {String} p_sType String representing the name of the event that
  2718. * was fired.
  2719. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2720. */
  2721. _onBeforeHide: function (p_sType, p_aArgs) {
  2722. var oActiveItem = this.activeItem,
  2723. oRoot = this.getRoot(),
  2724. oConfig,
  2725. oSubmenu;
  2726. if (oActiveItem) {
  2727. oConfig = oActiveItem.cfg;
  2728. oConfig.setProperty(_SELECTED, false);
  2729. oSubmenu = oConfig.getProperty(_SUBMENU);
  2730. if (oSubmenu) {
  2731. oSubmenu.hide();
  2732. }
  2733. }
  2734. /*
  2735. Focus can get lost in IE when the mouse is moving from a submenu back to its parent Menu.
  2736. For this reason, it is necessary to maintain the focused state in a private property
  2737. so that the _onMouseOver event handler is able to determined whether or not to set focus
  2738. to MenuItems as the user is moving the mouse.
  2739. */
  2740. if (UA.ie && this.cfg.getProperty(_POSITION) === _DYNAMIC && this.parent) {
  2741. oRoot._hasFocus = this.hasFocus();
  2742. }
  2743. if (oRoot == this) {
  2744. oRoot.blur();
  2745. }
  2746. },
  2747. /**
  2748. * @method _onParentMenuConfigChange
  2749. * @description "configchange" event handler for a submenu.
  2750. * @private
  2751. * @param {String} p_sType String representing the name of the event that
  2752. * was fired.
  2753. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2754. * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
  2755. * subscribed to the event.
  2756. */
  2757. _onParentMenuConfigChange: function (p_sType, p_aArgs, p_oSubmenu) {
  2758. var sPropertyName = p_aArgs[0][0],
  2759. oPropertyValue = p_aArgs[0][1];
  2760. switch(sPropertyName) {
  2761. case _IFRAME:
  2762. case _CONSTRAIN_TO_VIEWPORT:
  2763. case _HIDE_DELAY:
  2764. case _SHOW_DELAY:
  2765. case _SUBMENU_HIDE_DELAY:
  2766. case _CLICK_TO_HIDE:
  2767. case _EFFECT:
  2768. case _CLASSNAME:
  2769. case _SCROLL_INCREMENT:
  2770. case _MAX_HEIGHT:
  2771. case _MIN_SCROLL_HEIGHT:
  2772. case _MONITOR_RESIZE:
  2773. case _SHADOW:
  2774. case _PREVENT_CONTEXT_OVERLAP:
  2775. case _KEEP_OPEN:
  2776. p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
  2777. break;
  2778. case _SUBMENU_ALIGNMENT:
  2779. if (!(this.parent.parent instanceof YAHOO.widget.MenuBar)) {
  2780. p_oSubmenu.cfg.setProperty(sPropertyName, oPropertyValue);
  2781. }
  2782. break;
  2783. }
  2784. },
  2785. /**
  2786. * @method _onParentMenuRender
  2787. * @description "render" event handler for a submenu. Renders a
  2788. * submenu in response to the firing of its parent's "render" event.
  2789. * @private
  2790. * @param {String} p_sType String representing the name of the event that
  2791. * was fired.
  2792. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2793. * @param {YAHOO.widget.Menu} p_oSubmenu Object representing the submenu that
  2794. * subscribed to the event.
  2795. */
  2796. _onParentMenuRender: function (p_sType, p_aArgs, p_oSubmenu) {
  2797. var oParentMenu = p_oSubmenu.parent.parent,
  2798. oParentCfg = oParentMenu.cfg,
  2799. oConfig = {
  2800. constraintoviewport: oParentCfg.getProperty(_CONSTRAIN_TO_VIEWPORT),
  2801. xy: [0,0],
  2802. clicktohide: oParentCfg.getProperty(_CLICK_TO_HIDE),
  2803. effect: oParentCfg.getProperty(_EFFECT),
  2804. showdelay: oParentCfg.getProperty(_SHOW_DELAY),
  2805. hidedelay: oParentCfg.getProperty(_HIDE_DELAY),
  2806. submenuhidedelay: oParentCfg.getProperty(_SUBMENU_HIDE_DELAY),
  2807. classname: oParentCfg.getProperty(_CLASSNAME),
  2808. scrollincrement: oParentCfg.getProperty(_SCROLL_INCREMENT),
  2809. maxheight: oParentCfg.getProperty(_MAX_HEIGHT),
  2810. minscrollheight: oParentCfg.getProperty(_MIN_SCROLL_HEIGHT),
  2811. iframe: oParentCfg.getProperty(_IFRAME),
  2812. shadow: oParentCfg.getProperty(_SHADOW),
  2813. preventcontextoverlap: oParentCfg.getProperty(_PREVENT_CONTEXT_OVERLAP),
  2814. monitorresize: oParentCfg.getProperty(_MONITOR_RESIZE),
  2815. keepopen: oParentCfg.getProperty(_KEEP_OPEN)
  2816. },
  2817. oLI;
  2818. if (!(oParentMenu instanceof YAHOO.widget.MenuBar)) {
  2819. oConfig[_SUBMENU_ALIGNMENT] = oParentCfg.getProperty(_SUBMENU_ALIGNMENT);
  2820. }
  2821. p_oSubmenu.cfg.applyConfig(oConfig);
  2822. if (!this.lazyLoad) {
  2823. oLI = this.parent.element;
  2824. if (this.element.parentNode == oLI) {
  2825. this.render();
  2826. }
  2827. else {
  2828. this.render(oLI);
  2829. }
  2830. }
  2831. },
  2832. /**
  2833. * @method _onMenuItemDestroy
  2834. * @description "destroy" event handler for the menu's items.
  2835. * @private
  2836. * @param {String} p_sType String representing the name of the event
  2837. * that was fired.
  2838. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2839. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  2840. * that fired the event.
  2841. */
  2842. _onMenuItemDestroy: function (p_sType, p_aArgs, p_oItem) {
  2843. this._removeItemFromGroupByValue(p_oItem.groupIndex, p_oItem);
  2844. },
  2845. /**
  2846. * @method _onMenuItemConfigChange
  2847. * @description "configchange" event handler for the menu's items.
  2848. * @private
  2849. * @param {String} p_sType String representing the name of the event that
  2850. * was fired.
  2851. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2852. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  2853. * that fired the event.
  2854. */
  2855. _onMenuItemConfigChange: function (p_sType, p_aArgs, p_oItem) {
  2856. var sPropertyName = p_aArgs[0][0],
  2857. oPropertyValue = p_aArgs[0][1],
  2858. oSubmenu;
  2859. switch(sPropertyName) {
  2860. case _SELECTED:
  2861. if (oPropertyValue === true) {
  2862. this.activeItem = p_oItem;
  2863. }
  2864. break;
  2865. case _SUBMENU:
  2866. oSubmenu = p_aArgs[0][1];
  2867. if (oSubmenu) {
  2868. this._configureSubmenu(p_oItem);
  2869. }
  2870. break;
  2871. }
  2872. },
  2873. // Public event handlers for configuration properties
  2874. /**
  2875. * @method configVisible
  2876. * @description Event handler for when the "visible" configuration property
  2877. * the menu changes.
  2878. * @param {String} p_sType String representing the name of the event that
  2879. * was fired.
  2880. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2881. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2882. * fired the event.
  2883. */
  2884. configVisible: function (p_sType, p_aArgs, p_oMenu) {
  2885. var bVisible,
  2886. sDisplay;
  2887. if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  2888. Menu.superclass.configVisible.call(this, p_sType, p_aArgs, p_oMenu);
  2889. }
  2890. else {
  2891. bVisible = p_aArgs[0];
  2892. sDisplay = Dom.getStyle(this.element, _DISPLAY);
  2893. Dom.setStyle(this.element, _VISIBILITY, _VISIBLE);
  2894. if (bVisible) {
  2895. if (sDisplay != _BLOCK) {
  2896. this.beforeShowEvent.fire();
  2897. Dom.setStyle(this.element, _DISPLAY, _BLOCK);
  2898. this.showEvent.fire();
  2899. }
  2900. }
  2901. else {
  2902. if (sDisplay == _BLOCK) {
  2903. this.beforeHideEvent.fire();
  2904. Dom.setStyle(this.element, _DISPLAY, _NONE);
  2905. this.hideEvent.fire();
  2906. }
  2907. }
  2908. }
  2909. },
  2910. /**
  2911. * @method configPosition
  2912. * @description Event handler for when the "position" configuration property
  2913. * of the menu changes.
  2914. * @param {String} p_sType String representing the name of the event that
  2915. * was fired.
  2916. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2917. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2918. * fired the event.
  2919. */
  2920. configPosition: function (p_sType, p_aArgs, p_oMenu) {
  2921. var oElement = this.element,
  2922. sCSSPosition = p_aArgs[0] == _STATIC ? _STATIC : _ABSOLUTE,
  2923. oCfg = this.cfg,
  2924. nZIndex;
  2925. Dom.setStyle(oElement, _POSITION, sCSSPosition);
  2926. if (sCSSPosition == _STATIC) {
  2927. // Statically positioned menus are visible by default
  2928. Dom.setStyle(oElement, _DISPLAY, _BLOCK);
  2929. oCfg.setProperty(_VISIBLE, true);
  2930. }
  2931. else {
  2932. /*
  2933. Even though the "visible" property is queued to
  2934. "false" by default, we need to set the "visibility" property to
  2935. "hidden" since Overlay's "configVisible" implementation checks the
  2936. element's "visibility" style property before deciding whether
  2937. or not to show an Overlay instance.
  2938. */
  2939. Dom.setStyle(oElement, _VISIBILITY, _HIDDEN);
  2940. }
  2941. if (sCSSPosition == _ABSOLUTE) {
  2942. nZIndex = oCfg.getProperty(_ZINDEX);
  2943. if (!nZIndex || nZIndex === 0) {
  2944. oCfg.setProperty(_ZINDEX, 1);
  2945. }
  2946. }
  2947. },
  2948. /**
  2949. * @method configIframe
  2950. * @description Event handler for when the "iframe" configuration property of
  2951. * the menu changes.
  2952. * @param {String} p_sType String representing the name of the event that
  2953. * was fired.
  2954. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2955. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2956. * fired the event.
  2957. */
  2958. configIframe: function (p_sType, p_aArgs, p_oMenu) {
  2959. if (this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  2960. Menu.superclass.configIframe.call(this, p_sType, p_aArgs, p_oMenu);
  2961. }
  2962. },
  2963. /**
  2964. * @method configHideDelay
  2965. * @description Event handler for when the "hidedelay" configuration property
  2966. * of the menu changes.
  2967. * @param {String} p_sType String representing the name of the event that
  2968. * was fired.
  2969. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2970. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2971. * fired the event.
  2972. */
  2973. configHideDelay: function (p_sType, p_aArgs, p_oMenu) {
  2974. var nHideDelay = p_aArgs[0];
  2975. this._useHideDelay = (nHideDelay > 0);
  2976. },
  2977. /**
  2978. * @method configContainer
  2979. * @description Event handler for when the "container" configuration property
  2980. * of the menu changes.
  2981. * @param {String} p_sType String representing the name of the event that
  2982. * was fired.
  2983. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  2984. * @param {YAHOO.widget.Menu} p_oMenu Object representing the menu that
  2985. * fired the event.
  2986. */
  2987. configContainer: function (p_sType, p_aArgs, p_oMenu) {
  2988. var oElement = p_aArgs[0];
  2989. if (Lang.isString(oElement)) {
  2990. this.cfg.setProperty(_CONTAINER, Dom.get(oElement), true);
  2991. }
  2992. },
  2993. /**
  2994. * @method _clearSetWidthFlag
  2995. * @description Change event listener for the "width" configuration property. This listener is
  2996. * added when a Menu's "width" configuration property is set by the "_setScrollHeight" method, and
  2997. * is used to set the "_widthSetForScroll" property to "false" if the "width" configuration property
  2998. * is changed after it was set by the "_setScrollHeight" method. If the "_widthSetForScroll"
  2999. * property is set to "false", and the "_setScrollHeight" method is in the process of tearing down
  3000. * scrolling functionality, it will maintain the Menu's new width rather than reseting it.
  3001. * @private
  3002. */
  3003. _clearSetWidthFlag: function () {
  3004. this._widthSetForScroll = false;
  3005. this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
  3006. },
  3007. /**
  3008. * @method _setScrollHeight
  3009. * @description
  3010. * @param {String} p_nScrollHeight Number representing the scrolling height of the Menu.
  3011. * @private
  3012. */
  3013. _setScrollHeight: function (p_nScrollHeight) {
  3014. var nScrollHeight = p_nScrollHeight,
  3015. bRefireIFrameAndShadow = false,
  3016. bSetWidth = false,
  3017. oElement,
  3018. oBody,
  3019. oHeader,
  3020. oFooter,
  3021. fnMouseOver,
  3022. fnMouseOut,
  3023. nMinScrollHeight,
  3024. nHeight,
  3025. nOffsetWidth,
  3026. sWidth;
  3027. if (this.getItems().length > 0) {
  3028. oElement = this.element;
  3029. oBody = this.body;
  3030. oHeader = this.header;
  3031. oFooter = this.footer;
  3032. fnMouseOver = this._onScrollTargetMouseOver;
  3033. fnMouseOut = this._onScrollTargetMouseOut;
  3034. nMinScrollHeight = this.cfg.getProperty(_MIN_SCROLL_HEIGHT);
  3035. if (nScrollHeight > 0 && nScrollHeight < nMinScrollHeight) {
  3036. nScrollHeight = nMinScrollHeight;
  3037. }
  3038. Dom.setStyle(oBody, _HEIGHT, _EMPTY_STRING);
  3039. Dom.removeClass(oBody, _YUI_MENU_BODY_SCROLLED);
  3040. oBody.scrollTop = 0;
  3041. // Need to set a width for the Menu to fix the following problems in
  3042. // Firefox 2 and IE:
  3043. // #1) Scrolled Menus will render at 1px wide in Firefox 2
  3044. // #2) There is a bug in gecko-based browsers where an element whose
  3045. // "position" property is set to "absolute" and "overflow" property is
  3046. // set to "hidden" will not render at the correct width when its
  3047. // offsetParent's "position" property is also set to "absolute." It is
  3048. // possible to work around this bug by specifying a value for the width
  3049. // property in addition to overflow.
  3050. // #3) In IE it is necessary to give the Menu a width before the
  3051. // scrollbars are rendered to prevent the Menu from rendering with a
  3052. // width that is 100% of the browser viewport.
  3053. bSetWidth = ((UA.gecko && UA.gecko < 1.9) || UA.ie);
  3054. if (nScrollHeight > 0 && bSetWidth && !this.cfg.getProperty(_WIDTH)) {
  3055. nOffsetWidth = oElement.offsetWidth;
  3056. /*
  3057. Measuring the difference of the offsetWidth before and after
  3058. setting the "width" style attribute allows us to compute the
  3059. about of padding and borders applied to the element, which in
  3060. turn allows us to set the "width" property correctly.
  3061. */
  3062. oElement.style.width = nOffsetWidth + _PX;
  3063. sWidth = (nOffsetWidth - (oElement.offsetWidth - nOffsetWidth)) + _PX;
  3064. this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
  3065. YAHOO.log("Setting the \"width\" configuration property to " + sWidth + " for srolling.",
  3066. "info", this.toString());
  3067. this.cfg.setProperty(_WIDTH, sWidth);
  3068. /*
  3069. Set a flag (_widthSetForScroll) to maintain some history regarding how the
  3070. "width" configuration property was set. If the "width" configuration property
  3071. is set by something other than the "_setScrollHeight" method, it will be
  3072. necessary to maintain that new value and not clear the width if scrolling
  3073. is turned off.
  3074. */
  3075. this._widthSetForScroll = true;
  3076. this.cfg.subscribeToConfigEvent(_WIDTH, this._clearSetWidthFlag);
  3077. }
  3078. if (nScrollHeight > 0 && (!oHeader && !oFooter)) {
  3079. YAHOO.log("Creating header and footer for scrolling.", "info", this.toString());
  3080. this.setHeader(_NON_BREAKING_SPACE);
  3081. this.setFooter(_NON_BREAKING_SPACE);
  3082. oHeader = this.header;
  3083. oFooter = this.footer;
  3084. Dom.addClass(oHeader, _TOP_SCROLLBAR);
  3085. Dom.addClass(oFooter, _BOTTOM_SCROLLBAR);
  3086. oElement.insertBefore(oHeader, oBody);
  3087. oElement.appendChild(oFooter);
  3088. }
  3089. nHeight = nScrollHeight;
  3090. if (oHeader && oFooter) {
  3091. nHeight = (nHeight - (oHeader.offsetHeight + oFooter.offsetHeight));
  3092. }
  3093. if ((nHeight > 0) && (oBody.offsetHeight > nScrollHeight)) {
  3094. YAHOO.log("Setting up styles and event handlers for scrolling.",
  3095. "info", this.toString());
  3096. Dom.addClass(oBody, _YUI_MENU_BODY_SCROLLED);
  3097. Dom.setStyle(oBody, _HEIGHT, (nHeight + _PX));
  3098. if (!this._hasScrollEventHandlers) {
  3099. Event.on(oHeader, _MOUSEOVER, fnMouseOver, this, true);
  3100. Event.on(oHeader, _MOUSEOUT, fnMouseOut, this, true);
  3101. Event.on(oFooter, _MOUSEOVER, fnMouseOver, this, true);
  3102. Event.on(oFooter, _MOUSEOUT, fnMouseOut, this, true);
  3103. this._hasScrollEventHandlers = true;
  3104. }
  3105. this._disableScrollHeader();
  3106. this._enableScrollFooter();
  3107. bRefireIFrameAndShadow = true;
  3108. }
  3109. else if (oHeader && oFooter) {
  3110. YAHOO.log("Removing styles and event handlers for scrolling.", "info", this.toString());
  3111. /*
  3112. Only clear the the "width" configuration property if it was set the
  3113. "_setScrollHeight" method and wasn't changed by some other means after it was set.
  3114. */
  3115. if (this._widthSetForScroll) {
  3116. YAHOO.log("Clearing width used for scrolling.", "info", this.toString());
  3117. this._widthSetForScroll = false;
  3118. this.cfg.unsubscribeFromConfigEvent(_WIDTH, this._clearSetWidthFlag);
  3119. this.cfg.setProperty(_WIDTH, _EMPTY_STRING);
  3120. }
  3121. this._enableScrollHeader();
  3122. this._enableScrollFooter();
  3123. if (this._hasScrollEventHandlers) {
  3124. Event.removeListener(oHeader, _MOUSEOVER, fnMouseOver);
  3125. Event.removeListener(oHeader, _MOUSEOUT, fnMouseOut);
  3126. Event.removeListener(oFooter, _MOUSEOVER, fnMouseOver);
  3127. Event.removeListener(oFooter, _MOUSEOUT, fnMouseOut);
  3128. this._hasScrollEventHandlers = false;
  3129. }
  3130. oElement.removeChild(oHeader);
  3131. oElement.removeChild(oFooter);
  3132. this.header = null;
  3133. this.footer = null;
  3134. bRefireIFrameAndShadow = true;
  3135. }
  3136. if (bRefireIFrameAndShadow) {
  3137. this.cfg.refireEvent(_IFRAME);
  3138. this.cfg.refireEvent(_SHADOW);
  3139. }
  3140. }
  3141. },
  3142. /**
  3143. * @method _setMaxHeight
  3144. * @description "renderEvent" handler used to defer the setting of the
  3145. * "maxheight" configuration property until the menu is rendered in lazy
  3146. * load scenarios.
  3147. * @param {String} p_sType The name of the event that was fired.
  3148. * @param {Array} p_aArgs Collection of arguments sent when the event
  3149. * was fired.
  3150. * @param {Number} p_nMaxHeight Number representing the value to set for the
  3151. * "maxheight" configuration property.
  3152. * @private
  3153. */
  3154. _setMaxHeight: function (p_sType, p_aArgs, p_nMaxHeight) {
  3155. this._setScrollHeight(p_nMaxHeight);
  3156. this.renderEvent.unsubscribe(this._setMaxHeight);
  3157. },
  3158. /**
  3159. * @method configMaxHeight
  3160. * @description Event handler for when the "maxheight" configuration property of
  3161. * a Menu changes.
  3162. * @param {String} p_sType The name of the event that was fired.
  3163. * @param {Array} p_aArgs Collection of arguments sent when the event
  3164. * was fired.
  3165. * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired
  3166. * the event.
  3167. */
  3168. configMaxHeight: function (p_sType, p_aArgs, p_oMenu) {
  3169. var nMaxHeight = p_aArgs[0];
  3170. if (this.lazyLoad && !this.body && nMaxHeight > 0) {
  3171. this.renderEvent.subscribe(this._setMaxHeight, nMaxHeight, this);
  3172. }
  3173. else {
  3174. this._setScrollHeight(nMaxHeight);
  3175. }
  3176. },
  3177. /**
  3178. * @method configClassName
  3179. * @description Event handler for when the "classname" configuration property of
  3180. * a menu changes.
  3181. * @param {String} p_sType The name of the event that was fired.
  3182. * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
  3183. * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
  3184. */
  3185. configClassName: function (p_sType, p_aArgs, p_oMenu) {
  3186. var sClassName = p_aArgs[0];
  3187. if (this._sClassName) {
  3188. Dom.removeClass(this.element, this._sClassName);
  3189. }
  3190. Dom.addClass(this.element, sClassName);
  3191. this._sClassName = sClassName;
  3192. },
  3193. /**
  3194. * @method _onItemAdded
  3195. * @description "itemadded" event handler for a Menu instance.
  3196. * @private
  3197. * @param {String} p_sType The name of the event that was fired.
  3198. * @param {Array} p_aArgs Collection of arguments sent when the event
  3199. * was fired.
  3200. */
  3201. _onItemAdded: function (p_sType, p_aArgs) {
  3202. var oItem = p_aArgs[0];
  3203. if (oItem) {
  3204. oItem.cfg.setProperty(_DISABLED, true);
  3205. }
  3206. },
  3207. /**
  3208. * @method configDisabled
  3209. * @description Event handler for when the "disabled" configuration property of
  3210. * a menu changes.
  3211. * @param {String} p_sType The name of the event that was fired.
  3212. * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
  3213. * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
  3214. */
  3215. configDisabled: function (p_sType, p_aArgs, p_oMenu) {
  3216. var bDisabled = p_aArgs[0],
  3217. aItems = this.getItems(),
  3218. nItems,
  3219. i;
  3220. if (Lang.isArray(aItems)) {
  3221. nItems = aItems.length;
  3222. if (nItems > 0) {
  3223. i = nItems - 1;
  3224. do {
  3225. aItems[i].cfg.setProperty(_DISABLED, bDisabled);
  3226. }
  3227. while (i--);
  3228. }
  3229. if (bDisabled) {
  3230. this.clearActiveItem(true);
  3231. Dom.addClass(this.element, _DISABLED);
  3232. this.itemAddedEvent.subscribe(this._onItemAdded);
  3233. }
  3234. else {
  3235. Dom.removeClass(this.element, _DISABLED);
  3236. this.itemAddedEvent.unsubscribe(this._onItemAdded);
  3237. }
  3238. }
  3239. },
  3240. /**
  3241. * @method configShadow
  3242. * @description Event handler for when the "shadow" configuration property of
  3243. * a menu changes.
  3244. * @param {String} p_sType The name of the event that was fired.
  3245. * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
  3246. * @param {YAHOO.widget.Menu} p_oMenu The Menu instance fired the event.
  3247. */
  3248. configShadow: function (p_sType, p_aArgs, p_oMenu) {
  3249. var sizeShadow = function () {
  3250. var oElement = this.element,
  3251. oShadow = this._shadow;
  3252. if (oShadow && oElement) {
  3253. // Clear the previous width
  3254. if (oShadow.style.width && oShadow.style.height) {
  3255. oShadow.style.width = _EMPTY_STRING;
  3256. oShadow.style.height = _EMPTY_STRING;
  3257. }
  3258. oShadow.style.width = (oElement.offsetWidth + 6) + _PX;
  3259. oShadow.style.height = (oElement.offsetHeight + 1) + _PX;
  3260. }
  3261. };
  3262. var replaceShadow = function () {
  3263. this.element.appendChild(this._shadow);
  3264. };
  3265. var addShadowVisibleClass = function () {
  3266. Dom.addClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
  3267. };
  3268. var removeShadowVisibleClass = function () {
  3269. Dom.removeClass(this._shadow, _YUI_MENU_SHADOW_VISIBLE);
  3270. };
  3271. var createShadow = function () {
  3272. var oShadow = this._shadow,
  3273. oElement;
  3274. if (!oShadow) {
  3275. oElement = this.element;
  3276. if (!m_oShadowTemplate) {
  3277. m_oShadowTemplate = document.createElement(_DIV_LOWERCASE);
  3278. m_oShadowTemplate.className = _YUI_MENU_SHADOW_YUI_MENU_SHADOW_VISIBLE;
  3279. }
  3280. oShadow = m_oShadowTemplate.cloneNode(false);
  3281. oElement.appendChild(oShadow);
  3282. this._shadow = oShadow;
  3283. this.beforeShowEvent.subscribe(addShadowVisibleClass);
  3284. this.beforeHideEvent.subscribe(removeShadowVisibleClass);
  3285. if (UA.ie) {
  3286. /*
  3287. Need to call sizeShadow & syncIframe via setTimeout for
  3288. IE 7 Quirks Mode and IE 6 Standards Mode and Quirks Mode
  3289. or the shadow and iframe shim will not be sized and
  3290. positioned properly.
  3291. */
  3292. Lang.later(0, this, function () {
  3293. sizeShadow.call(this);
  3294. this.syncIframe();
  3295. });
  3296. this.cfg.subscribeToConfigEvent(_WIDTH, sizeShadow);
  3297. this.cfg.subscribeToConfigEvent(_HEIGHT, sizeShadow);
  3298. this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, sizeShadow);
  3299. this.changeContentEvent.subscribe(sizeShadow);
  3300. Module.textResizeEvent.subscribe(sizeShadow, this, true);
  3301. this.destroyEvent.subscribe(function () {
  3302. Module.textResizeEvent.unsubscribe(sizeShadow, this);
  3303. });
  3304. }
  3305. this.cfg.subscribeToConfigEvent(_MAX_HEIGHT, replaceShadow);
  3306. }
  3307. };
  3308. var onBeforeShow = function () {
  3309. if (this._shadow) {
  3310. // If called because the "shadow" event was refired - just append again and resize
  3311. replaceShadow.call(this);
  3312. if (UA.ie) {
  3313. sizeShadow.call(this);
  3314. }
  3315. }
  3316. else {
  3317. createShadow.call(this);
  3318. }
  3319. this.beforeShowEvent.unsubscribe(onBeforeShow);
  3320. };
  3321. var bShadow = p_aArgs[0];
  3322. if (bShadow && this.cfg.getProperty(_POSITION) == _DYNAMIC) {
  3323. if (this.cfg.getProperty(_VISIBLE)) {
  3324. if (this._shadow) {
  3325. // If the "shadow" event was refired - just append again and resize
  3326. replaceShadow.call(this);
  3327. if (UA.ie) {
  3328. sizeShadow.call(this);
  3329. }
  3330. }
  3331. else {
  3332. createShadow.call(this);
  3333. }
  3334. }
  3335. else {
  3336. this.beforeShowEvent.subscribe(onBeforeShow);
  3337. }
  3338. }
  3339. },
  3340. // Public methods
  3341. /**
  3342. * @method initEvents
  3343. * @description Initializes the custom events for the menu.
  3344. */
  3345. initEvents: function () {
  3346. Menu.superclass.initEvents.call(this);
  3347. // Create custom events
  3348. var i = EVENT_TYPES.length - 1,
  3349. aEventData,
  3350. oCustomEvent;
  3351. do {
  3352. aEventData = EVENT_TYPES[i];
  3353. oCustomEvent = this.createEvent(aEventData[1]);
  3354. oCustomEvent.signature = CustomEvent.LIST;
  3355. this[aEventData[0]] = oCustomEvent;
  3356. }
  3357. while (i--);
  3358. },
  3359. /**
  3360. * @method positionOffScreen
  3361. * @description Positions the menu outside of the boundaries of the browser's
  3362. * viewport. Called automatically when a menu is hidden to ensure that
  3363. * it doesn't force the browser to render uncessary scrollbars.
  3364. */
  3365. positionOffScreen: function () {
  3366. var oIFrame = this.iframe,
  3367. oElement = this.element,
  3368. sPos = this.OFF_SCREEN_POSITION;
  3369. oElement.style.top = _EMPTY_STRING;
  3370. oElement.style.left = _EMPTY_STRING;
  3371. if (oIFrame) {
  3372. oIFrame.style.top = sPos;
  3373. oIFrame.style.left = sPos;
  3374. }
  3375. },
  3376. /**
  3377. * @method getRoot
  3378. * @description Finds the menu's root menu.
  3379. */
  3380. getRoot: function () {
  3381. var oItem = this.parent,
  3382. oParentMenu,
  3383. returnVal;
  3384. if (oItem) {
  3385. oParentMenu = oItem.parent;
  3386. returnVal = oParentMenu ? oParentMenu.getRoot() : this;
  3387. }
  3388. else {
  3389. returnVal = this;
  3390. }
  3391. return returnVal;
  3392. },
  3393. /**
  3394. * @method toString
  3395. * @description Returns a string representing the menu.
  3396. * @return {String}
  3397. */
  3398. toString: function () {
  3399. var sReturnVal = _MENU,
  3400. sId = this.id;
  3401. if (sId) {
  3402. sReturnVal += (_SPACE + sId);
  3403. }
  3404. return sReturnVal;
  3405. },
  3406. /**
  3407. * @method setItemGroupTitle
  3408. * @description Sets the title of a group of menu items.
  3409. * @param {String} p_sGroupTitle String specifying the title of the group.
  3410. * @param {Number} p_nGroupIndex Optional. Number specifying the group to which
  3411. * the title belongs.
  3412. */
  3413. setItemGroupTitle: function (p_sGroupTitle, p_nGroupIndex) {
  3414. var nGroupIndex,
  3415. oTitle,
  3416. i,
  3417. nFirstIndex;
  3418. if (Lang.isString(p_sGroupTitle) && p_sGroupTitle.length > 0) {
  3419. nGroupIndex = Lang.isNumber(p_nGroupIndex) ? p_nGroupIndex : 0;
  3420. oTitle = this._aGroupTitleElements[nGroupIndex];
  3421. if (oTitle) {
  3422. oTitle.innerHTML = p_sGroupTitle;
  3423. }
  3424. else {
  3425. oTitle = document.createElement(this.GROUP_TITLE_TAG_NAME);
  3426. oTitle.innerHTML = p_sGroupTitle;
  3427. this._aGroupTitleElements[nGroupIndex] = oTitle;
  3428. }
  3429. i = this._aGroupTitleElements.length - 1;
  3430. do {
  3431. if (this._aGroupTitleElements[i]) {
  3432. Dom.removeClass(this._aGroupTitleElements[i], _FIRST_OF_TYPE);
  3433. nFirstIndex = i;
  3434. }
  3435. }
  3436. while (i--);
  3437. if (nFirstIndex !== null) {
  3438. Dom.addClass(this._aGroupTitleElements[nFirstIndex],
  3439. _FIRST_OF_TYPE);
  3440. }
  3441. this.changeContentEvent.fire();
  3442. }
  3443. },
  3444. /**
  3445. * @method addItem
  3446. * @description Appends an item to the menu.
  3447. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  3448. * instance to be added to the menu.
  3449. * @param {String} p_oItem String specifying the text of the item to be added
  3450. * to the menu.
  3451. * @param {Object} p_oItem Object literal containing a set of menu item
  3452. * configuration properties.
  3453. * @param {Number} p_nGroupIndex Optional. Number indicating the group to
  3454. * which the item belongs.
  3455. * @return {YAHOO.widget.MenuItem}
  3456. */
  3457. addItem: function (p_oItem, p_nGroupIndex) {
  3458. return this._addItemToGroup(p_nGroupIndex, p_oItem);
  3459. },
  3460. /**
  3461. * @method addItems
  3462. * @description Adds an array of items to the menu.
  3463. * @param {Array} p_aItems Array of items to be added to the menu. The array
  3464. * can contain strings specifying the text for each item to be created, object
  3465. * literals specifying each of the menu item configuration properties,
  3466. * or MenuItem instances.
  3467. * @param {Number} p_nGroupIndex Optional. Number specifying the group to
  3468. * which the items belongs.
  3469. * @return {Array}
  3470. */
  3471. addItems: function (p_aItems, p_nGroupIndex) {
  3472. var nItems,
  3473. aItems,
  3474. oItem,
  3475. i,
  3476. returnVal;
  3477. if (Lang.isArray(p_aItems)) {
  3478. nItems = p_aItems.length;
  3479. aItems = [];
  3480. for(i=0; i<nItems; i++) {
  3481. oItem = p_aItems[i];
  3482. if (oItem) {
  3483. if (Lang.isArray(oItem)) {
  3484. aItems[aItems.length] = this.addItems(oItem, i);
  3485. }
  3486. else {
  3487. aItems[aItems.length] = this._addItemToGroup(p_nGroupIndex, oItem);
  3488. }
  3489. }
  3490. }
  3491. if (aItems.length) {
  3492. returnVal = aItems;
  3493. }
  3494. }
  3495. return returnVal;
  3496. },
  3497. /**
  3498. * @method insertItem
  3499. * @description Inserts an item into the menu at the specified index.
  3500. * @param {YAHOO.widget.MenuItem} p_oItem Object reference for the MenuItem
  3501. * instance to be added to the menu.
  3502. * @param {String} p_oItem String specifying the text of the item to be added
  3503. * to the menu.
  3504. * @param {Object} p_oItem Object literal containing a set of menu item
  3505. * configuration properties.
  3506. * @param {Number} p_nItemIndex Number indicating the ordinal position at which
  3507. * the item should be added.
  3508. * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
  3509. * the item belongs.
  3510. * @return {YAHOO.widget.MenuItem}
  3511. */
  3512. insertItem: function (p_oItem, p_nItemIndex, p_nGroupIndex) {
  3513. return this._addItemToGroup(p_nGroupIndex, p_oItem, p_nItemIndex);
  3514. },
  3515. /**
  3516. * @method removeItem
  3517. * @description Removes the specified item from the menu.
  3518. * @param {YAHOO.widget.MenuItem} p_oObject Object reference for the MenuItem
  3519. * instance to be removed from the menu.
  3520. * @param {Number} p_oObject Number specifying the index of the item
  3521. * to be removed.
  3522. * @param {Number} p_nGroupIndex Optional. Number specifying the group to
  3523. * which the item belongs.
  3524. * @return {YAHOO.widget.MenuItem}
  3525. */
  3526. removeItem: function (p_oObject, p_nGroupIndex) {
  3527. var oItem,
  3528. returnVal;
  3529. if (!Lang.isUndefined(p_oObject)) {
  3530. if (p_oObject instanceof YAHOO.widget.MenuItem) {
  3531. oItem = this._removeItemFromGroupByValue(p_nGroupIndex, p_oObject);
  3532. }
  3533. else if (Lang.isNumber(p_oObject)) {
  3534. oItem = this._removeItemFromGroupByIndex(p_nGroupIndex, p_oObject);
  3535. }
  3536. if (oItem) {
  3537. oItem.destroy();
  3538. YAHOO.log("Item removed." +
  3539. " Text: " + oItem.cfg.getProperty("text") + ", " +
  3540. " Index: " + oItem.index + ", " +
  3541. " Group Index: " + oItem.groupIndex, "info", this.toString());
  3542. returnVal = oItem;
  3543. }
  3544. }
  3545. return returnVal;
  3546. },
  3547. /**
  3548. * @method getItems
  3549. * @description Returns an array of all of the items in the menu.
  3550. * @return {Array}
  3551. */
  3552. getItems: function () {
  3553. var aGroups = this._aItemGroups,
  3554. nGroups,
  3555. returnVal,
  3556. aItems = [];
  3557. if (Lang.isArray(aGroups)) {
  3558. nGroups = aGroups.length;
  3559. returnVal = ((nGroups == 1) ? aGroups[0] : (Array.prototype.concat.apply(aItems, aGroups)));
  3560. }
  3561. return returnVal;
  3562. },
  3563. /**
  3564. * @method getItemGroups
  3565. * @description Multi-dimensional Array representing the menu items as they
  3566. * are grouped in the menu.
  3567. * @return {Array}
  3568. */
  3569. getItemGroups: function () {
  3570. return this._aItemGroups;
  3571. },
  3572. /**
  3573. * @method getItem
  3574. * @description Returns the item at the specified index.
  3575. * @param {Number} p_nItemIndex Number indicating the ordinal position of the
  3576. * item to be retrieved.
  3577. * @param {Number} p_nGroupIndex Optional. Number indicating the group to which
  3578. * the item belongs.
  3579. * @return {YAHOO.widget.MenuItem}
  3580. */
  3581. getItem: function (p_nItemIndex, p_nGroupIndex) {
  3582. var aGroup,
  3583. returnVal;
  3584. if (Lang.isNumber(p_nItemIndex)) {
  3585. aGroup = this._getItemGroup(p_nGroupIndex);
  3586. if (aGroup) {
  3587. returnVal = aGroup[p_nItemIndex];
  3588. }
  3589. }
  3590. return returnVal;
  3591. },
  3592. /**
  3593. * @method getSubmenus
  3594. * @description Returns an array of all of the submenus that are immediate
  3595. * children of the menu.
  3596. * @return {Array}
  3597. */
  3598. getSubmenus: function () {
  3599. var aItems = this.getItems(),
  3600. nItems = aItems.length,
  3601. aSubmenus,
  3602. oSubmenu,
  3603. oItem,
  3604. i;
  3605. if (nItems > 0) {
  3606. aSubmenus = [];
  3607. for(i=0; i<nItems; i++) {
  3608. oItem = aItems[i];
  3609. if (oItem) {
  3610. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  3611. if (oSubmenu) {
  3612. aSubmenus[aSubmenus.length] = oSubmenu;
  3613. }
  3614. }
  3615. }
  3616. }
  3617. return aSubmenus;
  3618. },
  3619. /**
  3620. * @method clearContent
  3621. * @description Removes all of the content from the menu, including the menu
  3622. * items, group titles, header and footer.
  3623. */
  3624. clearContent: function () {
  3625. var aItems = this.getItems(),
  3626. nItems = aItems.length,
  3627. oElement = this.element,
  3628. oBody = this.body,
  3629. oHeader = this.header,
  3630. oFooter = this.footer,
  3631. oItem,
  3632. oSubmenu,
  3633. i;
  3634. if (nItems > 0) {
  3635. i = nItems - 1;
  3636. do {
  3637. oItem = aItems[i];
  3638. if (oItem) {
  3639. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  3640. if (oSubmenu) {
  3641. this.cfg.configChangedEvent.unsubscribe(
  3642. this._onParentMenuConfigChange, oSubmenu);
  3643. this.renderEvent.unsubscribe(this._onParentMenuRender,
  3644. oSubmenu);
  3645. }
  3646. this.removeItem(oItem, oItem.groupIndex);
  3647. }
  3648. }
  3649. while (i--);
  3650. }
  3651. if (oHeader) {
  3652. Event.purgeElement(oHeader);
  3653. oElement.removeChild(oHeader);
  3654. }
  3655. if (oFooter) {
  3656. Event.purgeElement(oFooter);
  3657. oElement.removeChild(oFooter);
  3658. }
  3659. if (oBody) {
  3660. Event.purgeElement(oBody);
  3661. oBody.innerHTML = _EMPTY_STRING;
  3662. }
  3663. this.activeItem = null;
  3664. this._aItemGroups = [];
  3665. this._aListElements = [];
  3666. this._aGroupTitleElements = [];
  3667. this.cfg.setProperty(_WIDTH, null);
  3668. },
  3669. /**
  3670. * @method destroy
  3671. * @description Removes the menu's <code>&#60;div&#62;</code> element
  3672. * (and accompanying child nodes) from the document.
  3673. */
  3674. destroy: function () {
  3675. // Remove all items
  3676. this.clearContent();
  3677. this._aItemGroups = null;
  3678. this._aListElements = null;
  3679. this._aGroupTitleElements = null;
  3680. // Continue with the superclass implementation of this method
  3681. Menu.superclass.destroy.call(this);
  3682. YAHOO.log("Destroyed.", "info", this.toString());
  3683. },
  3684. /**
  3685. * @method setInitialFocus
  3686. * @description Sets focus to the menu's first enabled item.
  3687. */
  3688. setInitialFocus: function () {
  3689. var oItem = this._getFirstEnabledItem();
  3690. if (oItem) {
  3691. oItem.focus();
  3692. }
  3693. },
  3694. /**
  3695. * @method setInitialSelection
  3696. * @description Sets the "selected" configuration property of the menu's first
  3697. * enabled item to "true."
  3698. */
  3699. setInitialSelection: function () {
  3700. var oItem = this._getFirstEnabledItem();
  3701. if (oItem) {
  3702. oItem.cfg.setProperty(_SELECTED, true);
  3703. }
  3704. },
  3705. /**
  3706. * @method clearActiveItem
  3707. * @description Sets the "selected" configuration property of the menu's active
  3708. * item to "false" and hides the item's submenu.
  3709. * @param {Boolean} p_bBlur Boolean indicating if the menu's active item
  3710. * should be blurred.
  3711. */
  3712. clearActiveItem: function (p_bBlur) {
  3713. if (this.cfg.getProperty(_SHOW_DELAY) > 0) {
  3714. this._cancelShowDelay();
  3715. }
  3716. var oActiveItem = this.activeItem,
  3717. oConfig,
  3718. oSubmenu;
  3719. if (oActiveItem) {
  3720. oConfig = oActiveItem.cfg;
  3721. if (p_bBlur) {
  3722. oActiveItem.blur();
  3723. this.getRoot()._hasFocus = true;
  3724. }
  3725. oConfig.setProperty(_SELECTED, false);
  3726. oSubmenu = oConfig.getProperty(_SUBMENU);
  3727. if (oSubmenu) {
  3728. oSubmenu.hide();
  3729. }
  3730. this.activeItem = null;
  3731. }
  3732. },
  3733. /**
  3734. * @method focus
  3735. * @description Causes the menu to receive focus and fires the "focus" event.
  3736. */
  3737. focus: function () {
  3738. if (!this.hasFocus()) {
  3739. this.setInitialFocus();
  3740. }
  3741. },
  3742. /**
  3743. * @method blur
  3744. * @description Causes the menu to lose focus and fires the "blur" event.
  3745. */
  3746. blur: function () {
  3747. var oItem;
  3748. if (this.hasFocus()) {
  3749. oItem = MenuManager.getFocusedMenuItem();
  3750. if (oItem) {
  3751. oItem.blur();
  3752. }
  3753. }
  3754. },
  3755. /**
  3756. * @method hasFocus
  3757. * @description Returns a boolean indicating whether or not the menu has focus.
  3758. * @return {Boolean}
  3759. */
  3760. hasFocus: function () {
  3761. return (MenuManager.getFocusedMenu() == this.getRoot());
  3762. },
  3763. _doItemSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
  3764. var oItem = p_aArgs[0],
  3765. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  3766. if (oSubmenu) {
  3767. oSubmenu.subscribe.apply(oSubmenu, p_oObject);
  3768. }
  3769. },
  3770. _doSubmenuSubscribe: function (p_sType, p_aArgs, p_oObject) {
  3771. var oSubmenu = this.cfg.getProperty(_SUBMENU);
  3772. if (oSubmenu) {
  3773. oSubmenu.subscribe.apply(oSubmenu, p_oObject);
  3774. }
  3775. },
  3776. /**
  3777. * Adds the specified CustomEvent subscriber to the menu and each of
  3778. * its submenus.
  3779. * @method subscribe
  3780. * @param p_type {string} the type, or name of the event
  3781. * @param p_fn {function} the function to exectute when the event fires
  3782. * @param p_obj {Object} An object to be passed along when the event
  3783. * fires
  3784. * @param p_override {boolean} If true, the obj passed in becomes the
  3785. * execution scope of the listener
  3786. */
  3787. subscribe: function () {
  3788. // Subscribe to the event for this Menu instance
  3789. Menu.superclass.subscribe.apply(this, arguments);
  3790. // Subscribe to the "itemAdded" event so that all future submenus
  3791. // also subscribe to this event
  3792. Menu.superclass.subscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
  3793. var aItems = this.getItems(),
  3794. nItems,
  3795. oItem,
  3796. oSubmenu,
  3797. i;
  3798. if (aItems) {
  3799. nItems = aItems.length;
  3800. if (nItems > 0) {
  3801. i = nItems - 1;
  3802. do {
  3803. oItem = aItems[i];
  3804. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  3805. if (oSubmenu) {
  3806. oSubmenu.subscribe.apply(oSubmenu, arguments);
  3807. }
  3808. else {
  3809. oItem.cfg.subscribeToConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
  3810. }
  3811. }
  3812. while (i--);
  3813. }
  3814. }
  3815. },
  3816. unsubscribe: function () {
  3817. // Remove the event for this Menu instance
  3818. Menu.superclass.unsubscribe.apply(this, arguments);
  3819. // Remove the "itemAdded" event so that all future submenus don't have
  3820. // the event handler
  3821. Menu.superclass.unsubscribe.call(this, _ITEM_ADDED, this._doItemSubmenuSubscribe, arguments);
  3822. var aItems = this.getItems(),
  3823. nItems,
  3824. oItem,
  3825. oSubmenu,
  3826. i;
  3827. if (aItems) {
  3828. nItems = aItems.length;
  3829. if (nItems > 0) {
  3830. i = nItems - 1;
  3831. do {
  3832. oItem = aItems[i];
  3833. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  3834. if (oSubmenu) {
  3835. oSubmenu.unsubscribe.apply(oSubmenu, arguments);
  3836. }
  3837. else {
  3838. oItem.cfg.unsubscribeFromConfigEvent(_SUBMENU, this._doSubmenuSubscribe, arguments);
  3839. }
  3840. }
  3841. while (i--);
  3842. }
  3843. }
  3844. },
  3845. /**
  3846. * @description Initializes the class's configurable properties which can be
  3847. * changed using the menu's Config object ("cfg").
  3848. * @method initDefaultConfig
  3849. */
  3850. initDefaultConfig: function () {
  3851. Menu.superclass.initDefaultConfig.call(this);
  3852. var oConfig = this.cfg;
  3853. // Module documentation overrides
  3854. /**
  3855. * @config effect
  3856. * @description Object or array of objects representing the ContainerEffect
  3857. * classes that are active for animating the container. When set this
  3858. * property is automatically applied to all submenus.
  3859. * @type Object
  3860. * @default null
  3861. */
  3862. // Overlay documentation overrides
  3863. /**
  3864. * @config x
  3865. * @description Number representing the absolute x-coordinate position of
  3866. * the Menu. This property is only applied when the "position"
  3867. * configuration property is set to dynamic.
  3868. * @type Number
  3869. * @default null
  3870. */
  3871. /**
  3872. * @config y
  3873. * @description Number representing the absolute y-coordinate position of
  3874. * the Menu. This property is only applied when the "position"
  3875. * configuration property is set to dynamic.
  3876. * @type Number
  3877. * @default null
  3878. */
  3879. /**
  3880. * @description Array of the absolute x and y positions of the Menu. This
  3881. * property is only applied when the "position" configuration property is
  3882. * set to dynamic.
  3883. * @config xy
  3884. * @type Number[]
  3885. * @default null
  3886. */
  3887. /**
  3888. * @config context
  3889. * @description Array of context arguments for context-sensitive positioning.
  3890. * The format is: [id or element, element corner, context corner].
  3891. * For example, setting this property to ["img1", "tl", "bl"] would
  3892. * align the Menu's top left corner to the context element's
  3893. * bottom left corner. This property is only applied when the "position"
  3894. * configuration property is set to dynamic.
  3895. * @type Array
  3896. * @default null
  3897. */
  3898. /**
  3899. * @config fixedcenter
  3900. * @description Boolean indicating if the Menu should be anchored to the
  3901. * center of the viewport. This property is only applied when the
  3902. * "position" configuration property is set to dynamic.
  3903. * @type Boolean
  3904. * @default false
  3905. */
  3906. /**
  3907. * @config iframe
  3908. * @description Boolean indicating whether or not the Menu should
  3909. * have an IFRAME shim; used to prevent SELECT elements from
  3910. * poking through an Overlay instance in IE6. When set to "true",
  3911. * the iframe shim is created when the Menu instance is intially
  3912. * made visible. This property is only applied when the "position"
  3913. * configuration property is set to dynamic and is automatically applied
  3914. * to all submenus.
  3915. * @type Boolean
  3916. * @default true for IE6 and below, false for all other browsers.
  3917. */
  3918. // Add configuration attributes
  3919. /*
  3920. Change the default value for the "visible" configuration
  3921. property to "false" by re-adding the property.
  3922. */
  3923. /**
  3924. * @config visible
  3925. * @description Boolean indicating whether or not the menu is visible. If
  3926. * the menu's "position" configuration property is set to "dynamic" (the
  3927. * default), this property toggles the menu's <code>&#60;div&#62;</code>
  3928. * element's "visibility" style property between "visible" (true) or
  3929. * "hidden" (false). If the menu's "position" configuration property is
  3930. * set to "static" this property toggles the menu's
  3931. * <code>&#60;div&#62;</code> element's "display" style property
  3932. * between "block" (true) or "none" (false).
  3933. * @default false
  3934. * @type Boolean
  3935. */
  3936. oConfig.addProperty(
  3937. VISIBLE_CONFIG.key,
  3938. {
  3939. handler: this.configVisible,
  3940. value: VISIBLE_CONFIG.value,
  3941. validator: VISIBLE_CONFIG.validator
  3942. }
  3943. );
  3944. /*
  3945. Change the default value for the "constraintoviewport" configuration
  3946. property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
  3947. */
  3948. /**
  3949. * @config constraintoviewport
  3950. * @description Boolean indicating if the menu will try to remain inside
  3951. * the boundaries of the size of viewport. This property is only applied
  3952. * when the "position" configuration property is set to dynamic and is
  3953. * automatically applied to all submenus.
  3954. * @default true
  3955. * @type Boolean
  3956. */
  3957. oConfig.addProperty(
  3958. CONSTRAIN_TO_VIEWPORT_CONFIG.key,
  3959. {
  3960. handler: this.configConstrainToViewport,
  3961. value: CONSTRAIN_TO_VIEWPORT_CONFIG.value,
  3962. validator: CONSTRAIN_TO_VIEWPORT_CONFIG.validator,
  3963. supercedes: CONSTRAIN_TO_VIEWPORT_CONFIG.supercedes
  3964. }
  3965. );
  3966. /*
  3967. Change the default value for the "preventcontextoverlap" configuration
  3968. property (inherited by YAHOO.widget.Overlay) to "true" by re-adding the property.
  3969. */
  3970. /**
  3971. * @config preventcontextoverlap
  3972. * @description Boolean indicating whether or not a submenu should overlap its parent MenuItem
  3973. * when the "constraintoviewport" configuration property is set to "true".
  3974. * @type Boolean
  3975. * @default true
  3976. */
  3977. oConfig.addProperty(PREVENT_CONTEXT_OVERLAP_CONFIG.key, {
  3978. value: PREVENT_CONTEXT_OVERLAP_CONFIG.value,
  3979. validator: PREVENT_CONTEXT_OVERLAP_CONFIG.validator,
  3980. supercedes: PREVENT_CONTEXT_OVERLAP_CONFIG.supercedes
  3981. });
  3982. /**
  3983. * @config position
  3984. * @description String indicating how a menu should be positioned on the
  3985. * screen. Possible values are "static" and "dynamic." Static menus are
  3986. * visible by default and reside in the normal flow of the document
  3987. * (CSS position: static). Dynamic menus are hidden by default, reside
  3988. * out of the normal flow of the document (CSS position: absolute), and
  3989. * can overlay other elements on the screen.
  3990. * @default dynamic
  3991. * @type String
  3992. */
  3993. oConfig.addProperty(
  3994. POSITION_CONFIG.key,
  3995. {
  3996. handler: this.configPosition,
  3997. value: POSITION_CONFIG.value,
  3998. validator: POSITION_CONFIG.validator,
  3999. supercedes: POSITION_CONFIG.supercedes
  4000. }
  4001. );
  4002. /**
  4003. * @config submenualignment
  4004. * @description Array defining how submenus should be aligned to their
  4005. * parent menu item. The format is: [itemCorner, submenuCorner]. By default
  4006. * a submenu's top left corner is aligned to its parent menu item's top
  4007. * right corner.
  4008. * @default ["tl","tr"]
  4009. * @type Array
  4010. */
  4011. oConfig.addProperty(
  4012. SUBMENU_ALIGNMENT_CONFIG.key,
  4013. {
  4014. value: SUBMENU_ALIGNMENT_CONFIG.value,
  4015. suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
  4016. }
  4017. );
  4018. /**
  4019. * @config autosubmenudisplay
  4020. * @description Boolean indicating if submenus are automatically made
  4021. * visible when the user mouses over the menu's items.
  4022. * @default true
  4023. * @type Boolean
  4024. */
  4025. oConfig.addProperty(
  4026. AUTO_SUBMENU_DISPLAY_CONFIG.key,
  4027. {
  4028. value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
  4029. validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
  4030. suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
  4031. }
  4032. );
  4033. /**
  4034. * @config showdelay
  4035. * @description Number indicating the time (in milliseconds) that should
  4036. * expire before a submenu is made visible when the user mouses over
  4037. * the menu's items. This property is only applied when the "position"
  4038. * configuration property is set to dynamic and is automatically applied
  4039. * to all submenus.
  4040. * @default 250
  4041. * @type Number
  4042. */
  4043. oConfig.addProperty(
  4044. SHOW_DELAY_CONFIG.key,
  4045. {
  4046. value: SHOW_DELAY_CONFIG.value,
  4047. validator: SHOW_DELAY_CONFIG.validator,
  4048. suppressEvent: SHOW_DELAY_CONFIG.suppressEvent
  4049. }
  4050. );
  4051. /**
  4052. * @config hidedelay
  4053. * @description Number indicating the time (in milliseconds) that should
  4054. * expire before the menu is hidden. This property is only applied when
  4055. * the "position" configuration property is set to dynamic and is
  4056. * automatically applied to all submenus.
  4057. * @default 0
  4058. * @type Number
  4059. */
  4060. oConfig.addProperty(
  4061. HIDE_DELAY_CONFIG.key,
  4062. {
  4063. handler: this.configHideDelay,
  4064. value: HIDE_DELAY_CONFIG.value,
  4065. validator: HIDE_DELAY_CONFIG.validator,
  4066. suppressEvent: HIDE_DELAY_CONFIG.suppressEvent
  4067. }
  4068. );
  4069. /**
  4070. * @config submenuhidedelay
  4071. * @description Number indicating the time (in milliseconds) that should
  4072. * expire before a submenu is hidden when the user mouses out of a menu item
  4073. * heading in the direction of a submenu. The value must be greater than or
  4074. * equal to the value specified for the "showdelay" configuration property.
  4075. * This property is only applied when the "position" configuration property
  4076. * is set to dynamic and is automatically applied to all submenus.
  4077. * @default 250
  4078. * @type Number
  4079. */
  4080. oConfig.addProperty(
  4081. SUBMENU_HIDE_DELAY_CONFIG.key,
  4082. {
  4083. value: SUBMENU_HIDE_DELAY_CONFIG.value,
  4084. validator: SUBMENU_HIDE_DELAY_CONFIG.validator,
  4085. suppressEvent: SUBMENU_HIDE_DELAY_CONFIG.suppressEvent
  4086. }
  4087. );
  4088. /**
  4089. * @config clicktohide
  4090. * @description Boolean indicating if the menu will automatically be
  4091. * hidden if the user clicks outside of it. This property is only
  4092. * applied when the "position" configuration property is set to dynamic
  4093. * and is automatically applied to all submenus.
  4094. * @default true
  4095. * @type Boolean
  4096. */
  4097. oConfig.addProperty(
  4098. CLICK_TO_HIDE_CONFIG.key,
  4099. {
  4100. value: CLICK_TO_HIDE_CONFIG.value,
  4101. validator: CLICK_TO_HIDE_CONFIG.validator,
  4102. suppressEvent: CLICK_TO_HIDE_CONFIG.suppressEvent
  4103. }
  4104. );
  4105. /**
  4106. * @config container
  4107. * @description HTML element reference or string specifying the id
  4108. * attribute of the HTML element that the menu's markup should be
  4109. * rendered into.
  4110. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  4111. * level-one-html.html#ID-58190037">HTMLElement</a>|String
  4112. * @default document.body
  4113. */
  4114. oConfig.addProperty(
  4115. CONTAINER_CONFIG.key,
  4116. {
  4117. handler: this.configContainer,
  4118. value: document.body,
  4119. suppressEvent: CONTAINER_CONFIG.suppressEvent
  4120. }
  4121. );
  4122. /**
  4123. * @config scrollincrement
  4124. * @description Number used to control the scroll speed of a menu. Used to
  4125. * increment the "scrollTop" property of the menu's body by when a menu's
  4126. * content is scrolling. When set this property is automatically applied
  4127. * to all submenus.
  4128. * @default 1
  4129. * @type Number
  4130. */
  4131. oConfig.addProperty(
  4132. SCROLL_INCREMENT_CONFIG.key,
  4133. {
  4134. value: SCROLL_INCREMENT_CONFIG.value,
  4135. validator: SCROLL_INCREMENT_CONFIG.validator,
  4136. supercedes: SCROLL_INCREMENT_CONFIG.supercedes,
  4137. suppressEvent: SCROLL_INCREMENT_CONFIG.suppressEvent
  4138. }
  4139. );
  4140. /**
  4141. * @config minscrollheight
  4142. * @description Number defining the minimum threshold for the "maxheight"
  4143. * configuration property. When set this property is automatically applied
  4144. * to all submenus.
  4145. * @default 90
  4146. * @type Number
  4147. */
  4148. oConfig.addProperty(
  4149. MIN_SCROLL_HEIGHT_CONFIG.key,
  4150. {
  4151. value: MIN_SCROLL_HEIGHT_CONFIG.value,
  4152. validator: MIN_SCROLL_HEIGHT_CONFIG.validator,
  4153. supercedes: MIN_SCROLL_HEIGHT_CONFIG.supercedes,
  4154. suppressEvent: MIN_SCROLL_HEIGHT_CONFIG.suppressEvent
  4155. }
  4156. );
  4157. /**
  4158. * @config maxheight
  4159. * @description Number defining the maximum height (in pixels) for a menu's
  4160. * body element (<code>&#60;div class="bd"&#62;</code>). Once a menu's body
  4161. * exceeds this height, the contents of the body are scrolled to maintain
  4162. * this value. This value cannot be set lower than the value of the
  4163. * "minscrollheight" configuration property.
  4164. * @default 0
  4165. * @type Number
  4166. */
  4167. oConfig.addProperty(
  4168. MAX_HEIGHT_CONFIG.key,
  4169. {
  4170. handler: this.configMaxHeight,
  4171. value: MAX_HEIGHT_CONFIG.value,
  4172. validator: MAX_HEIGHT_CONFIG.validator,
  4173. suppressEvent: MAX_HEIGHT_CONFIG.suppressEvent,
  4174. supercedes: MAX_HEIGHT_CONFIG.supercedes
  4175. }
  4176. );
  4177. /**
  4178. * @config classname
  4179. * @description String representing the CSS class to be applied to the
  4180. * menu's root <code>&#60;div&#62;</code> element. The specified class(es)
  4181. * are appended in addition to the default class as specified by the menu's
  4182. * CSS_CLASS_NAME constant. When set this property is automatically
  4183. * applied to all submenus.
  4184. * @default null
  4185. * @type String
  4186. */
  4187. oConfig.addProperty(
  4188. CLASS_NAME_CONFIG.key,
  4189. {
  4190. handler: this.configClassName,
  4191. value: CLASS_NAME_CONFIG.value,
  4192. validator: CLASS_NAME_CONFIG.validator,
  4193. supercedes: CLASS_NAME_CONFIG.supercedes
  4194. }
  4195. );
  4196. /**
  4197. * @config disabled
  4198. * @description Boolean indicating if the menu should be disabled.
  4199. * Disabling a menu disables each of its items. (Disabled menu items are
  4200. * dimmed and will not respond to user input or fire events.) Disabled
  4201. * menus have a corresponding "disabled" CSS class applied to their root
  4202. * <code>&#60;div&#62;</code> element.
  4203. * @default false
  4204. * @type Boolean
  4205. */
  4206. oConfig.addProperty(
  4207. DISABLED_CONFIG.key,
  4208. {
  4209. handler: this.configDisabled,
  4210. value: DISABLED_CONFIG.value,
  4211. validator: DISABLED_CONFIG.validator,
  4212. suppressEvent: DISABLED_CONFIG.suppressEvent
  4213. }
  4214. );
  4215. /**
  4216. * @config shadow
  4217. * @description Boolean indicating if the menu should have a shadow.
  4218. * @default true
  4219. * @type Boolean
  4220. */
  4221. oConfig.addProperty(
  4222. SHADOW_CONFIG.key,
  4223. {
  4224. handler: this.configShadow,
  4225. value: SHADOW_CONFIG.value,
  4226. validator: SHADOW_CONFIG.validator
  4227. }
  4228. );
  4229. /**
  4230. * @config keepopen
  4231. * @description Boolean indicating if the menu should remain open when clicked.
  4232. * @default false
  4233. * @type Boolean
  4234. */
  4235. oConfig.addProperty(
  4236. KEEP_OPEN_CONFIG.key,
  4237. {
  4238. value: KEEP_OPEN_CONFIG.value,
  4239. validator: KEEP_OPEN_CONFIG.validator
  4240. }
  4241. );
  4242. }
  4243. }); // END YAHOO.lang.extend
  4244. })();
  4245. (function () {
  4246. /**
  4247. * Creates an item for a menu.
  4248. *
  4249. * @param {String} p_oObject String specifying the text of the menu item.
  4250. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4251. * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
  4252. * the <code>&#60;li&#62;</code> element of the menu item.
  4253. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4254. * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
  4255. * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
  4256. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4257. * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
  4258. * specifying the <code>&#60;option&#62;</code> element of the menu item.
  4259. * @param {Object} p_oConfig Optional. Object literal specifying the
  4260. * configuration for the menu item. See configuration class documentation
  4261. * for more details.
  4262. * @class MenuItem
  4263. * @constructor
  4264. */
  4265. YAHOO.widget.MenuItem = function (p_oObject, p_oConfig) {
  4266. if (p_oObject) {
  4267. if (p_oConfig) {
  4268. this.parent = p_oConfig.parent;
  4269. this.value = p_oConfig.value;
  4270. this.id = p_oConfig.id;
  4271. }
  4272. this.init(p_oObject, p_oConfig);
  4273. }
  4274. };
  4275. var Dom = YAHOO.util.Dom,
  4276. Module = YAHOO.widget.Module,
  4277. Menu = YAHOO.widget.Menu,
  4278. MenuItem = YAHOO.widget.MenuItem,
  4279. CustomEvent = YAHOO.util.CustomEvent,
  4280. UA = YAHOO.env.ua,
  4281. Lang = YAHOO.lang,
  4282. // Private string constants
  4283. _TEXT = "text",
  4284. _HASH = "#",
  4285. _HYPHEN = "-",
  4286. _HELP_TEXT = "helptext",
  4287. _URL = "url",
  4288. _TARGET = "target",
  4289. _EMPHASIS = "emphasis",
  4290. _STRONG_EMPHASIS = "strongemphasis",
  4291. _CHECKED = "checked",
  4292. _SUBMENU = "submenu",
  4293. _DISABLED = "disabled",
  4294. _SELECTED = "selected",
  4295. _HAS_SUBMENU = "hassubmenu",
  4296. _CHECKED_DISABLED = "checked-disabled",
  4297. _HAS_SUBMENU_DISABLED = "hassubmenu-disabled",
  4298. _HAS_SUBMENU_SELECTED = "hassubmenu-selected",
  4299. _CHECKED_SELECTED = "checked-selected",
  4300. _ONCLICK = "onclick",
  4301. _CLASSNAME = "classname",
  4302. _EMPTY_STRING = "",
  4303. _OPTION = "OPTION",
  4304. _OPTGROUP = "OPTGROUP",
  4305. _LI_UPPERCASE = "LI",
  4306. _HREF = "href",
  4307. _SELECT = "SELECT",
  4308. _DIV = "DIV",
  4309. _START_HELP_TEXT = "<em class=\"helptext\">",
  4310. _START_EM = "<em>",
  4311. _END_EM = "</em>",
  4312. _START_STRONG = "<strong>",
  4313. _END_STRONG = "</strong>",
  4314. _PREVENT_CONTEXT_OVERLAP = "preventcontextoverlap",
  4315. _OBJ = "obj",
  4316. _SCOPE = "scope",
  4317. _NONE = "none",
  4318. _VISIBLE = "visible",
  4319. _SPACE = " ",
  4320. _MENUITEM = "MenuItem",
  4321. _CLICK = "click",
  4322. _SHOW = "show",
  4323. _HIDE = "hide",
  4324. _LI_LOWERCASE = "li",
  4325. _ANCHOR_TEMPLATE = "<a href=\"#\"></a>",
  4326. EVENT_TYPES = [
  4327. ["mouseOverEvent", "mouseover"],
  4328. ["mouseOutEvent", "mouseout"],
  4329. ["mouseDownEvent", "mousedown"],
  4330. ["mouseUpEvent", "mouseup"],
  4331. ["clickEvent", _CLICK],
  4332. ["keyPressEvent", "keypress"],
  4333. ["keyDownEvent", "keydown"],
  4334. ["keyUpEvent", "keyup"],
  4335. ["focusEvent", "focus"],
  4336. ["blurEvent", "blur"],
  4337. ["destroyEvent", "destroy"]
  4338. ],
  4339. TEXT_CONFIG = {
  4340. key: _TEXT,
  4341. value: _EMPTY_STRING,
  4342. validator: Lang.isString,
  4343. suppressEvent: true
  4344. },
  4345. HELP_TEXT_CONFIG = {
  4346. key: _HELP_TEXT,
  4347. supercedes: [_TEXT],
  4348. suppressEvent: true
  4349. },
  4350. URL_CONFIG = {
  4351. key: _URL,
  4352. value: _HASH,
  4353. suppressEvent: true
  4354. },
  4355. TARGET_CONFIG = {
  4356. key: _TARGET,
  4357. suppressEvent: true
  4358. },
  4359. EMPHASIS_CONFIG = {
  4360. key: _EMPHASIS,
  4361. value: false,
  4362. validator: Lang.isBoolean,
  4363. suppressEvent: true,
  4364. supercedes: [_TEXT]
  4365. },
  4366. STRONG_EMPHASIS_CONFIG = {
  4367. key: _STRONG_EMPHASIS,
  4368. value: false,
  4369. validator: Lang.isBoolean,
  4370. suppressEvent: true,
  4371. supercedes: [_TEXT]
  4372. },
  4373. CHECKED_CONFIG = {
  4374. key: _CHECKED,
  4375. value: false,
  4376. validator: Lang.isBoolean,
  4377. suppressEvent: true,
  4378. supercedes: [_DISABLED, _SELECTED]
  4379. },
  4380. SUBMENU_CONFIG = {
  4381. key: _SUBMENU,
  4382. suppressEvent: true,
  4383. supercedes: [_DISABLED, _SELECTED]
  4384. },
  4385. DISABLED_CONFIG = {
  4386. key: _DISABLED,
  4387. value: false,
  4388. validator: Lang.isBoolean,
  4389. suppressEvent: true,
  4390. supercedes: [_TEXT, _SELECTED]
  4391. },
  4392. SELECTED_CONFIG = {
  4393. key: _SELECTED,
  4394. value: false,
  4395. validator: Lang.isBoolean,
  4396. suppressEvent: true
  4397. },
  4398. ONCLICK_CONFIG = {
  4399. key: _ONCLICK,
  4400. suppressEvent: true
  4401. },
  4402. CLASS_NAME_CONFIG = {
  4403. key: _CLASSNAME,
  4404. value: null,
  4405. validator: Lang.isString,
  4406. suppressEvent: true
  4407. },
  4408. KEY_LISTENER_CONFIG = {
  4409. key: "keylistener",
  4410. value: null,
  4411. suppressEvent: true
  4412. },
  4413. m_oMenuItemTemplate = null,
  4414. CLASS_NAMES = {};
  4415. /**
  4416. * @method getClassNameForState
  4417. * @description Returns a class name for the specified prefix and state. If the class name does not
  4418. * yet exist, it is created and stored in the CLASS_NAMES object to increase performance.
  4419. * @private
  4420. * @param {String} prefix String representing the prefix for the class name
  4421. * @param {String} state String representing a state - "disabled," "checked," etc.
  4422. */
  4423. var getClassNameForState = function (prefix, state) {
  4424. var oClassNames = CLASS_NAMES[prefix];
  4425. if (!oClassNames) {
  4426. CLASS_NAMES[prefix] = {};
  4427. oClassNames = CLASS_NAMES[prefix];
  4428. }
  4429. var sClassName = oClassNames[state];
  4430. if (!sClassName) {
  4431. sClassName = prefix + _HYPHEN + state;
  4432. oClassNames[state] = sClassName;
  4433. }
  4434. return sClassName;
  4435. };
  4436. /**
  4437. * @method addClassNameForState
  4438. * @description Applies a class name to a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
  4439. * that represents a MenuItem's state - "disabled," "checked," etc.
  4440. * @private
  4441. * @param {String} state String representing a state - "disabled," "checked," etc.
  4442. */
  4443. var addClassNameForState = function (state) {
  4444. Dom.addClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
  4445. Dom.addClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
  4446. };
  4447. /**
  4448. * @method removeClassNameForState
  4449. * @description Removes a class name from a MenuItem instance's &#60;LI&#62; and &#60;A&#62; elements
  4450. * that represents a MenuItem's state - "disabled," "checked," etc.
  4451. * @private
  4452. * @param {String} state String representing a state - "disabled," "checked," etc.
  4453. */
  4454. var removeClassNameForState = function (state) {
  4455. Dom.removeClass(this.element, getClassNameForState(this.CSS_CLASS_NAME, state));
  4456. Dom.removeClass(this._oAnchor, getClassNameForState(this.CSS_LABEL_CLASS_NAME, state));
  4457. };
  4458. MenuItem.prototype = {
  4459. /**
  4460. * @property CSS_CLASS_NAME
  4461. * @description String representing the CSS class(es) to be applied to the
  4462. * <code>&#60;li&#62;</code> element of the menu item.
  4463. * @default "yuimenuitem"
  4464. * @final
  4465. * @type String
  4466. */
  4467. CSS_CLASS_NAME: "yuimenuitem",
  4468. /**
  4469. * @property CSS_LABEL_CLASS_NAME
  4470. * @description String representing the CSS class(es) to be applied to the
  4471. * menu item's <code>&#60;a&#62;</code> element.
  4472. * @default "yuimenuitemlabel"
  4473. * @final
  4474. * @type String
  4475. */
  4476. CSS_LABEL_CLASS_NAME: "yuimenuitemlabel",
  4477. /**
  4478. * @property SUBMENU_TYPE
  4479. * @description Object representing the type of menu to instantiate and
  4480. * add when parsing the child nodes of the menu item's source HTML element.
  4481. * @final
  4482. * @type YAHOO.widget.Menu
  4483. */
  4484. SUBMENU_TYPE: null,
  4485. // Private member variables
  4486. /**
  4487. * @property _oAnchor
  4488. * @description Object reference to the menu item's
  4489. * <code>&#60;a&#62;</code> element.
  4490. * @default null
  4491. * @private
  4492. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4493. * one-html.html#ID-48250443">HTMLAnchorElement</a>
  4494. */
  4495. _oAnchor: null,
  4496. /**
  4497. * @property _oHelpTextEM
  4498. * @description Object reference to the menu item's help text
  4499. * <code>&#60;em&#62;</code> element.
  4500. * @default null
  4501. * @private
  4502. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4503. * one-html.html#ID-58190037">HTMLElement</a>
  4504. */
  4505. _oHelpTextEM: null,
  4506. /**
  4507. * @property _oSubmenu
  4508. * @description Object reference to the menu item's submenu.
  4509. * @default null
  4510. * @private
  4511. * @type YAHOO.widget.Menu
  4512. */
  4513. _oSubmenu: null,
  4514. /**
  4515. * @property _oOnclickAttributeValue
  4516. * @description Object reference to the menu item's current value for the
  4517. * "onclick" configuration attribute.
  4518. * @default null
  4519. * @private
  4520. * @type Object
  4521. */
  4522. _oOnclickAttributeValue: null,
  4523. /**
  4524. * @property _sClassName
  4525. * @description The current value of the "classname" configuration attribute.
  4526. * @default null
  4527. * @private
  4528. * @type String
  4529. */
  4530. _sClassName: null,
  4531. // Public properties
  4532. /**
  4533. * @property constructor
  4534. * @description Object reference to the menu item's constructor function.
  4535. * @default YAHOO.widget.MenuItem
  4536. * @type YAHOO.widget.MenuItem
  4537. */
  4538. constructor: MenuItem,
  4539. /**
  4540. * @property index
  4541. * @description Number indicating the ordinal position of the menu item in
  4542. * its group.
  4543. * @default null
  4544. * @type Number
  4545. */
  4546. index: null,
  4547. /**
  4548. * @property groupIndex
  4549. * @description Number indicating the index of the group to which the menu
  4550. * item belongs.
  4551. * @default null
  4552. * @type Number
  4553. */
  4554. groupIndex: null,
  4555. /**
  4556. * @property parent
  4557. * @description Object reference to the menu item's parent menu.
  4558. * @default null
  4559. * @type YAHOO.widget.Menu
  4560. */
  4561. parent: null,
  4562. /**
  4563. * @property element
  4564. * @description Object reference to the menu item's
  4565. * <code>&#60;li&#62;</code> element.
  4566. * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level
  4567. * -one-html.html#ID-74680021">HTMLLIElement</a>
  4568. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4569. * one-html.html#ID-74680021">HTMLLIElement</a>
  4570. */
  4571. element: null,
  4572. /**
  4573. * @property srcElement
  4574. * @description Object reference to the HTML element (either
  4575. * <code>&#60;li&#62;</code>, <code>&#60;optgroup&#62;</code> or
  4576. * <code>&#60;option&#62;</code>) used create the menu item.
  4577. * @default <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  4578. * level-one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.
  4579. * w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247"
  4580. * >HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
  4581. * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
  4582. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4583. * one-html.html#ID-74680021">HTMLLIElement</a>|<a href="http://www.w3.
  4584. * org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-38450247">
  4585. * HTMLOptGroupElement</a>|<a href="http://www.w3.org/TR/2000/WD-DOM-
  4586. * Level-1-20000929/level-one-html.html#ID-70901257">HTMLOptionElement</a>
  4587. */
  4588. srcElement: null,
  4589. /**
  4590. * @property value
  4591. * @description Object reference to the menu item's value.
  4592. * @default null
  4593. * @type Object
  4594. */
  4595. value: null,
  4596. /**
  4597. * @property browser
  4598. * @deprecated Use YAHOO.env.ua
  4599. * @description String representing the browser.
  4600. * @type String
  4601. */
  4602. browser: Module.prototype.browser,
  4603. /**
  4604. * @property id
  4605. * @description Id of the menu item's root <code>&#60;li&#62;</code>
  4606. * element. This property should be set via the constructor using the
  4607. * configuration object literal. If an id is not specified, then one will
  4608. * be created using the "generateId" method of the Dom utility.
  4609. * @default null
  4610. * @type String
  4611. */
  4612. id: null,
  4613. // Events
  4614. /**
  4615. * @event destroyEvent
  4616. * @description Fires when the menu item's <code>&#60;li&#62;</code>
  4617. * element is removed from its parent <code>&#60;ul&#62;</code> element.
  4618. * @type YAHOO.util.CustomEvent
  4619. */
  4620. /**
  4621. * @event mouseOverEvent
  4622. * @description Fires when the mouse has entered the menu item. Passes
  4623. * back the DOM Event object as an argument.
  4624. * @type YAHOO.util.CustomEvent
  4625. */
  4626. /**
  4627. * @event mouseOutEvent
  4628. * @description Fires when the mouse has left the menu item. Passes back
  4629. * the DOM Event object as an argument.
  4630. * @type YAHOO.util.CustomEvent
  4631. */
  4632. /**
  4633. * @event mouseDownEvent
  4634. * @description Fires when the user mouses down on the menu item. Passes
  4635. * back the DOM Event object as an argument.
  4636. * @type YAHOO.util.CustomEvent
  4637. */
  4638. /**
  4639. * @event mouseUpEvent
  4640. * @description Fires when the user releases a mouse button while the mouse
  4641. * is over the menu item. Passes back the DOM Event object as an argument.
  4642. * @type YAHOO.util.CustomEvent
  4643. */
  4644. /**
  4645. * @event clickEvent
  4646. * @description Fires when the user clicks the on the menu item. Passes
  4647. * back the DOM Event object as an argument.
  4648. * @type YAHOO.util.CustomEvent
  4649. */
  4650. /**
  4651. * @event keyPressEvent
  4652. * @description Fires when the user presses an alphanumeric key when the
  4653. * menu item has focus. Passes back the DOM Event object as an argument.
  4654. * @type YAHOO.util.CustomEvent
  4655. */
  4656. /**
  4657. * @event keyDownEvent
  4658. * @description Fires when the user presses a key when the menu item has
  4659. * focus. Passes back the DOM Event object as an argument.
  4660. * @type YAHOO.util.CustomEvent
  4661. */
  4662. /**
  4663. * @event keyUpEvent
  4664. * @description Fires when the user releases a key when the menu item has
  4665. * focus. Passes back the DOM Event object as an argument.
  4666. * @type YAHOO.util.CustomEvent
  4667. */
  4668. /**
  4669. * @event focusEvent
  4670. * @description Fires when the menu item receives focus.
  4671. * @type YAHOO.util.CustomEvent
  4672. */
  4673. /**
  4674. * @event blurEvent
  4675. * @description Fires when the menu item loses the input focus.
  4676. * @type YAHOO.util.CustomEvent
  4677. */
  4678. /**
  4679. * @method init
  4680. * @description The MenuItem class's initialization method. This method is
  4681. * automatically called by the constructor, and sets up all DOM references
  4682. * for pre-existing markup, and creates required markup if it is not
  4683. * already present.
  4684. * @param {String} p_oObject String specifying the text of the menu item.
  4685. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4686. * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying
  4687. * the <code>&#60;li&#62;</code> element of the menu item.
  4688. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4689. * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
  4690. * specifying the <code>&#60;optgroup&#62;</code> element of the menu item.
  4691. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  4692. * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object
  4693. * specifying the <code>&#60;option&#62;</code> element of the menu item.
  4694. * @param {Object} p_oConfig Optional. Object literal specifying the
  4695. * configuration for the menu item. See configuration class documentation
  4696. * for more details.
  4697. */
  4698. init: function (p_oObject, p_oConfig) {
  4699. if (!this.SUBMENU_TYPE) {
  4700. this.SUBMENU_TYPE = Menu;
  4701. }
  4702. // Create the config object
  4703. this.cfg = new YAHOO.util.Config(this);
  4704. this.initDefaultConfig();
  4705. var oConfig = this.cfg,
  4706. sURL = _HASH,
  4707. oCustomEvent,
  4708. aEventData,
  4709. oAnchor,
  4710. sTarget,
  4711. sText,
  4712. sId,
  4713. i;
  4714. if (Lang.isString(p_oObject)) {
  4715. this._createRootNodeStructure();
  4716. oConfig.queueProperty(_TEXT, p_oObject);
  4717. }
  4718. else if (p_oObject && p_oObject.tagName) {
  4719. switch(p_oObject.tagName.toUpperCase()) {
  4720. case _OPTION:
  4721. this._createRootNodeStructure();
  4722. oConfig.queueProperty(_TEXT, p_oObject.text);
  4723. oConfig.queueProperty(_DISABLED, p_oObject.disabled);
  4724. this.value = p_oObject.value;
  4725. this.srcElement = p_oObject;
  4726. break;
  4727. case _OPTGROUP:
  4728. this._createRootNodeStructure();
  4729. oConfig.queueProperty(_TEXT, p_oObject.label);
  4730. oConfig.queueProperty(_DISABLED, p_oObject.disabled);
  4731. this.srcElement = p_oObject;
  4732. this._initSubTree();
  4733. break;
  4734. case _LI_UPPERCASE:
  4735. // Get the anchor node (if it exists)
  4736. oAnchor = Dom.getFirstChild(p_oObject);
  4737. // Capture the "text" and/or the "URL"
  4738. if (oAnchor) {
  4739. sURL = oAnchor.getAttribute(_HREF, 2);
  4740. sTarget = oAnchor.getAttribute(_TARGET);
  4741. sText = oAnchor.innerHTML;
  4742. }
  4743. this.srcElement = p_oObject;
  4744. this.element = p_oObject;
  4745. this._oAnchor = oAnchor;
  4746. /*
  4747. Set these properties silently to sync up the
  4748. configuration object without making changes to the
  4749. element's DOM
  4750. */
  4751. oConfig.setProperty(_TEXT, sText, true);
  4752. oConfig.setProperty(_URL, sURL, true);
  4753. oConfig.setProperty(_TARGET, sTarget, true);
  4754. this._initSubTree();
  4755. break;
  4756. }
  4757. }
  4758. if (this.element) {
  4759. sId = (this.srcElement || this.element).id;
  4760. if (!sId) {
  4761. sId = this.id || Dom.generateId();
  4762. this.element.id = sId;
  4763. }
  4764. this.id = sId;
  4765. Dom.addClass(this.element, this.CSS_CLASS_NAME);
  4766. Dom.addClass(this._oAnchor, this.CSS_LABEL_CLASS_NAME);
  4767. i = EVENT_TYPES.length - 1;
  4768. do {
  4769. aEventData = EVENT_TYPES[i];
  4770. oCustomEvent = this.createEvent(aEventData[1]);
  4771. oCustomEvent.signature = CustomEvent.LIST;
  4772. this[aEventData[0]] = oCustomEvent;
  4773. }
  4774. while (i--);
  4775. if (p_oConfig) {
  4776. oConfig.applyConfig(p_oConfig);
  4777. }
  4778. oConfig.fireQueue();
  4779. }
  4780. },
  4781. // Private methods
  4782. /**
  4783. * @method _createRootNodeStructure
  4784. * @description Creates the core DOM structure for the menu item.
  4785. * @private
  4786. */
  4787. _createRootNodeStructure: function () {
  4788. var oElement,
  4789. oAnchor;
  4790. if (!m_oMenuItemTemplate) {
  4791. m_oMenuItemTemplate = document.createElement(_LI_LOWERCASE);
  4792. m_oMenuItemTemplate.innerHTML = _ANCHOR_TEMPLATE;
  4793. }
  4794. oElement = m_oMenuItemTemplate.cloneNode(true);
  4795. oElement.className = this.CSS_CLASS_NAME;
  4796. oAnchor = oElement.firstChild;
  4797. oAnchor.className = this.CSS_LABEL_CLASS_NAME;
  4798. this.element = oElement;
  4799. this._oAnchor = oAnchor;
  4800. },
  4801. /**
  4802. * @method _initSubTree
  4803. * @description Iterates the source element's childNodes collection and uses
  4804. * the child nodes to instantiate other menus.
  4805. * @private
  4806. */
  4807. _initSubTree: function () {
  4808. var oSrcEl = this.srcElement,
  4809. oConfig = this.cfg,
  4810. oNode,
  4811. aOptions,
  4812. nOptions,
  4813. oMenu,
  4814. n;
  4815. if (oSrcEl.childNodes.length > 0) {
  4816. if (this.parent.lazyLoad && this.parent.srcElement &&
  4817. this.parent.srcElement.tagName.toUpperCase() == _SELECT) {
  4818. oConfig.setProperty(
  4819. _SUBMENU,
  4820. { id: Dom.generateId(), itemdata: oSrcEl.childNodes }
  4821. );
  4822. }
  4823. else {
  4824. oNode = oSrcEl.firstChild;
  4825. aOptions = [];
  4826. do {
  4827. if (oNode && oNode.tagName) {
  4828. switch(oNode.tagName.toUpperCase()) {
  4829. case _DIV:
  4830. oConfig.setProperty(_SUBMENU, oNode);
  4831. break;
  4832. case _OPTION:
  4833. aOptions[aOptions.length] = oNode;
  4834. break;
  4835. }
  4836. }
  4837. }
  4838. while((oNode = oNode.nextSibling));
  4839. nOptions = aOptions.length;
  4840. if (nOptions > 0) {
  4841. oMenu = new this.SUBMENU_TYPE(Dom.generateId());
  4842. oConfig.setProperty(_SUBMENU, oMenu);
  4843. for(n=0; n<nOptions; n++) {
  4844. oMenu.addItem((new oMenu.ITEM_TYPE(aOptions[n])));
  4845. }
  4846. }
  4847. }
  4848. }
  4849. },
  4850. // Event handlers for configuration properties
  4851. /**
  4852. * @method configText
  4853. * @description Event handler for when the "text" configuration property of
  4854. * the menu item changes.
  4855. * @param {String} p_sType String representing the name of the event that
  4856. * was fired.
  4857. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4858. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4859. * that fired the event.
  4860. */
  4861. configText: function (p_sType, p_aArgs, p_oItem) {
  4862. var sText = p_aArgs[0],
  4863. oConfig = this.cfg,
  4864. oAnchor = this._oAnchor,
  4865. sHelpText = oConfig.getProperty(_HELP_TEXT),
  4866. sHelpTextHTML = _EMPTY_STRING,
  4867. sEmphasisStartTag = _EMPTY_STRING,
  4868. sEmphasisEndTag = _EMPTY_STRING;
  4869. if (sText) {
  4870. if (sHelpText) {
  4871. sHelpTextHTML = _START_HELP_TEXT + sHelpText + _END_EM;
  4872. }
  4873. if (oConfig.getProperty(_EMPHASIS)) {
  4874. sEmphasisStartTag = _START_EM;
  4875. sEmphasisEndTag = _END_EM;
  4876. }
  4877. if (oConfig.getProperty(_STRONG_EMPHASIS)) {
  4878. sEmphasisStartTag = _START_STRONG;
  4879. sEmphasisEndTag = _END_STRONG;
  4880. }
  4881. oAnchor.innerHTML = (sEmphasisStartTag + sText + sEmphasisEndTag + sHelpTextHTML);
  4882. }
  4883. },
  4884. /**
  4885. * @method configHelpText
  4886. * @description Event handler for when the "helptext" configuration property
  4887. * of the menu item changes.
  4888. * @param {String} p_sType String representing the name of the event that
  4889. * was fired.
  4890. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4891. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4892. * that fired the event.
  4893. */
  4894. configHelpText: function (p_sType, p_aArgs, p_oItem) {
  4895. this.cfg.refireEvent(_TEXT);
  4896. },
  4897. /**
  4898. * @method configURL
  4899. * @description Event handler for when the "url" configuration property of
  4900. * the menu item changes.
  4901. * @param {String} p_sType String representing the name of the event that
  4902. * was fired.
  4903. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4904. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4905. * that fired the event.
  4906. */
  4907. configURL: function (p_sType, p_aArgs, p_oItem) {
  4908. var sURL = p_aArgs[0];
  4909. if (!sURL) {
  4910. sURL = _HASH;
  4911. }
  4912. var oAnchor = this._oAnchor;
  4913. if (UA.opera) {
  4914. oAnchor.removeAttribute(_HREF);
  4915. }
  4916. oAnchor.setAttribute(_HREF, sURL);
  4917. },
  4918. /**
  4919. * @method configTarget
  4920. * @description Event handler for when the "target" configuration property
  4921. * of the menu item changes.
  4922. * @param {String} p_sType String representing the name of the event that
  4923. * was fired.
  4924. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4925. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4926. * that fired the event.
  4927. */
  4928. configTarget: function (p_sType, p_aArgs, p_oItem) {
  4929. var sTarget = p_aArgs[0],
  4930. oAnchor = this._oAnchor;
  4931. if (sTarget && sTarget.length > 0) {
  4932. oAnchor.setAttribute(_TARGET, sTarget);
  4933. }
  4934. else {
  4935. oAnchor.removeAttribute(_TARGET);
  4936. }
  4937. },
  4938. /**
  4939. * @method configEmphasis
  4940. * @description Event handler for when the "emphasis" configuration property
  4941. * of the menu item changes.
  4942. * @param {String} p_sType String representing the name of the event that
  4943. * was fired.
  4944. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4945. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4946. * that fired the event.
  4947. */
  4948. configEmphasis: function (p_sType, p_aArgs, p_oItem) {
  4949. var bEmphasis = p_aArgs[0],
  4950. oConfig = this.cfg;
  4951. if (bEmphasis && oConfig.getProperty(_STRONG_EMPHASIS)) {
  4952. oConfig.setProperty(_STRONG_EMPHASIS, false);
  4953. }
  4954. oConfig.refireEvent(_TEXT);
  4955. },
  4956. /**
  4957. * @method configStrongEmphasis
  4958. * @description Event handler for when the "strongemphasis" configuration
  4959. * property of the menu item changes.
  4960. * @param {String} p_sType String representing the name of the event that
  4961. * was fired.
  4962. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4963. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4964. * that fired the event.
  4965. */
  4966. configStrongEmphasis: function (p_sType, p_aArgs, p_oItem) {
  4967. var bStrongEmphasis = p_aArgs[0],
  4968. oConfig = this.cfg;
  4969. if (bStrongEmphasis && oConfig.getProperty(_EMPHASIS)) {
  4970. oConfig.setProperty(_EMPHASIS, false);
  4971. }
  4972. oConfig.refireEvent(_TEXT);
  4973. },
  4974. /**
  4975. * @method configChecked
  4976. * @description Event handler for when the "checked" configuration property
  4977. * of the menu item changes.
  4978. * @param {String} p_sType String representing the name of the event that
  4979. * was fired.
  4980. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  4981. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  4982. * that fired the event.
  4983. */
  4984. configChecked: function (p_sType, p_aArgs, p_oItem) {
  4985. var bChecked = p_aArgs[0],
  4986. oConfig = this.cfg;
  4987. if (bChecked) {
  4988. addClassNameForState.call(this, _CHECKED);
  4989. }
  4990. else {
  4991. removeClassNameForState.call(this, _CHECKED);
  4992. }
  4993. oConfig.refireEvent(_TEXT);
  4994. if (oConfig.getProperty(_DISABLED)) {
  4995. oConfig.refireEvent(_DISABLED);
  4996. }
  4997. if (oConfig.getProperty(_SELECTED)) {
  4998. oConfig.refireEvent(_SELECTED);
  4999. }
  5000. },
  5001. /**
  5002. * @method configDisabled
  5003. * @description Event handler for when the "disabled" configuration property
  5004. * of the menu item changes.
  5005. * @param {String} p_sType String representing the name of the event that
  5006. * was fired.
  5007. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5008. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  5009. * that fired the event.
  5010. */
  5011. configDisabled: function (p_sType, p_aArgs, p_oItem) {
  5012. var bDisabled = p_aArgs[0],
  5013. oConfig = this.cfg,
  5014. oSubmenu = oConfig.getProperty(_SUBMENU),
  5015. bChecked = oConfig.getProperty(_CHECKED);
  5016. if (bDisabled) {
  5017. if (oConfig.getProperty(_SELECTED)) {
  5018. oConfig.setProperty(_SELECTED, false);
  5019. }
  5020. addClassNameForState.call(this, _DISABLED);
  5021. if (oSubmenu) {
  5022. addClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
  5023. }
  5024. if (bChecked) {
  5025. addClassNameForState.call(this, _CHECKED_DISABLED);
  5026. }
  5027. }
  5028. else {
  5029. removeClassNameForState.call(this, _DISABLED);
  5030. if (oSubmenu) {
  5031. removeClassNameForState.call(this, _HAS_SUBMENU_DISABLED);
  5032. }
  5033. if (bChecked) {
  5034. removeClassNameForState.call(this, _CHECKED_DISABLED);
  5035. }
  5036. }
  5037. },
  5038. /**
  5039. * @method configSelected
  5040. * @description Event handler for when the "selected" configuration property
  5041. * of the menu item changes.
  5042. * @param {String} p_sType String representing the name of the event that
  5043. * was fired.
  5044. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5045. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  5046. * that fired the event.
  5047. */
  5048. configSelected: function (p_sType, p_aArgs, p_oItem) {
  5049. var oConfig = this.cfg,
  5050. oAnchor = this._oAnchor,
  5051. bSelected = p_aArgs[0],
  5052. bChecked = oConfig.getProperty(_CHECKED),
  5053. oSubmenu = oConfig.getProperty(_SUBMENU);
  5054. if (UA.opera) {
  5055. oAnchor.blur();
  5056. }
  5057. if (bSelected && !oConfig.getProperty(_DISABLED)) {
  5058. addClassNameForState.call(this, _SELECTED);
  5059. if (oSubmenu) {
  5060. addClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
  5061. }
  5062. if (bChecked) {
  5063. addClassNameForState.call(this, _CHECKED_SELECTED);
  5064. }
  5065. }
  5066. else {
  5067. removeClassNameForState.call(this, _SELECTED);
  5068. if (oSubmenu) {
  5069. removeClassNameForState.call(this, _HAS_SUBMENU_SELECTED);
  5070. }
  5071. if (bChecked) {
  5072. removeClassNameForState.call(this, _CHECKED_SELECTED);
  5073. }
  5074. }
  5075. if (this.hasFocus() && UA.opera) {
  5076. oAnchor.focus();
  5077. }
  5078. },
  5079. /**
  5080. * @method _onSubmenuBeforeHide
  5081. * @description "beforehide" Custom Event handler for a submenu.
  5082. * @private
  5083. * @param {String} p_sType String representing the name of the event that
  5084. * was fired.
  5085. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5086. */
  5087. _onSubmenuBeforeHide: function (p_sType, p_aArgs) {
  5088. var oItem = this.parent,
  5089. oMenu;
  5090. function onHide() {
  5091. oItem._oAnchor.blur();
  5092. oMenu.beforeHideEvent.unsubscribe(onHide);
  5093. }
  5094. if (oItem.hasFocus()) {
  5095. oMenu = oItem.parent;
  5096. oMenu.beforeHideEvent.subscribe(onHide);
  5097. }
  5098. },
  5099. /**
  5100. * @method configSubmenu
  5101. * @description Event handler for when the "submenu" configuration property
  5102. * of the menu item changes.
  5103. * @param {String} p_sType String representing the name of the event that
  5104. * was fired.
  5105. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5106. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  5107. * that fired the event.
  5108. */
  5109. configSubmenu: function (p_sType, p_aArgs, p_oItem) {
  5110. var oSubmenu = p_aArgs[0],
  5111. oConfig = this.cfg,
  5112. bLazyLoad = this.parent && this.parent.lazyLoad,
  5113. oMenu,
  5114. sSubmenuId,
  5115. oSubmenuConfig;
  5116. if (oSubmenu) {
  5117. if (oSubmenu instanceof Menu) {
  5118. oMenu = oSubmenu;
  5119. oMenu.parent = this;
  5120. oMenu.lazyLoad = bLazyLoad;
  5121. }
  5122. else if (Lang.isObject(oSubmenu) && oSubmenu.id && !oSubmenu.nodeType) {
  5123. sSubmenuId = oSubmenu.id;
  5124. oSubmenuConfig = oSubmenu;
  5125. oSubmenuConfig.lazyload = bLazyLoad;
  5126. oSubmenuConfig.parent = this;
  5127. oMenu = new this.SUBMENU_TYPE(sSubmenuId, oSubmenuConfig);
  5128. // Set the value of the property to the Menu instance
  5129. oConfig.setProperty(_SUBMENU, oMenu, true);
  5130. }
  5131. else {
  5132. oMenu = new this.SUBMENU_TYPE(oSubmenu, { lazyload: bLazyLoad, parent: this });
  5133. // Set the value of the property to the Menu instance
  5134. oConfig.setProperty(_SUBMENU, oMenu, true);
  5135. }
  5136. if (oMenu) {
  5137. oMenu.cfg.setProperty(_PREVENT_CONTEXT_OVERLAP, true);
  5138. addClassNameForState.call(this, _HAS_SUBMENU);
  5139. if (oConfig.getProperty(_URL) === _HASH) {
  5140. oConfig.setProperty(_URL, (_HASH + oMenu.id));
  5141. }
  5142. this._oSubmenu = oMenu;
  5143. if (UA.opera) {
  5144. oMenu.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);
  5145. }
  5146. }
  5147. }
  5148. else {
  5149. removeClassNameForState.call(this, _HAS_SUBMENU);
  5150. if (this._oSubmenu) {
  5151. this._oSubmenu.destroy();
  5152. }
  5153. }
  5154. if (oConfig.getProperty(_DISABLED)) {
  5155. oConfig.refireEvent(_DISABLED);
  5156. }
  5157. if (oConfig.getProperty(_SELECTED)) {
  5158. oConfig.refireEvent(_SELECTED);
  5159. }
  5160. },
  5161. /**
  5162. * @method configOnClick
  5163. * @description Event handler for when the "onclick" configuration property
  5164. * of the menu item changes.
  5165. * @param {String} p_sType String representing the name of the event that
  5166. * was fired.
  5167. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5168. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  5169. * that fired the event.
  5170. */
  5171. configOnClick: function (p_sType, p_aArgs, p_oItem) {
  5172. var oObject = p_aArgs[0];
  5173. /*
  5174. Remove any existing listeners if a "click" event handler has
  5175. already been specified.
  5176. */
  5177. if (this._oOnclickAttributeValue && (this._oOnclickAttributeValue != oObject)) {
  5178. this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,
  5179. this._oOnclickAttributeValue.obj);
  5180. this._oOnclickAttributeValue = null;
  5181. }
  5182. if (!this._oOnclickAttributeValue && Lang.isObject(oObject) &&
  5183. Lang.isFunction(oObject.fn)) {
  5184. this.clickEvent.subscribe(oObject.fn,
  5185. ((_OBJ in oObject) ? oObject.obj : this),
  5186. ((_SCOPE in oObject) ? oObject.scope : null) );
  5187. this._oOnclickAttributeValue = oObject;
  5188. }
  5189. },
  5190. /**
  5191. * @method configClassName
  5192. * @description Event handler for when the "classname" configuration
  5193. * property of a menu item changes.
  5194. * @param {String} p_sType String representing the name of the event that
  5195. * was fired.
  5196. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5197. * @param {YAHOO.widget.MenuItem} p_oItem Object representing the menu item
  5198. * that fired the event.
  5199. */
  5200. configClassName: function (p_sType, p_aArgs, p_oItem) {
  5201. var sClassName = p_aArgs[0];
  5202. if (this._sClassName) {
  5203. Dom.removeClass(this.element, this._sClassName);
  5204. }
  5205. Dom.addClass(this.element, sClassName);
  5206. this._sClassName = sClassName;
  5207. },
  5208. /**
  5209. * @method _dispatchClickEvent
  5210. * @description Dispatches a DOM "click" event to the anchor element of a
  5211. * MenuItem instance.
  5212. * @private
  5213. */
  5214. _dispatchClickEvent: function () {
  5215. var oMenuItem = this,
  5216. oAnchor,
  5217. oEvent;
  5218. if (!oMenuItem.cfg.getProperty(_DISABLED)) {
  5219. oAnchor = Dom.getFirstChild(oMenuItem.element);
  5220. // Dispatch a "click" event to the MenuItem's anchor so that its
  5221. // "click" event handlers will get called in response to the user
  5222. // pressing the keyboard shortcut defined by the "keylistener"
  5223. // configuration property.
  5224. if (UA.ie) {
  5225. oAnchor.fireEvent(_ONCLICK);
  5226. }
  5227. else {
  5228. if ((UA.gecko && UA.gecko >= 1.9) || UA.opera || UA.webkit) {
  5229. oEvent = document.createEvent("HTMLEvents");
  5230. oEvent.initEvent(_CLICK, true, true);
  5231. }
  5232. else {
  5233. oEvent = document.createEvent("MouseEvents");
  5234. oEvent.initMouseEvent(_CLICK, true, true, window, 0, 0, 0,
  5235. 0, 0, false, false, false, false, 0, null);
  5236. }
  5237. oAnchor.dispatchEvent(oEvent);
  5238. }
  5239. }
  5240. },
  5241. /**
  5242. * @method _createKeyListener
  5243. * @description "show" event handler for a Menu instance - responsible for
  5244. * setting up the KeyListener instance for a MenuItem.
  5245. * @private
  5246. * @param {String} type String representing the name of the event that
  5247. * was fired.
  5248. * @param {Array} args Array of arguments sent when the event was fired.
  5249. * @param {Array} keyData Array of arguments sent when the event was fired.
  5250. */
  5251. _createKeyListener: function (type, args, keyData) {
  5252. var oMenuItem = this,
  5253. oMenu = oMenuItem.parent;
  5254. var oKeyListener = new YAHOO.util.KeyListener(
  5255. oMenu.element.ownerDocument,
  5256. keyData,
  5257. {
  5258. fn: oMenuItem._dispatchClickEvent,
  5259. scope: oMenuItem,
  5260. correctScope: true });
  5261. if (oMenu.cfg.getProperty(_VISIBLE)) {
  5262. oKeyListener.enable();
  5263. }
  5264. oMenu.subscribe(_SHOW, oKeyListener.enable, null, oKeyListener);
  5265. oMenu.subscribe(_HIDE, oKeyListener.disable, null, oKeyListener);
  5266. oMenuItem._keyListener = oKeyListener;
  5267. oMenu.unsubscribe(_SHOW, oMenuItem._createKeyListener, keyData);
  5268. },
  5269. /**
  5270. * @method configKeyListener
  5271. * @description Event handler for when the "keylistener" configuration
  5272. * property of a menu item changes.
  5273. * @param {String} p_sType String representing the name of the event that
  5274. * was fired.
  5275. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5276. */
  5277. configKeyListener: function (p_sType, p_aArgs) {
  5278. var oKeyData = p_aArgs[0],
  5279. oMenuItem = this,
  5280. oMenu = oMenuItem.parent;
  5281. if (oMenuItem._keyData) {
  5282. // Unsubscribe from the "show" event in case the keylistener
  5283. // config was changed before the Menu was ever made visible.
  5284. oMenu.unsubscribe(_SHOW,
  5285. oMenuItem._createKeyListener, oMenuItem._keyData);
  5286. oMenuItem._keyData = null;
  5287. }
  5288. // Tear down for the previous value of the "keylistener" property
  5289. if (oMenuItem._keyListener) {
  5290. oMenu.unsubscribe(_SHOW, oMenuItem._keyListener.enable);
  5291. oMenu.unsubscribe(_HIDE, oMenuItem._keyListener.disable);
  5292. oMenuItem._keyListener.disable();
  5293. oMenuItem._keyListener = null;
  5294. }
  5295. if (oKeyData) {
  5296. oMenuItem._keyData = oKeyData;
  5297. // Defer the creation of the KeyListener instance until the
  5298. // parent Menu is visible. This is necessary since the
  5299. // KeyListener instance needs to be bound to the document the
  5300. // Menu has been rendered into. Deferring creation of the
  5301. // KeyListener instance also improves performance.
  5302. oMenu.subscribe(_SHOW, oMenuItem._createKeyListener,
  5303. oKeyData, oMenuItem);
  5304. }
  5305. },
  5306. // Public methods
  5307. /**
  5308. * @method initDefaultConfig
  5309. * @description Initializes an item's configurable properties.
  5310. */
  5311. initDefaultConfig : function () {
  5312. var oConfig = this.cfg;
  5313. // Define the configuration attributes
  5314. /**
  5315. * @config text
  5316. * @description String specifying the text label for the menu item.
  5317. * When building a menu from existing HTML the value of this property
  5318. * will be interpreted from the menu's markup.
  5319. * @default ""
  5320. * @type String
  5321. */
  5322. oConfig.addProperty(
  5323. TEXT_CONFIG.key,
  5324. {
  5325. handler: this.configText,
  5326. value: TEXT_CONFIG.value,
  5327. validator: TEXT_CONFIG.validator,
  5328. suppressEvent: TEXT_CONFIG.suppressEvent
  5329. }
  5330. );
  5331. /**
  5332. * @config helptext
  5333. * @description String specifying additional instructional text to
  5334. * accompany the text for the menu item.
  5335. * @deprecated Use "text" configuration property to add help text markup.
  5336. * For example: <code>oMenuItem.cfg.setProperty("text", "Copy &#60;em
  5337. * class=\"helptext\"&#62;Ctrl + C&#60;/em&#62;");</code>
  5338. * @default null
  5339. * @type String|<a href="http://www.w3.org/TR/
  5340. * 2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
  5341. * HTMLElement</a>
  5342. */
  5343. oConfig.addProperty(
  5344. HELP_TEXT_CONFIG.key,
  5345. {
  5346. handler: this.configHelpText,
  5347. supercedes: HELP_TEXT_CONFIG.supercedes,
  5348. suppressEvent: HELP_TEXT_CONFIG.suppressEvent
  5349. }
  5350. );
  5351. /**
  5352. * @config url
  5353. * @description String specifying the URL for the menu item's anchor's
  5354. * "href" attribute. When building a menu from existing HTML the value
  5355. * of this property will be interpreted from the menu's markup.
  5356. * @default "#"
  5357. * @type String
  5358. */
  5359. oConfig.addProperty(
  5360. URL_CONFIG.key,
  5361. {
  5362. handler: this.configURL,
  5363. value: URL_CONFIG.value,
  5364. suppressEvent: URL_CONFIG.suppressEvent
  5365. }
  5366. );
  5367. /**
  5368. * @config target
  5369. * @description String specifying the value for the "target" attribute
  5370. * of the menu item's anchor element. <strong>Specifying a target will
  5371. * require the user to click directly on the menu item's anchor node in
  5372. * order to cause the browser to navigate to the specified URL.</strong>
  5373. * When building a menu from existing HTML the value of this property
  5374. * will be interpreted from the menu's markup.
  5375. * @default null
  5376. * @type String
  5377. */
  5378. oConfig.addProperty(
  5379. TARGET_CONFIG.key,
  5380. {
  5381. handler: this.configTarget,
  5382. suppressEvent: TARGET_CONFIG.suppressEvent
  5383. }
  5384. );
  5385. /**
  5386. * @config emphasis
  5387. * @description Boolean indicating if the text of the menu item will be
  5388. * rendered with emphasis.
  5389. * @deprecated Use the "text" configuration property to add emphasis.
  5390. * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;em&#62;Some
  5391. * Text&#60;/em&#62;");</code>
  5392. * @default false
  5393. * @type Boolean
  5394. */
  5395. oConfig.addProperty(
  5396. EMPHASIS_CONFIG.key,
  5397. {
  5398. handler: this.configEmphasis,
  5399. value: EMPHASIS_CONFIG.value,
  5400. validator: EMPHASIS_CONFIG.validator,
  5401. suppressEvent: EMPHASIS_CONFIG.suppressEvent,
  5402. supercedes: EMPHASIS_CONFIG.supercedes
  5403. }
  5404. );
  5405. /**
  5406. * @config strongemphasis
  5407. * @description Boolean indicating if the text of the menu item will be
  5408. * rendered with strong emphasis.
  5409. * @deprecated Use the "text" configuration property to add strong emphasis.
  5410. * For example: <code>oMenuItem.cfg.setProperty("text", "&#60;strong&#62;
  5411. * Some Text&#60;/strong&#62;");</code>
  5412. * @default false
  5413. * @type Boolean
  5414. */
  5415. oConfig.addProperty(
  5416. STRONG_EMPHASIS_CONFIG.key,
  5417. {
  5418. handler: this.configStrongEmphasis,
  5419. value: STRONG_EMPHASIS_CONFIG.value,
  5420. validator: STRONG_EMPHASIS_CONFIG.validator,
  5421. suppressEvent: STRONG_EMPHASIS_CONFIG.suppressEvent,
  5422. supercedes: STRONG_EMPHASIS_CONFIG.supercedes
  5423. }
  5424. );
  5425. /**
  5426. * @config checked
  5427. * @description Boolean indicating if the menu item should be rendered
  5428. * with a checkmark.
  5429. * @default false
  5430. * @type Boolean
  5431. */
  5432. oConfig.addProperty(
  5433. CHECKED_CONFIG.key,
  5434. {
  5435. handler: this.configChecked,
  5436. value: CHECKED_CONFIG.value,
  5437. validator: CHECKED_CONFIG.validator,
  5438. suppressEvent: CHECKED_CONFIG.suppressEvent,
  5439. supercedes: CHECKED_CONFIG.supercedes
  5440. }
  5441. );
  5442. /**
  5443. * @config disabled
  5444. * @description Boolean indicating if the menu item should be disabled.
  5445. * (Disabled menu items are dimmed and will not respond to user input
  5446. * or fire events.)
  5447. * @default false
  5448. * @type Boolean
  5449. */
  5450. oConfig.addProperty(
  5451. DISABLED_CONFIG.key,
  5452. {
  5453. handler: this.configDisabled,
  5454. value: DISABLED_CONFIG.value,
  5455. validator: DISABLED_CONFIG.validator,
  5456. suppressEvent: DISABLED_CONFIG.suppressEvent
  5457. }
  5458. );
  5459. /**
  5460. * @config selected
  5461. * @description Boolean indicating if the menu item should
  5462. * be highlighted.
  5463. * @default false
  5464. * @type Boolean
  5465. */
  5466. oConfig.addProperty(
  5467. SELECTED_CONFIG.key,
  5468. {
  5469. handler: this.configSelected,
  5470. value: SELECTED_CONFIG.value,
  5471. validator: SELECTED_CONFIG.validator,
  5472. suppressEvent: SELECTED_CONFIG.suppressEvent
  5473. }
  5474. );
  5475. /**
  5476. * @config submenu
  5477. * @description Object specifying the submenu to be appended to the
  5478. * menu item. The value can be one of the following: <ul><li>Object
  5479. * specifying a Menu instance.</li><li>Object literal specifying the
  5480. * menu to be created. Format: <code>{ id: [menu id], itemdata:
  5481. * [<a href="YAHOO.widget.Menu.html#itemData">array of values for
  5482. * items</a>] }</code>.</li><li>String specifying the id attribute
  5483. * of the <code>&#60;div&#62;</code> element of the menu.</li><li>
  5484. * Object specifying the <code>&#60;div&#62;</code> element of the
  5485. * menu.</li></ul>
  5486. * @default null
  5487. * @type Menu|String|Object|<a href="http://www.w3.org/TR/2000/
  5488. * WD-DOM-Level-1-20000929/level-one-html.html#ID-58190037">
  5489. * HTMLElement</a>
  5490. */
  5491. oConfig.addProperty(
  5492. SUBMENU_CONFIG.key,
  5493. {
  5494. handler: this.configSubmenu,
  5495. supercedes: SUBMENU_CONFIG.supercedes,
  5496. suppressEvent: SUBMENU_CONFIG.suppressEvent
  5497. }
  5498. );
  5499. /**
  5500. * @config onclick
  5501. * @description Object literal representing the code to be executed when
  5502. * the item is clicked. Format:<br> <code> {<br>
  5503. * <strong>fn:</strong> Function, &#47;&#47; The handler to call when
  5504. * the event fires.<br> <strong>obj:</strong> Object, &#47;&#47; An
  5505. * object to pass back to the handler.<br> <strong>scope:</strong>
  5506. * Object &#47;&#47; The object to use for the scope of the handler.
  5507. * <br> } </code>
  5508. * @type Object
  5509. * @default null
  5510. */
  5511. oConfig.addProperty(
  5512. ONCLICK_CONFIG.key,
  5513. {
  5514. handler: this.configOnClick,
  5515. suppressEvent: ONCLICK_CONFIG.suppressEvent
  5516. }
  5517. );
  5518. /**
  5519. * @config classname
  5520. * @description CSS class to be applied to the menu item's root
  5521. * <code>&#60;li&#62;</code> element. The specified class(es) are
  5522. * appended in addition to the default class as specified by the menu
  5523. * item's CSS_CLASS_NAME constant.
  5524. * @default null
  5525. * @type String
  5526. */
  5527. oConfig.addProperty(
  5528. CLASS_NAME_CONFIG.key,
  5529. {
  5530. handler: this.configClassName,
  5531. value: CLASS_NAME_CONFIG.value,
  5532. validator: CLASS_NAME_CONFIG.validator,
  5533. suppressEvent: CLASS_NAME_CONFIG.suppressEvent
  5534. }
  5535. );
  5536. /**
  5537. * @config keylistener
  5538. * @description Object literal representing the key(s) that can be used
  5539. * to trigger the MenuItem's "click" event. Possible attributes are
  5540. * shift (boolean), alt (boolean), ctrl (boolean) and keys (either an int
  5541. * or an array of ints representing keycodes).
  5542. * @default null
  5543. * @type Object
  5544. */
  5545. oConfig.addProperty(
  5546. KEY_LISTENER_CONFIG.key,
  5547. {
  5548. handler: this.configKeyListener,
  5549. value: KEY_LISTENER_CONFIG.value,
  5550. suppressEvent: KEY_LISTENER_CONFIG.suppressEvent
  5551. }
  5552. );
  5553. },
  5554. /**
  5555. * @method getNextSibling
  5556. * @description Finds the menu item's next sibling.
  5557. * @return YAHOO.widget.MenuItem
  5558. */
  5559. getNextSibling: function () {
  5560. var isUL = function (el) {
  5561. return (el.nodeName.toLowerCase() === "ul");
  5562. },
  5563. menuitemEl = this.element,
  5564. next = Dom.getNextSibling(menuitemEl),
  5565. parent,
  5566. sibling,
  5567. list;
  5568. if (!next) {
  5569. parent = menuitemEl.parentNode;
  5570. sibling = Dom.getNextSiblingBy(parent, isUL);
  5571. if (sibling) {
  5572. list = sibling;
  5573. }
  5574. else {
  5575. list = Dom.getFirstChildBy(parent.parentNode, isUL);
  5576. }
  5577. next = Dom.getFirstChild(list);
  5578. }
  5579. return YAHOO.widget.MenuManager.getMenuItem(next.id);
  5580. },
  5581. /**
  5582. * @method getNextEnabledSibling
  5583. * @description Finds the menu item's next enabled sibling.
  5584. * @return YAHOO.widget.MenuItem
  5585. */
  5586. getNextEnabledSibling: function () {
  5587. var next = this.getNextSibling();
  5588. return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getNextEnabledSibling() : next;
  5589. },
  5590. /**
  5591. * @method getPreviousSibling
  5592. * @description Finds the menu item's previous sibling.
  5593. * @return {YAHOO.widget.MenuItem}
  5594. */
  5595. getPreviousSibling: function () {
  5596. var isUL = function (el) {
  5597. return (el.nodeName.toLowerCase() === "ul");
  5598. },
  5599. menuitemEl = this.element,
  5600. next = Dom.getPreviousSibling(menuitemEl),
  5601. parent,
  5602. sibling,
  5603. list;
  5604. if (!next) {
  5605. parent = menuitemEl.parentNode;
  5606. sibling = Dom.getPreviousSiblingBy(parent, isUL);
  5607. if (sibling) {
  5608. list = sibling;
  5609. }
  5610. else {
  5611. list = Dom.getLastChildBy(parent.parentNode, isUL);
  5612. }
  5613. next = Dom.getLastChild(list);
  5614. }
  5615. return YAHOO.widget.MenuManager.getMenuItem(next.id);
  5616. },
  5617. /**
  5618. * @method getPreviousEnabledSibling
  5619. * @description Finds the menu item's previous enabled sibling.
  5620. * @return {YAHOO.widget.MenuItem}
  5621. */
  5622. getPreviousEnabledSibling: function () {
  5623. var next = this.getPreviousSibling();
  5624. return (next.cfg.getProperty(_DISABLED) || next.element.style.display == _NONE) ? next.getPreviousEnabledSibling() : next;
  5625. },
  5626. /**
  5627. * @method focus
  5628. * @description Causes the menu item to receive the focus and fires the
  5629. * focus event.
  5630. */
  5631. focus: function () {
  5632. var oParent = this.parent,
  5633. oAnchor = this._oAnchor,
  5634. oActiveItem = oParent.activeItem;
  5635. function setFocus() {
  5636. try {
  5637. if (!(UA.ie && !document.hasFocus())) {
  5638. if (oActiveItem) {
  5639. oActiveItem.blurEvent.fire();
  5640. }
  5641. oAnchor.focus();
  5642. this.focusEvent.fire();
  5643. }
  5644. }
  5645. catch(e) {
  5646. }
  5647. }
  5648. if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE) &&
  5649. this.element.style.display != _NONE) {
  5650. /*
  5651. Setting focus via a timer fixes a race condition in Firefox, IE
  5652. and Opera where the browser viewport jumps as it trys to
  5653. position and focus the menu.
  5654. */
  5655. Lang.later(0, this, setFocus);
  5656. }
  5657. },
  5658. /**
  5659. * @method blur
  5660. * @description Causes the menu item to lose focus and fires the
  5661. * blur event.
  5662. */
  5663. blur: function () {
  5664. var oParent = this.parent;
  5665. if (!this.cfg.getProperty(_DISABLED) && oParent && oParent.cfg.getProperty(_VISIBLE)) {
  5666. Lang.later(0, this, function () {
  5667. try {
  5668. this._oAnchor.blur();
  5669. this.blurEvent.fire();
  5670. }
  5671. catch (e) {
  5672. }
  5673. }, 0);
  5674. }
  5675. },
  5676. /**
  5677. * @method hasFocus
  5678. * @description Returns a boolean indicating whether or not the menu item
  5679. * has focus.
  5680. * @return {Boolean}
  5681. */
  5682. hasFocus: function () {
  5683. return (YAHOO.widget.MenuManager.getFocusedMenuItem() == this);
  5684. },
  5685. /**
  5686. * @method destroy
  5687. * @description Removes the menu item's <code>&#60;li&#62;</code> element
  5688. * from its parent <code>&#60;ul&#62;</code> element.
  5689. */
  5690. destroy: function () {
  5691. var oEl = this.element,
  5692. oSubmenu,
  5693. oParentNode,
  5694. aEventData,
  5695. i;
  5696. if (oEl) {
  5697. // If the item has a submenu, destroy it first
  5698. oSubmenu = this.cfg.getProperty(_SUBMENU);
  5699. if (oSubmenu) {
  5700. oSubmenu.destroy();
  5701. }
  5702. // Remove the element from the parent node
  5703. oParentNode = oEl.parentNode;
  5704. if (oParentNode) {
  5705. oParentNode.removeChild(oEl);
  5706. this.destroyEvent.fire();
  5707. }
  5708. // Remove CustomEvent listeners
  5709. i = EVENT_TYPES.length - 1;
  5710. do {
  5711. aEventData = EVENT_TYPES[i];
  5712. this[aEventData[0]].unsubscribeAll();
  5713. }
  5714. while (i--);
  5715. this.cfg.configChangedEvent.unsubscribeAll();
  5716. }
  5717. },
  5718. /**
  5719. * @method toString
  5720. * @description Returns a string representing the menu item.
  5721. * @return {String}
  5722. */
  5723. toString: function () {
  5724. var sReturnVal = _MENUITEM,
  5725. sId = this.id;
  5726. if (sId) {
  5727. sReturnVal += (_SPACE + sId);
  5728. }
  5729. return sReturnVal;
  5730. }
  5731. };
  5732. Lang.augmentProto(MenuItem, YAHOO.util.EventProvider);
  5733. })();
  5734. (function () {
  5735. var _XY = "xy",
  5736. _MOUSEDOWN = "mousedown",
  5737. _CONTEXTMENU = "ContextMenu",
  5738. _SPACE = " ";
  5739. /**
  5740. * Creates a list of options or commands which are made visible in response to
  5741. * an HTML element's "contextmenu" event ("mousedown" for Opera).
  5742. *
  5743. * @param {String} p_oElement String specifying the id attribute of the
  5744. * <code>&#60;div&#62;</code> element of the context menu.
  5745. * @param {String} p_oElement String specifying the id attribute of the
  5746. * <code>&#60;select&#62;</code> element to be used as the data source for the
  5747. * context menu.
  5748. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
  5749. * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
  5750. * <code>&#60;div&#62;</code> element of the context menu.
  5751. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
  5752. * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
  5753. * the <code>&#60;select&#62;</code> element to be used as the data source for
  5754. * the context menu.
  5755. * @param {Object} p_oConfig Optional. Object literal specifying the
  5756. * configuration for the context menu. See configuration class documentation
  5757. * for more details.
  5758. * @class ContextMenu
  5759. * @constructor
  5760. * @extends YAHOO.widget.Menu
  5761. * @namespace YAHOO.widget
  5762. */
  5763. YAHOO.widget.ContextMenu = function(p_oElement, p_oConfig) {
  5764. YAHOO.widget.ContextMenu.superclass.constructor.call(this, p_oElement, p_oConfig);
  5765. };
  5766. var Event = YAHOO.util.Event,
  5767. UA = YAHOO.env.ua,
  5768. ContextMenu = YAHOO.widget.ContextMenu,
  5769. /**
  5770. * Constant representing the name of the ContextMenu's events
  5771. * @property EVENT_TYPES
  5772. * @private
  5773. * @final
  5774. * @type Object
  5775. */
  5776. EVENT_TYPES = {
  5777. "TRIGGER_CONTEXT_MENU": "triggerContextMenu",
  5778. "CONTEXT_MENU": (UA.opera ? _MOUSEDOWN : "contextmenu"),
  5779. "CLICK": "click"
  5780. },
  5781. /**
  5782. * Constant representing the ContextMenu's configuration properties
  5783. * @property DEFAULT_CONFIG
  5784. * @private
  5785. * @final
  5786. * @type Object
  5787. */
  5788. TRIGGER_CONFIG = {
  5789. key: "trigger",
  5790. suppressEvent: true
  5791. };
  5792. /**
  5793. * @method position
  5794. * @description "beforeShow" event handler used to position the contextmenu.
  5795. * @private
  5796. * @param {String} p_sType String representing the name of the event that
  5797. * was fired.
  5798. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  5799. * @param {Array} p_aPos Array representing the xy position for the context menu.
  5800. */
  5801. function position(p_sType, p_aArgs, p_aPos) {
  5802. this.cfg.setProperty(_XY, p_aPos);
  5803. this.beforeShowEvent.unsubscribe(position, p_aPos);
  5804. }
  5805. YAHOO.lang.extend(ContextMenu, YAHOO.widget.Menu, {
  5806. // Private properties
  5807. /**
  5808. * @property _oTrigger
  5809. * @description Object reference to the current value of the "trigger"
  5810. * configuration property.
  5811. * @default null
  5812. * @private
  5813. * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/leve
  5814. * l-one-html.html#ID-58190037">HTMLElement</a>|Array
  5815. */
  5816. _oTrigger: null,
  5817. /**
  5818. * @property _bCancelled
  5819. * @description Boolean indicating if the display of the context menu should
  5820. * be cancelled.
  5821. * @default false
  5822. * @private
  5823. * @type Boolean
  5824. */
  5825. _bCancelled: false,
  5826. // Public properties
  5827. /**
  5828. * @property contextEventTarget
  5829. * @description Object reference for the HTML element that was the target of the
  5830. * "contextmenu" DOM event ("mousedown" for Opera) that triggered the display of
  5831. * the context menu.
  5832. * @default null
  5833. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
  5834. * html.html#ID-58190037">HTMLElement</a>
  5835. */
  5836. contextEventTarget: null,
  5837. // Events
  5838. /**
  5839. * @event triggerContextMenuEvent
  5840. * @description Custom Event wrapper for the "contextmenu" DOM event
  5841. * ("mousedown" for Opera) fired by the element(s) that trigger the display of
  5842. * the context menu.
  5843. */
  5844. triggerContextMenuEvent: null,
  5845. /**
  5846. * @method init
  5847. * @description The ContextMenu class's initialization method. This method is
  5848. * automatically called by the constructor, and sets up all DOM references for
  5849. * pre-existing markup, and creates required markup if it is not already present.
  5850. * @param {String} p_oElement String specifying the id attribute of the
  5851. * <code>&#60;div&#62;</code> element of the context menu.
  5852. * @param {String} p_oElement String specifying the id attribute of the
  5853. * <code>&#60;select&#62;</code> element to be used as the data source for
  5854. * the context menu.
  5855. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
  5856. * html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying the
  5857. * <code>&#60;div&#62;</code> element of the context menu.
  5858. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-
  5859. * html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object specifying
  5860. * the <code>&#60;select&#62;</code> element to be used as the data source for
  5861. * the context menu.
  5862. * @param {Object} p_oConfig Optional. Object literal specifying the
  5863. * configuration for the context menu. See configuration class documentation
  5864. * for more details.
  5865. */
  5866. init: function(p_oElement, p_oConfig) {
  5867. // Call the init of the superclass (YAHOO.widget.Menu)
  5868. ContextMenu.superclass.init.call(this, p_oElement);
  5869. this.beforeInitEvent.fire(ContextMenu);
  5870. if (p_oConfig) {
  5871. this.cfg.applyConfig(p_oConfig, true);
  5872. }
  5873. this.initEvent.fire(ContextMenu);
  5874. },
  5875. /**
  5876. * @method initEvents
  5877. * @description Initializes the custom events for the context menu.
  5878. */
  5879. initEvents: function() {
  5880. ContextMenu.superclass.initEvents.call(this);
  5881. // Create custom events
  5882. this.triggerContextMenuEvent = this.createEvent(EVENT_TYPES.TRIGGER_CONTEXT_MENU);
  5883. this.triggerContextMenuEvent.signature = YAHOO.util.CustomEvent.LIST;
  5884. },
  5885. /**
  5886. * @method cancel
  5887. * @description Cancels the display of the context menu.
  5888. */
  5889. cancel: function() {
  5890. this._bCancelled = true;
  5891. },
  5892. // Private methods
  5893. /**
  5894. * @method _removeEventHandlers
  5895. * @description Removes all of the DOM event handlers from the HTML element(s)
  5896. * whose "context menu" event ("click" for Opera) trigger the display of
  5897. * the context menu.
  5898. * @private
  5899. */
  5900. _removeEventHandlers: function() {
  5901. var oTrigger = this._oTrigger;
  5902. // Remove the event handlers from the trigger(s)
  5903. if (oTrigger) {
  5904. Event.removeListener(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu);
  5905. if (UA.opera) {
  5906. Event.removeListener(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick);
  5907. }
  5908. }
  5909. },
  5910. // Private event handlers
  5911. /**
  5912. * @method _onTriggerClick
  5913. * @description "click" event handler for the HTML element(s) identified as the
  5914. * "trigger" for the context menu. Used to cancel default behaviors in Opera.
  5915. * @private
  5916. * @param {Event} p_oEvent Object representing the DOM event object passed back
  5917. * by the event utility (YAHOO.util.Event).
  5918. * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
  5919. * menu that is handling the event.
  5920. */
  5921. _onTriggerClick: function(p_oEvent, p_oMenu) {
  5922. if (p_oEvent.ctrlKey) {
  5923. Event.stopEvent(p_oEvent);
  5924. }
  5925. },
  5926. /**
  5927. * @method _onTriggerContextMenu
  5928. * @description "contextmenu" event handler ("mousedown" for Opera) for the HTML
  5929. * element(s) that trigger the display of the context menu.
  5930. * @private
  5931. * @param {Event} p_oEvent Object representing the DOM event object passed back
  5932. * by the event utility (YAHOO.util.Event).
  5933. * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
  5934. * menu that is handling the event.
  5935. */
  5936. _onTriggerContextMenu: function(p_oEvent, p_oMenu) {
  5937. var aXY;
  5938. if (!(p_oEvent.type == _MOUSEDOWN && !p_oEvent.ctrlKey)) {
  5939. this.contextEventTarget = Event.getTarget(p_oEvent);
  5940. this.triggerContextMenuEvent.fire(p_oEvent);
  5941. if (!this._bCancelled) {
  5942. /*
  5943. Prevent the browser's default context menu from appearing and
  5944. stop the propagation of the "contextmenu" event so that
  5945. other ContextMenu instances are not displayed.
  5946. */
  5947. Event.stopEvent(p_oEvent);
  5948. // Hide any other Menu instances that might be visible
  5949. YAHOO.widget.MenuManager.hideVisible();
  5950. // Position and display the context menu
  5951. aXY = Event.getXY(p_oEvent);
  5952. if (!YAHOO.util.Dom.inDocument(this.element)) {
  5953. this.beforeShowEvent.subscribe(position, aXY);
  5954. }
  5955. else {
  5956. this.cfg.setProperty(_XY, aXY);
  5957. }
  5958. this.show();
  5959. }
  5960. this._bCancelled = false;
  5961. }
  5962. },
  5963. // Public methods
  5964. /**
  5965. * @method toString
  5966. * @description Returns a string representing the context menu.
  5967. * @return {String}
  5968. */
  5969. toString: function() {
  5970. var sReturnVal = _CONTEXTMENU,
  5971. sId = this.id;
  5972. if (sId) {
  5973. sReturnVal += (_SPACE + sId);
  5974. }
  5975. return sReturnVal;
  5976. },
  5977. /**
  5978. * @method initDefaultConfig
  5979. * @description Initializes the class's configurable properties which can be
  5980. * changed using the context menu's Config object ("cfg").
  5981. */
  5982. initDefaultConfig: function() {
  5983. ContextMenu.superclass.initDefaultConfig.call(this);
  5984. /**
  5985. * @config trigger
  5986. * @description The HTML element(s) whose "contextmenu" event ("mousedown"
  5987. * for Opera) trigger the display of the context menu. Can be a string
  5988. * representing the id attribute of the HTML element, an object reference
  5989. * for the HTML element, or an array of strings or HTML element references.
  5990. * @default null
  5991. * @type String|<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  5992. * level-one-html.html#ID-58190037">HTMLElement</a>|Array
  5993. */
  5994. this.cfg.addProperty(TRIGGER_CONFIG.key,
  5995. {
  5996. handler: this.configTrigger,
  5997. suppressEvent: TRIGGER_CONFIG.suppressEvent
  5998. }
  5999. );
  6000. },
  6001. /**
  6002. * @method destroy
  6003. * @description Removes the context menu's <code>&#60;div&#62;</code> element
  6004. * (and accompanying child nodes) from the document.
  6005. */
  6006. destroy: function() {
  6007. // Remove the DOM event handlers from the current trigger(s)
  6008. this._removeEventHandlers();
  6009. // Continue with the superclass implementation of this method
  6010. ContextMenu.superclass.destroy.call(this);
  6011. },
  6012. // Public event handlers for configuration properties
  6013. /**
  6014. * @method configTrigger
  6015. * @description Event handler for when the value of the "trigger" configuration
  6016. * property changes.
  6017. * @param {String} p_sType String representing the name of the event that
  6018. * was fired.
  6019. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  6020. * @param {YAHOO.widget.ContextMenu} p_oMenu Object representing the context
  6021. * menu that fired the event.
  6022. */
  6023. configTrigger: function(p_sType, p_aArgs, p_oMenu) {
  6024. var oTrigger = p_aArgs[0];
  6025. if (oTrigger) {
  6026. /*
  6027. If there is a current "trigger" - remove the event handlers
  6028. from that element(s) before assigning new ones
  6029. */
  6030. if (this._oTrigger) {
  6031. this._removeEventHandlers();
  6032. }
  6033. this._oTrigger = oTrigger;
  6034. /*
  6035. Listen for the "mousedown" event in Opera b/c it does not
  6036. support the "contextmenu" event
  6037. */
  6038. Event.on(oTrigger, EVENT_TYPES.CONTEXT_MENU, this._onTriggerContextMenu, this, true);
  6039. /*
  6040. Assign a "click" event handler to the trigger element(s) for
  6041. Opera to prevent default browser behaviors.
  6042. */
  6043. if (UA.opera) {
  6044. Event.on(oTrigger, EVENT_TYPES.CLICK, this._onTriggerClick, this, true);
  6045. }
  6046. }
  6047. else {
  6048. this._removeEventHandlers();
  6049. }
  6050. }
  6051. }); // END YAHOO.lang.extend
  6052. }());
  6053. /**
  6054. * Creates an item for a context menu.
  6055. *
  6056. * @param {String} p_oObject String specifying the text of the context menu item.
  6057. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6058. * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
  6059. * <code>&#60;li&#62;</code> element of the context menu item.
  6060. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6061. * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
  6062. * specifying the <code>&#60;optgroup&#62;</code> element of the context
  6063. * menu item.
  6064. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6065. * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
  6066. * the <code>&#60;option&#62;</code> element of the context menu item.
  6067. * @param {Object} p_oConfig Optional. Object literal specifying the
  6068. * configuration for the context menu item. See configuration class
  6069. * documentation for more details.
  6070. * @class ContextMenuItem
  6071. * @constructor
  6072. * @extends YAHOO.widget.MenuItem
  6073. * @deprecated As of version 2.4.0 items for YAHOO.widget.ContextMenu instances
  6074. * are of type YAHOO.widget.MenuItem.
  6075. */
  6076. YAHOO.widget.ContextMenuItem = YAHOO.widget.MenuItem;
  6077. (function () {
  6078. var Lang = YAHOO.lang,
  6079. // String constants
  6080. _STATIC = "static",
  6081. _DYNAMIC_STATIC = "dynamic," + _STATIC,
  6082. _DISABLED = "disabled",
  6083. _SELECTED = "selected",
  6084. _AUTO_SUBMENU_DISPLAY = "autosubmenudisplay",
  6085. _SUBMENU = "submenu",
  6086. _VISIBLE = "visible",
  6087. _SPACE = " ",
  6088. _SUBMENU_TOGGLE_REGION = "submenutoggleregion",
  6089. _MENUBAR = "MenuBar";
  6090. /**
  6091. * Horizontal collection of items, each of which can contain a submenu.
  6092. *
  6093. * @param {String} p_oElement String specifying the id attribute of the
  6094. * <code>&#60;div&#62;</code> element of the menu bar.
  6095. * @param {String} p_oElement String specifying the id attribute of the
  6096. * <code>&#60;select&#62;</code> element to be used as the data source for the
  6097. * menu bar.
  6098. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6099. * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
  6100. * the <code>&#60;div&#62;</code> element of the menu bar.
  6101. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6102. * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
  6103. * specifying the <code>&#60;select&#62;</code> element to be used as the data
  6104. * source for the menu bar.
  6105. * @param {Object} p_oConfig Optional. Object literal specifying the
  6106. * configuration for the menu bar. See configuration class documentation for
  6107. * more details.
  6108. * @class MenuBar
  6109. * @constructor
  6110. * @extends YAHOO.widget.Menu
  6111. * @namespace YAHOO.widget
  6112. */
  6113. YAHOO.widget.MenuBar = function(p_oElement, p_oConfig) {
  6114. YAHOO.widget.MenuBar.superclass.constructor.call(this, p_oElement, p_oConfig);
  6115. };
  6116. /**
  6117. * @method checkPosition
  6118. * @description Checks to make sure that the value of the "position" property
  6119. * is one of the supported strings. Returns true if the position is supported.
  6120. * @private
  6121. * @param {Object} p_sPosition String specifying the position of the menu.
  6122. * @return {Boolean}
  6123. */
  6124. function checkPosition(p_sPosition) {
  6125. var returnVal = false;
  6126. if (Lang.isString(p_sPosition)) {
  6127. returnVal = (_DYNAMIC_STATIC.indexOf((p_sPosition.toLowerCase())) != -1);
  6128. }
  6129. return returnVal;
  6130. }
  6131. var Event = YAHOO.util.Event,
  6132. MenuBar = YAHOO.widget.MenuBar,
  6133. POSITION_CONFIG = {
  6134. key: "position",
  6135. value: _STATIC,
  6136. validator: checkPosition,
  6137. supercedes: [_VISIBLE]
  6138. },
  6139. SUBMENU_ALIGNMENT_CONFIG = {
  6140. key: "submenualignment",
  6141. value: ["tl","bl"]
  6142. },
  6143. AUTO_SUBMENU_DISPLAY_CONFIG = {
  6144. key: _AUTO_SUBMENU_DISPLAY,
  6145. value: false,
  6146. validator: Lang.isBoolean,
  6147. suppressEvent: true
  6148. },
  6149. SUBMENU_TOGGLE_REGION_CONFIG = {
  6150. key: _SUBMENU_TOGGLE_REGION,
  6151. value: false,
  6152. validator: Lang.isBoolean
  6153. };
  6154. Lang.extend(MenuBar, YAHOO.widget.Menu, {
  6155. /**
  6156. * @method init
  6157. * @description The MenuBar class's initialization method. This method is
  6158. * automatically called by the constructor, and sets up all DOM references for
  6159. * pre-existing markup, and creates required markup if it is not already present.
  6160. * @param {String} p_oElement String specifying the id attribute of the
  6161. * <code>&#60;div&#62;</code> element of the menu bar.
  6162. * @param {String} p_oElement String specifying the id attribute of the
  6163. * <code>&#60;select&#62;</code> element to be used as the data source for the
  6164. * menu bar.
  6165. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6166. * one-html.html#ID-22445964">HTMLDivElement</a>} p_oElement Object specifying
  6167. * the <code>&#60;div&#62;</code> element of the menu bar.
  6168. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6169. * one-html.html#ID-94282980">HTMLSelectElement</a>} p_oElement Object
  6170. * specifying the <code>&#60;select&#62;</code> element to be used as the data
  6171. * source for the menu bar.
  6172. * @param {Object} p_oConfig Optional. Object literal specifying the
  6173. * configuration for the menu bar. See configuration class documentation for
  6174. * more details.
  6175. */
  6176. init: function(p_oElement, p_oConfig) {
  6177. if(!this.ITEM_TYPE) {
  6178. this.ITEM_TYPE = YAHOO.widget.MenuBarItem;
  6179. }
  6180. // Call the init of the superclass (YAHOO.widget.Menu)
  6181. MenuBar.superclass.init.call(this, p_oElement);
  6182. this.beforeInitEvent.fire(MenuBar);
  6183. if(p_oConfig) {
  6184. this.cfg.applyConfig(p_oConfig, true);
  6185. }
  6186. this.initEvent.fire(MenuBar);
  6187. },
  6188. // Constants
  6189. /**
  6190. * @property CSS_CLASS_NAME
  6191. * @description String representing the CSS class(es) to be applied to the menu
  6192. * bar's <code>&#60;div&#62;</code> element.
  6193. * @default "yuimenubar"
  6194. * @final
  6195. * @type String
  6196. */
  6197. CSS_CLASS_NAME: "yuimenubar",
  6198. /**
  6199. * @property SUBMENU_TOGGLE_REGION_WIDTH
  6200. * @description Width (in pixels) of the area of a MenuBarItem that, when pressed, will toggle the
  6201. * display of the MenuBarItem's submenu.
  6202. * @default 20
  6203. * @final
  6204. * @type Number
  6205. */
  6206. SUBMENU_TOGGLE_REGION_WIDTH: 20,
  6207. // Protected event handlers
  6208. /**
  6209. * @method _onKeyDown
  6210. * @description "keydown" Custom Event handler for the menu bar.
  6211. * @private
  6212. * @param {String} p_sType String representing the name of the event that
  6213. * was fired.
  6214. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  6215. * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
  6216. * that fired the event.
  6217. */
  6218. _onKeyDown: function(p_sType, p_aArgs, p_oMenuBar) {
  6219. var oEvent = p_aArgs[0],
  6220. oItem = p_aArgs[1],
  6221. oSubmenu,
  6222. oItemCfg,
  6223. oNextItem;
  6224. if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
  6225. oItemCfg = oItem.cfg;
  6226. switch(oEvent.keyCode) {
  6227. case 37: // Left arrow
  6228. case 39: // Right arrow
  6229. if(oItem == this.activeItem && !oItemCfg.getProperty(_SELECTED)) {
  6230. oItemCfg.setProperty(_SELECTED, true);
  6231. }
  6232. else {
  6233. oNextItem = (oEvent.keyCode == 37) ?
  6234. oItem.getPreviousEnabledSibling() :
  6235. oItem.getNextEnabledSibling();
  6236. if(oNextItem) {
  6237. this.clearActiveItem();
  6238. oNextItem.cfg.setProperty(_SELECTED, true);
  6239. oSubmenu = oNextItem.cfg.getProperty(_SUBMENU);
  6240. if(oSubmenu) {
  6241. oSubmenu.show();
  6242. oSubmenu.setInitialFocus();
  6243. }
  6244. else {
  6245. oNextItem.focus();
  6246. }
  6247. }
  6248. }
  6249. Event.preventDefault(oEvent);
  6250. break;
  6251. case 40: // Down arrow
  6252. if(this.activeItem != oItem) {
  6253. this.clearActiveItem();
  6254. oItemCfg.setProperty(_SELECTED, true);
  6255. oItem.focus();
  6256. }
  6257. oSubmenu = oItemCfg.getProperty(_SUBMENU);
  6258. if(oSubmenu) {
  6259. if(oSubmenu.cfg.getProperty(_VISIBLE)) {
  6260. oSubmenu.setInitialSelection();
  6261. oSubmenu.setInitialFocus();
  6262. }
  6263. else {
  6264. oSubmenu.show();
  6265. oSubmenu.setInitialFocus();
  6266. }
  6267. }
  6268. Event.preventDefault(oEvent);
  6269. break;
  6270. }
  6271. }
  6272. if(oEvent.keyCode == 27 && this.activeItem) { // Esc key
  6273. oSubmenu = this.activeItem.cfg.getProperty(_SUBMENU);
  6274. if(oSubmenu && oSubmenu.cfg.getProperty(_VISIBLE)) {
  6275. oSubmenu.hide();
  6276. this.activeItem.focus();
  6277. }
  6278. else {
  6279. this.activeItem.cfg.setProperty(_SELECTED, false);
  6280. this.activeItem.blur();
  6281. }
  6282. Event.preventDefault(oEvent);
  6283. }
  6284. },
  6285. /**
  6286. * @method _onClick
  6287. * @description "click" event handler for the menu bar.
  6288. * @protected
  6289. * @param {String} p_sType String representing the name of the event that
  6290. * was fired.
  6291. * @param {Array} p_aArgs Array of arguments sent when the event was fired.
  6292. * @param {YAHOO.widget.MenuBar} p_oMenuBar Object representing the menu bar
  6293. * that fired the event.
  6294. */
  6295. _onClick: function(p_sType, p_aArgs, p_oMenuBar) {
  6296. MenuBar.superclass._onClick.call(this, p_sType, p_aArgs, p_oMenuBar);
  6297. var oItem = p_aArgs[1],
  6298. bReturnVal = true,
  6299. oItemEl,
  6300. oEvent,
  6301. oTarget,
  6302. oActiveItem,
  6303. oConfig,
  6304. oSubmenu,
  6305. nMenuItemX,
  6306. nToggleRegion;
  6307. var toggleSubmenuDisplay = function () {
  6308. if(oSubmenu.cfg.getProperty(_VISIBLE)) {
  6309. oSubmenu.hide();
  6310. }
  6311. else {
  6312. oSubmenu.show();
  6313. }
  6314. };
  6315. if(oItem && !oItem.cfg.getProperty(_DISABLED)) {
  6316. oEvent = p_aArgs[0];
  6317. oTarget = Event.getTarget(oEvent);
  6318. oActiveItem = this.activeItem;
  6319. oConfig = this.cfg;
  6320. // Hide any other submenus that might be visible
  6321. if(oActiveItem && oActiveItem != oItem) {
  6322. this.clearActiveItem();
  6323. }
  6324. oItem.cfg.setProperty(_SELECTED, true);
  6325. // Show the submenu for the item
  6326. oSubmenu = oItem.cfg.getProperty(_SUBMENU);
  6327. if(oSubmenu) {
  6328. oItemEl = oItem.element;
  6329. nMenuItemX = YAHOO.util.Dom.getX(oItemEl);
  6330. nToggleRegion = nMenuItemX + (oItemEl.offsetWidth - this.SUBMENU_TOGGLE_REGION_WIDTH);
  6331. if (oConfig.getProperty(_SUBMENU_TOGGLE_REGION)) {
  6332. if (Event.getPageX(oEvent) > nToggleRegion) {
  6333. toggleSubmenuDisplay();
  6334. Event.preventDefault(oEvent);
  6335. /*
  6336. Return false so that other click event handlers are not called when the
  6337. user clicks inside the toggle region.
  6338. */
  6339. bReturnVal = false;
  6340. }
  6341. }
  6342. else {
  6343. toggleSubmenuDisplay();
  6344. }
  6345. }
  6346. }
  6347. return bReturnVal;
  6348. },
  6349. // Public methods
  6350. /**
  6351. * @method configSubmenuToggle
  6352. * @description Event handler for when the "submenutoggleregion" configuration property of
  6353. * a MenuBar changes.
  6354. * @param {String} p_sType The name of the event that was fired.
  6355. * @param {Array} p_aArgs Collection of arguments sent when the event was fired.
  6356. */
  6357. configSubmenuToggle: function (p_sType, p_aArgs) {
  6358. var bSubmenuToggle = p_aArgs[0];
  6359. if (bSubmenuToggle) {
  6360. this.cfg.setProperty(_AUTO_SUBMENU_DISPLAY, false);
  6361. }
  6362. },
  6363. /**
  6364. * @method toString
  6365. * @description Returns a string representing the menu bar.
  6366. * @return {String}
  6367. */
  6368. toString: function() {
  6369. var sReturnVal = _MENUBAR,
  6370. sId = this.id;
  6371. if(sId) {
  6372. sReturnVal += (_SPACE + sId);
  6373. }
  6374. return sReturnVal;
  6375. },
  6376. /**
  6377. * @description Initializes the class's configurable properties which can be
  6378. * changed using the menu bar's Config object ("cfg").
  6379. * @method initDefaultConfig
  6380. */
  6381. initDefaultConfig: function() {
  6382. MenuBar.superclass.initDefaultConfig.call(this);
  6383. var oConfig = this.cfg;
  6384. // Add configuration properties
  6385. /*
  6386. Set the default value for the "position" configuration property
  6387. to "static" by re-adding the property.
  6388. */
  6389. /**
  6390. * @config position
  6391. * @description String indicating how a menu bar should be positioned on the
  6392. * screen. Possible values are "static" and "dynamic." Static menu bars
  6393. * are visible by default and reside in the normal flow of the document
  6394. * (CSS position: static). Dynamic menu bars are hidden by default, reside
  6395. * out of the normal flow of the document (CSS position: absolute), and can
  6396. * overlay other elements on the screen.
  6397. * @default static
  6398. * @type String
  6399. */
  6400. oConfig.addProperty(
  6401. POSITION_CONFIG.key,
  6402. {
  6403. handler: this.configPosition,
  6404. value: POSITION_CONFIG.value,
  6405. validator: POSITION_CONFIG.validator,
  6406. supercedes: POSITION_CONFIG.supercedes
  6407. }
  6408. );
  6409. /*
  6410. Set the default value for the "submenualignment" configuration property
  6411. to ["tl","bl"] by re-adding the property.
  6412. */
  6413. /**
  6414. * @config submenualignment
  6415. * @description Array defining how submenus should be aligned to their
  6416. * parent menu bar item. The format is: [itemCorner, submenuCorner].
  6417. * @default ["tl","bl"]
  6418. * @type Array
  6419. */
  6420. oConfig.addProperty(
  6421. SUBMENU_ALIGNMENT_CONFIG.key,
  6422. {
  6423. value: SUBMENU_ALIGNMENT_CONFIG.value,
  6424. suppressEvent: SUBMENU_ALIGNMENT_CONFIG.suppressEvent
  6425. }
  6426. );
  6427. /*
  6428. Change the default value for the "autosubmenudisplay" configuration
  6429. property to "false" by re-adding the property.
  6430. */
  6431. /**
  6432. * @config autosubmenudisplay
  6433. * @description Boolean indicating if submenus are automatically made
  6434. * visible when the user mouses over the menu bar's items.
  6435. * @default false
  6436. * @type Boolean
  6437. */
  6438. oConfig.addProperty(
  6439. AUTO_SUBMENU_DISPLAY_CONFIG.key,
  6440. {
  6441. value: AUTO_SUBMENU_DISPLAY_CONFIG.value,
  6442. validator: AUTO_SUBMENU_DISPLAY_CONFIG.validator,
  6443. suppressEvent: AUTO_SUBMENU_DISPLAY_CONFIG.suppressEvent
  6444. }
  6445. );
  6446. /**
  6447. * @config submenutoggleregion
  6448. * @description Boolean indicating if only a specific region of a MenuBarItem should toggle the
  6449. * display of a submenu. The default width of the region is determined by the value of the
  6450. * SUBMENU_TOGGLE_REGION_WIDTH property. If set to true, the autosubmenudisplay
  6451. * configuration property will be set to false, and any click event listeners will not be
  6452. * called when the user clicks inside the submenu toggle region of a MenuBarItem. If the
  6453. * user clicks outside of the submenu toggle region, the MenuBarItem will maintain its
  6454. * standard behavior.
  6455. * @default false
  6456. * @type Boolean
  6457. */
  6458. oConfig.addProperty(
  6459. SUBMENU_TOGGLE_REGION_CONFIG.key,
  6460. {
  6461. value: SUBMENU_TOGGLE_REGION_CONFIG.value,
  6462. validator: SUBMENU_TOGGLE_REGION_CONFIG.validator,
  6463. handler: this.configSubmenuToggle
  6464. }
  6465. );
  6466. }
  6467. }); // END YAHOO.lang.extend
  6468. }());
  6469. /**
  6470. * Creates an item for a menu bar.
  6471. *
  6472. * @param {String} p_oObject String specifying the text of the menu bar item.
  6473. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6474. * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
  6475. * <code>&#60;li&#62;</code> element of the menu bar item.
  6476. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6477. * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
  6478. * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
  6479. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6480. * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
  6481. * the <code>&#60;option&#62;</code> element of the menu bar item.
  6482. * @param {Object} p_oConfig Optional. Object literal specifying the
  6483. * configuration for the menu bar item. See configuration class documentation
  6484. * for more details.
  6485. * @class MenuBarItem
  6486. * @constructor
  6487. * @extends YAHOO.widget.MenuItem
  6488. */
  6489. YAHOO.widget.MenuBarItem = function(p_oObject, p_oConfig) {
  6490. YAHOO.widget.MenuBarItem.superclass.constructor.call(this, p_oObject, p_oConfig);
  6491. };
  6492. YAHOO.lang.extend(YAHOO.widget.MenuBarItem, YAHOO.widget.MenuItem, {
  6493. /**
  6494. * @method init
  6495. * @description The MenuBarItem class's initialization method. This method is
  6496. * automatically called by the constructor, and sets up all DOM references for
  6497. * pre-existing markup, and creates required markup if it is not already present.
  6498. * @param {String} p_oObject String specifying the text of the menu bar item.
  6499. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6500. * one-html.html#ID-74680021">HTMLLIElement</a>} p_oObject Object specifying the
  6501. * <code>&#60;li&#62;</code> element of the menu bar item.
  6502. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6503. * one-html.html#ID-38450247">HTMLOptGroupElement</a>} p_oObject Object
  6504. * specifying the <code>&#60;optgroup&#62;</code> element of the menu bar item.
  6505. * @param {<a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-
  6506. * one-html.html#ID-70901257">HTMLOptionElement</a>} p_oObject Object specifying
  6507. * the <code>&#60;option&#62;</code> element of the menu bar item.
  6508. * @param {Object} p_oConfig Optional. Object literal specifying the
  6509. * configuration for the menu bar item. See configuration class documentation
  6510. * for more details.
  6511. */
  6512. init: function(p_oObject, p_oConfig) {
  6513. if(!this.SUBMENU_TYPE) {
  6514. this.SUBMENU_TYPE = YAHOO.widget.Menu;
  6515. }
  6516. /*
  6517. Call the init of the superclass (YAHOO.widget.MenuItem)
  6518. Note: We don't pass the user config in here yet
  6519. because we only want it executed once, at the lowest
  6520. subclass level.
  6521. */
  6522. YAHOO.widget.MenuBarItem.superclass.init.call(this, p_oObject);
  6523. var oConfig = this.cfg;
  6524. if(p_oConfig) {
  6525. oConfig.applyConfig(p_oConfig, true);
  6526. }
  6527. oConfig.fireQueue();
  6528. },
  6529. // Constants
  6530. /**
  6531. * @property CSS_CLASS_NAME
  6532. * @description String representing the CSS class(es) to be applied to the
  6533. * <code>&#60;li&#62;</code> element of the menu bar item.
  6534. * @default "yuimenubaritem"
  6535. * @final
  6536. * @type String
  6537. */
  6538. CSS_CLASS_NAME: "yuimenubaritem",
  6539. /**
  6540. * @property CSS_LABEL_CLASS_NAME
  6541. * @description String representing the CSS class(es) to be applied to the
  6542. * menu bar item's <code>&#60;a&#62;</code> element.
  6543. * @default "yuimenubaritemlabel"
  6544. * @final
  6545. * @type String
  6546. */
  6547. CSS_LABEL_CLASS_NAME: "yuimenubaritemlabel",
  6548. // Public methods
  6549. /**
  6550. * @method toString
  6551. * @description Returns a string representing the menu bar item.
  6552. * @return {String}
  6553. */
  6554. toString: function() {
  6555. var sReturnVal = "MenuBarItem";
  6556. if(this.cfg && this.cfg.getProperty("text")) {
  6557. sReturnVal += (": " + this.cfg.getProperty("text"));
  6558. }
  6559. return sReturnVal;
  6560. }
  6561. }); // END YAHOO.lang.extend
  6562. YAHOO.register("menu", YAHOO.widget.Menu, {version: "2.8.0r4", build: "2449"});