container-debug.js 317 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077
  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. (function () {
  8. /**
  9. * Config is a utility used within an Object to allow the implementer to
  10. * maintain a list of local configuration properties and listen for changes
  11. * to those properties dynamically using CustomEvent. The initial values are
  12. * also maintained so that the configuration can be reset at any given point
  13. * to its initial state.
  14. * @namespace YAHOO.util
  15. * @class Config
  16. * @constructor
  17. * @param {Object} owner The owner Object to which this Config Object belongs
  18. */
  19. YAHOO.util.Config = function (owner) {
  20. if (owner) {
  21. this.init(owner);
  22. }
  23. if (!owner) { YAHOO.log("No owner specified for Config object", "error", "Config"); }
  24. };
  25. var Lang = YAHOO.lang,
  26. CustomEvent = YAHOO.util.CustomEvent,
  27. Config = YAHOO.util.Config;
  28. /**
  29. * Constant representing the CustomEvent type for the config changed event.
  30. * @property YAHOO.util.Config.CONFIG_CHANGED_EVENT
  31. * @private
  32. * @static
  33. * @final
  34. */
  35. Config.CONFIG_CHANGED_EVENT = "configChanged";
  36. /**
  37. * Constant representing the boolean type string
  38. * @property YAHOO.util.Config.BOOLEAN_TYPE
  39. * @private
  40. * @static
  41. * @final
  42. */
  43. Config.BOOLEAN_TYPE = "boolean";
  44. Config.prototype = {
  45. /**
  46. * Object reference to the owner of this Config Object
  47. * @property owner
  48. * @type Object
  49. */
  50. owner: null,
  51. /**
  52. * Boolean flag that specifies whether a queue is currently
  53. * being executed
  54. * @property queueInProgress
  55. * @type Boolean
  56. */
  57. queueInProgress: false,
  58. /**
  59. * Maintains the local collection of configuration property objects and
  60. * their specified values
  61. * @property config
  62. * @private
  63. * @type Object
  64. */
  65. config: null,
  66. /**
  67. * Maintains the local collection of configuration property objects as
  68. * they were initially applied.
  69. * This object is used when resetting a property.
  70. * @property initialConfig
  71. * @private
  72. * @type Object
  73. */
  74. initialConfig: null,
  75. /**
  76. * Maintains the local, normalized CustomEvent queue
  77. * @property eventQueue
  78. * @private
  79. * @type Object
  80. */
  81. eventQueue: null,
  82. /**
  83. * Custom Event, notifying subscribers when Config properties are set
  84. * (setProperty is called without the silent flag
  85. * @event configChangedEvent
  86. */
  87. configChangedEvent: null,
  88. /**
  89. * Initializes the configuration Object and all of its local members.
  90. * @method init
  91. * @param {Object} owner The owner Object to which this Config
  92. * Object belongs
  93. */
  94. init: function (owner) {
  95. this.owner = owner;
  96. this.configChangedEvent =
  97. this.createEvent(Config.CONFIG_CHANGED_EVENT);
  98. this.configChangedEvent.signature = CustomEvent.LIST;
  99. this.queueInProgress = false;
  100. this.config = {};
  101. this.initialConfig = {};
  102. this.eventQueue = [];
  103. },
  104. /**
  105. * Validates that the value passed in is a Boolean.
  106. * @method checkBoolean
  107. * @param {Object} val The value to validate
  108. * @return {Boolean} true, if the value is valid
  109. */
  110. checkBoolean: function (val) {
  111. return (typeof val == Config.BOOLEAN_TYPE);
  112. },
  113. /**
  114. * Validates that the value passed in is a number.
  115. * @method checkNumber
  116. * @param {Object} val The value to validate
  117. * @return {Boolean} true, if the value is valid
  118. */
  119. checkNumber: function (val) {
  120. return (!isNaN(val));
  121. },
  122. /**
  123. * Fires a configuration property event using the specified value.
  124. * @method fireEvent
  125. * @private
  126. * @param {String} key The configuration property's name
  127. * @param {value} Object The value of the correct type for the property
  128. */
  129. fireEvent: function ( key, value ) {
  130. YAHOO.log("Firing Config event: " + key + "=" + value, "info", "Config");
  131. var property = this.config[key];
  132. if (property && property.event) {
  133. property.event.fire(value);
  134. }
  135. },
  136. /**
  137. * Adds a property to the Config Object's private config hash.
  138. * @method addProperty
  139. * @param {String} key The configuration property's name
  140. * @param {Object} propertyObject The Object containing all of this
  141. * property's arguments
  142. */
  143. addProperty: function ( key, propertyObject ) {
  144. key = key.toLowerCase();
  145. YAHOO.log("Added property: " + key, "info", "Config");
  146. this.config[key] = propertyObject;
  147. propertyObject.event = this.createEvent(key, { scope: this.owner });
  148. propertyObject.event.signature = CustomEvent.LIST;
  149. propertyObject.key = key;
  150. if (propertyObject.handler) {
  151. propertyObject.event.subscribe(propertyObject.handler,
  152. this.owner);
  153. }
  154. this.setProperty(key, propertyObject.value, true);
  155. if (! propertyObject.suppressEvent) {
  156. this.queueProperty(key, propertyObject.value);
  157. }
  158. },
  159. /**
  160. * Returns a key-value configuration map of the values currently set in
  161. * the Config Object.
  162. * @method getConfig
  163. * @return {Object} The current config, represented in a key-value map
  164. */
  165. getConfig: function () {
  166. var cfg = {},
  167. currCfg = this.config,
  168. prop,
  169. property;
  170. for (prop in currCfg) {
  171. if (Lang.hasOwnProperty(currCfg, prop)) {
  172. property = currCfg[prop];
  173. if (property && property.event) {
  174. cfg[prop] = property.value;
  175. }
  176. }
  177. }
  178. return cfg;
  179. },
  180. /**
  181. * Returns the value of specified property.
  182. * @method getProperty
  183. * @param {String} key The name of the property
  184. * @return {Object} The value of the specified property
  185. */
  186. getProperty: function (key) {
  187. var property = this.config[key.toLowerCase()];
  188. if (property && property.event) {
  189. return property.value;
  190. } else {
  191. return undefined;
  192. }
  193. },
  194. /**
  195. * Resets the specified property's value to its initial value.
  196. * @method resetProperty
  197. * @param {String} key The name of the property
  198. * @return {Boolean} True is the property was reset, false if not
  199. */
  200. resetProperty: function (key) {
  201. key = key.toLowerCase();
  202. var property = this.config[key];
  203. if (property && property.event) {
  204. if (this.initialConfig[key] &&
  205. !Lang.isUndefined(this.initialConfig[key])) {
  206. this.setProperty(key, this.initialConfig[key]);
  207. return true;
  208. }
  209. } else {
  210. return false;
  211. }
  212. },
  213. /**
  214. * Sets the value of a property. If the silent property is passed as
  215. * true, the property's event will not be fired.
  216. * @method setProperty
  217. * @param {String} key The name of the property
  218. * @param {String} value The value to set the property to
  219. * @param {Boolean} silent Whether the value should be set silently,
  220. * without firing the property event.
  221. * @return {Boolean} True, if the set was successful, false if it failed.
  222. */
  223. setProperty: function (key, value, silent) {
  224. var property;
  225. key = key.toLowerCase();
  226. YAHOO.log("setProperty: " + key + "=" + value, "info", "Config");
  227. if (this.queueInProgress && ! silent) {
  228. // Currently running through a queue...
  229. this.queueProperty(key,value);
  230. return true;
  231. } else {
  232. property = this.config[key];
  233. if (property && property.event) {
  234. if (property.validator && !property.validator(value)) {
  235. return false;
  236. } else {
  237. property.value = value;
  238. if (! silent) {
  239. this.fireEvent(key, value);
  240. this.configChangedEvent.fire([key, value]);
  241. }
  242. return true;
  243. }
  244. } else {
  245. return false;
  246. }
  247. }
  248. },
  249. /**
  250. * Sets the value of a property and queues its event to execute. If the
  251. * event is already scheduled to execute, it is
  252. * moved from its current position to the end of the queue.
  253. * @method queueProperty
  254. * @param {String} key The name of the property
  255. * @param {String} value The value to set the property to
  256. * @return {Boolean} true, if the set was successful, false if
  257. * it failed.
  258. */
  259. queueProperty: function (key, value) {
  260. key = key.toLowerCase();
  261. YAHOO.log("queueProperty: " + key + "=" + value, "info", "Config");
  262. var property = this.config[key],
  263. foundDuplicate = false,
  264. iLen,
  265. queueItem,
  266. queueItemKey,
  267. queueItemValue,
  268. sLen,
  269. supercedesCheck,
  270. qLen,
  271. queueItemCheck,
  272. queueItemCheckKey,
  273. queueItemCheckValue,
  274. i,
  275. s,
  276. q;
  277. if (property && property.event) {
  278. if (!Lang.isUndefined(value) && property.validator &&
  279. !property.validator(value)) { // validator
  280. return false;
  281. } else {
  282. if (!Lang.isUndefined(value)) {
  283. property.value = value;
  284. } else {
  285. value = property.value;
  286. }
  287. foundDuplicate = false;
  288. iLen = this.eventQueue.length;
  289. for (i = 0; i < iLen; i++) {
  290. queueItem = this.eventQueue[i];
  291. if (queueItem) {
  292. queueItemKey = queueItem[0];
  293. queueItemValue = queueItem[1];
  294. if (queueItemKey == key) {
  295. /*
  296. found a dupe... push to end of queue, null
  297. current item, and break
  298. */
  299. this.eventQueue[i] = null;
  300. this.eventQueue.push(
  301. [key, (!Lang.isUndefined(value) ?
  302. value : queueItemValue)]);
  303. foundDuplicate = true;
  304. break;
  305. }
  306. }
  307. }
  308. // this is a refire, or a new property in the queue
  309. if (! foundDuplicate && !Lang.isUndefined(value)) {
  310. this.eventQueue.push([key, value]);
  311. }
  312. }
  313. if (property.supercedes) {
  314. sLen = property.supercedes.length;
  315. for (s = 0; s < sLen; s++) {
  316. supercedesCheck = property.supercedes[s];
  317. qLen = this.eventQueue.length;
  318. for (q = 0; q < qLen; q++) {
  319. queueItemCheck = this.eventQueue[q];
  320. if (queueItemCheck) {
  321. queueItemCheckKey = queueItemCheck[0];
  322. queueItemCheckValue = queueItemCheck[1];
  323. if (queueItemCheckKey ==
  324. supercedesCheck.toLowerCase() ) {
  325. this.eventQueue.push([queueItemCheckKey,
  326. queueItemCheckValue]);
  327. this.eventQueue[q] = null;
  328. break;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. YAHOO.log("Config event queue: " + this.outputEventQueue(), "info", "Config");
  335. return true;
  336. } else {
  337. return false;
  338. }
  339. },
  340. /**
  341. * Fires the event for a property using the property's current value.
  342. * @method refireEvent
  343. * @param {String} key The name of the property
  344. */
  345. refireEvent: function (key) {
  346. key = key.toLowerCase();
  347. var property = this.config[key];
  348. if (property && property.event &&
  349. !Lang.isUndefined(property.value)) {
  350. if (this.queueInProgress) {
  351. this.queueProperty(key);
  352. } else {
  353. this.fireEvent(key, property.value);
  354. }
  355. }
  356. },
  357. /**
  358. * Applies a key-value Object literal to the configuration, replacing
  359. * any existing values, and queueing the property events.
  360. * Although the values will be set, fireQueue() must be called for their
  361. * associated events to execute.
  362. * @method applyConfig
  363. * @param {Object} userConfig The configuration Object literal
  364. * @param {Boolean} init When set to true, the initialConfig will
  365. * be set to the userConfig passed in, so that calling a reset will
  366. * reset the properties to the passed values.
  367. */
  368. applyConfig: function (userConfig, init) {
  369. var sKey,
  370. oConfig;
  371. if (init) {
  372. oConfig = {};
  373. for (sKey in userConfig) {
  374. if (Lang.hasOwnProperty(userConfig, sKey)) {
  375. oConfig[sKey.toLowerCase()] = userConfig[sKey];
  376. }
  377. }
  378. this.initialConfig = oConfig;
  379. }
  380. for (sKey in userConfig) {
  381. if (Lang.hasOwnProperty(userConfig, sKey)) {
  382. this.queueProperty(sKey, userConfig[sKey]);
  383. }
  384. }
  385. },
  386. /**
  387. * Refires the events for all configuration properties using their
  388. * current values.
  389. * @method refresh
  390. */
  391. refresh: function () {
  392. var prop;
  393. for (prop in this.config) {
  394. if (Lang.hasOwnProperty(this.config, prop)) {
  395. this.refireEvent(prop);
  396. }
  397. }
  398. },
  399. /**
  400. * Fires the normalized list of queued property change events
  401. * @method fireQueue
  402. */
  403. fireQueue: function () {
  404. var i,
  405. queueItem,
  406. key,
  407. value,
  408. property;
  409. this.queueInProgress = true;
  410. for (i = 0;i < this.eventQueue.length; i++) {
  411. queueItem = this.eventQueue[i];
  412. if (queueItem) {
  413. key = queueItem[0];
  414. value = queueItem[1];
  415. property = this.config[key];
  416. property.value = value;
  417. // Clear out queue entry, to avoid it being
  418. // re-added to the queue by any queueProperty/supercedes
  419. // calls which are invoked during fireEvent
  420. this.eventQueue[i] = null;
  421. this.fireEvent(key,value);
  422. }
  423. }
  424. this.queueInProgress = false;
  425. this.eventQueue = [];
  426. },
  427. /**
  428. * Subscribes an external handler to the change event for any
  429. * given property.
  430. * @method subscribeToConfigEvent
  431. * @param {String} key The property name
  432. * @param {Function} handler The handler function to use subscribe to
  433. * the property's event
  434. * @param {Object} obj The Object to use for scoping the event handler
  435. * (see CustomEvent documentation)
  436. * @param {Boolean} overrideContext Optional. If true, will override
  437. * "this" within the handler to map to the scope Object passed into the
  438. * method.
  439. * @return {Boolean} True, if the subscription was successful,
  440. * otherwise false.
  441. */
  442. subscribeToConfigEvent: function (key, handler, obj, overrideContext) {
  443. var property = this.config[key.toLowerCase()];
  444. if (property && property.event) {
  445. if (!Config.alreadySubscribed(property.event, handler, obj)) {
  446. property.event.subscribe(handler, obj, overrideContext);
  447. }
  448. return true;
  449. } else {
  450. return false;
  451. }
  452. },
  453. /**
  454. * Unsubscribes an external handler from the change event for any
  455. * given property.
  456. * @method unsubscribeFromConfigEvent
  457. * @param {String} key The property name
  458. * @param {Function} handler The handler function to use subscribe to
  459. * the property's event
  460. * @param {Object} obj The Object to use for scoping the event
  461. * handler (see CustomEvent documentation)
  462. * @return {Boolean} True, if the unsubscription was successful,
  463. * otherwise false.
  464. */
  465. unsubscribeFromConfigEvent: function (key, handler, obj) {
  466. var property = this.config[key.toLowerCase()];
  467. if (property && property.event) {
  468. return property.event.unsubscribe(handler, obj);
  469. } else {
  470. return false;
  471. }
  472. },
  473. /**
  474. * Returns a string representation of the Config object
  475. * @method toString
  476. * @return {String} The Config object in string format.
  477. */
  478. toString: function () {
  479. var output = "Config";
  480. if (this.owner) {
  481. output += " [" + this.owner.toString() + "]";
  482. }
  483. return output;
  484. },
  485. /**
  486. * Returns a string representation of the Config object's current
  487. * CustomEvent queue
  488. * @method outputEventQueue
  489. * @return {String} The string list of CustomEvents currently queued
  490. * for execution
  491. */
  492. outputEventQueue: function () {
  493. var output = "",
  494. queueItem,
  495. q,
  496. nQueue = this.eventQueue.length;
  497. for (q = 0; q < nQueue; q++) {
  498. queueItem = this.eventQueue[q];
  499. if (queueItem) {
  500. output += queueItem[0] + "=" + queueItem[1] + ", ";
  501. }
  502. }
  503. return output;
  504. },
  505. /**
  506. * Sets all properties to null, unsubscribes all listeners from each
  507. * property's change event and all listeners from the configChangedEvent.
  508. * @method destroy
  509. */
  510. destroy: function () {
  511. var oConfig = this.config,
  512. sProperty,
  513. oProperty;
  514. for (sProperty in oConfig) {
  515. if (Lang.hasOwnProperty(oConfig, sProperty)) {
  516. oProperty = oConfig[sProperty];
  517. oProperty.event.unsubscribeAll();
  518. oProperty.event = null;
  519. }
  520. }
  521. this.configChangedEvent.unsubscribeAll();
  522. this.configChangedEvent = null;
  523. this.owner = null;
  524. this.config = null;
  525. this.initialConfig = null;
  526. this.eventQueue = null;
  527. }
  528. };
  529. /**
  530. * Checks to determine if a particular function/Object pair are already
  531. * subscribed to the specified CustomEvent
  532. * @method YAHOO.util.Config.alreadySubscribed
  533. * @static
  534. * @param {YAHOO.util.CustomEvent} evt The CustomEvent for which to check
  535. * the subscriptions
  536. * @param {Function} fn The function to look for in the subscribers list
  537. * @param {Object} obj The execution scope Object for the subscription
  538. * @return {Boolean} true, if the function/Object pair is already subscribed
  539. * to the CustomEvent passed in
  540. */
  541. Config.alreadySubscribed = function (evt, fn, obj) {
  542. var nSubscribers = evt.subscribers.length,
  543. subsc,
  544. i;
  545. if (nSubscribers > 0) {
  546. i = nSubscribers - 1;
  547. do {
  548. subsc = evt.subscribers[i];
  549. if (subsc && subsc.obj == obj && subsc.fn == fn) {
  550. return true;
  551. }
  552. }
  553. while (i--);
  554. }
  555. return false;
  556. };
  557. YAHOO.lang.augmentProto(Config, YAHOO.util.EventProvider);
  558. }());
  559. (function () {
  560. /**
  561. * The Container family of components is designed to enable developers to
  562. * create different kinds of content-containing modules on the web. Module
  563. * and Overlay are the most basic containers, and they can be used directly
  564. * or extended to build custom containers. Also part of the Container family
  565. * are four UI controls that extend Module and Overlay: Tooltip, Panel,
  566. * Dialog, and SimpleDialog.
  567. * @module container
  568. * @title Container
  569. * @requires yahoo, dom, event
  570. * @optional dragdrop, animation, button
  571. */
  572. /**
  573. * Module is a JavaScript representation of the Standard Module Format.
  574. * Standard Module Format is a simple standard for markup containers where
  575. * child nodes representing the header, body, and footer of the content are
  576. * denoted using the CSS classes "hd", "bd", and "ft" respectively.
  577. * Module is the base class for all other classes in the YUI
  578. * Container package.
  579. * @namespace YAHOO.widget
  580. * @class Module
  581. * @constructor
  582. * @param {String} el The element ID representing the Module <em>OR</em>
  583. * @param {HTMLElement} el The element representing the Module
  584. * @param {Object} userConfig The configuration Object literal containing
  585. * the configuration that should be set for this module. See configuration
  586. * documentation for more details.
  587. */
  588. YAHOO.widget.Module = function (el, userConfig) {
  589. if (el) {
  590. this.init(el, userConfig);
  591. } else {
  592. YAHOO.log("No element or element ID specified" +
  593. " for Module instantiation", "error");
  594. }
  595. };
  596. var Dom = YAHOO.util.Dom,
  597. Config = YAHOO.util.Config,
  598. Event = YAHOO.util.Event,
  599. CustomEvent = YAHOO.util.CustomEvent,
  600. Module = YAHOO.widget.Module,
  601. UA = YAHOO.env.ua,
  602. m_oModuleTemplate,
  603. m_oHeaderTemplate,
  604. m_oBodyTemplate,
  605. m_oFooterTemplate,
  606. /**
  607. * Constant representing the name of the Module's events
  608. * @property EVENT_TYPES
  609. * @private
  610. * @final
  611. * @type Object
  612. */
  613. EVENT_TYPES = {
  614. "BEFORE_INIT": "beforeInit",
  615. "INIT": "init",
  616. "APPEND": "append",
  617. "BEFORE_RENDER": "beforeRender",
  618. "RENDER": "render",
  619. "CHANGE_HEADER": "changeHeader",
  620. "CHANGE_BODY": "changeBody",
  621. "CHANGE_FOOTER": "changeFooter",
  622. "CHANGE_CONTENT": "changeContent",
  623. "DESTROY": "destroy",
  624. "BEFORE_SHOW": "beforeShow",
  625. "SHOW": "show",
  626. "BEFORE_HIDE": "beforeHide",
  627. "HIDE": "hide"
  628. },
  629. /**
  630. * Constant representing the Module's configuration properties
  631. * @property DEFAULT_CONFIG
  632. * @private
  633. * @final
  634. * @type Object
  635. */
  636. DEFAULT_CONFIG = {
  637. "VISIBLE": {
  638. key: "visible",
  639. value: true,
  640. validator: YAHOO.lang.isBoolean
  641. },
  642. "EFFECT": {
  643. key: "effect",
  644. suppressEvent: true,
  645. supercedes: ["visible"]
  646. },
  647. "MONITOR_RESIZE": {
  648. key: "monitorresize",
  649. value: true
  650. },
  651. "APPEND_TO_DOCUMENT_BODY": {
  652. key: "appendtodocumentbody",
  653. value: false
  654. }
  655. };
  656. /**
  657. * Constant representing the prefix path to use for non-secure images
  658. * @property YAHOO.widget.Module.IMG_ROOT
  659. * @static
  660. * @final
  661. * @type String
  662. */
  663. Module.IMG_ROOT = null;
  664. /**
  665. * Constant representing the prefix path to use for securely served images
  666. * @property YAHOO.widget.Module.IMG_ROOT_SSL
  667. * @static
  668. * @final
  669. * @type String
  670. */
  671. Module.IMG_ROOT_SSL = null;
  672. /**
  673. * Constant for the default CSS class name that represents a Module
  674. * @property YAHOO.widget.Module.CSS_MODULE
  675. * @static
  676. * @final
  677. * @type String
  678. */
  679. Module.CSS_MODULE = "yui-module";
  680. /**
  681. * Constant representing the module header
  682. * @property YAHOO.widget.Module.CSS_HEADER
  683. * @static
  684. * @final
  685. * @type String
  686. */
  687. Module.CSS_HEADER = "hd";
  688. /**
  689. * Constant representing the module body
  690. * @property YAHOO.widget.Module.CSS_BODY
  691. * @static
  692. * @final
  693. * @type String
  694. */
  695. Module.CSS_BODY = "bd";
  696. /**
  697. * Constant representing the module footer
  698. * @property YAHOO.widget.Module.CSS_FOOTER
  699. * @static
  700. * @final
  701. * @type String
  702. */
  703. Module.CSS_FOOTER = "ft";
  704. /**
  705. * Constant representing the url for the "src" attribute of the iframe
  706. * used to monitor changes to the browser's base font size
  707. * @property YAHOO.widget.Module.RESIZE_MONITOR_SECURE_URL
  708. * @static
  709. * @final
  710. * @type String
  711. */
  712. Module.RESIZE_MONITOR_SECURE_URL = "javascript:false;";
  713. /**
  714. * Constant representing the buffer amount (in pixels) to use when positioning
  715. * the text resize monitor offscreen. The resize monitor is positioned
  716. * offscreen by an amount eqaul to its offsetHeight + the buffer value.
  717. *
  718. * @property YAHOO.widget.Module.RESIZE_MONITOR_BUFFER
  719. * @static
  720. * @type Number
  721. */
  722. // Set to 1, to work around pixel offset in IE8, which increases when zoom is used
  723. Module.RESIZE_MONITOR_BUFFER = 1;
  724. /**
  725. * Singleton CustomEvent fired when the font size is changed in the browser.
  726. * Opera's "zoom" functionality currently does not support text
  727. * size detection.
  728. * @event YAHOO.widget.Module.textResizeEvent
  729. */
  730. Module.textResizeEvent = new CustomEvent("textResize");
  731. /**
  732. * Helper utility method, which forces a document level
  733. * redraw for Opera, which can help remove repaint
  734. * irregularities after applying DOM changes.
  735. *
  736. * @method YAHOO.widget.Module.forceDocumentRedraw
  737. * @static
  738. */
  739. Module.forceDocumentRedraw = function() {
  740. var docEl = document.documentElement;
  741. if (docEl) {
  742. docEl.className += " ";
  743. docEl.className = YAHOO.lang.trim(docEl.className);
  744. }
  745. };
  746. function createModuleTemplate() {
  747. if (!m_oModuleTemplate) {
  748. m_oModuleTemplate = document.createElement("div");
  749. m_oModuleTemplate.innerHTML = ("<div class=\"" +
  750. Module.CSS_HEADER + "\"></div>" + "<div class=\"" +
  751. Module.CSS_BODY + "\"></div><div class=\"" +
  752. Module.CSS_FOOTER + "\"></div>");
  753. m_oHeaderTemplate = m_oModuleTemplate.firstChild;
  754. m_oBodyTemplate = m_oHeaderTemplate.nextSibling;
  755. m_oFooterTemplate = m_oBodyTemplate.nextSibling;
  756. }
  757. return m_oModuleTemplate;
  758. }
  759. function createHeader() {
  760. if (!m_oHeaderTemplate) {
  761. createModuleTemplate();
  762. }
  763. return (m_oHeaderTemplate.cloneNode(false));
  764. }
  765. function createBody() {
  766. if (!m_oBodyTemplate) {
  767. createModuleTemplate();
  768. }
  769. return (m_oBodyTemplate.cloneNode(false));
  770. }
  771. function createFooter() {
  772. if (!m_oFooterTemplate) {
  773. createModuleTemplate();
  774. }
  775. return (m_oFooterTemplate.cloneNode(false));
  776. }
  777. Module.prototype = {
  778. /**
  779. * The class's constructor function
  780. * @property contructor
  781. * @type Function
  782. */
  783. constructor: Module,
  784. /**
  785. * The main module element that contains the header, body, and footer
  786. * @property element
  787. * @type HTMLElement
  788. */
  789. element: null,
  790. /**
  791. * The header element, denoted with CSS class "hd"
  792. * @property header
  793. * @type HTMLElement
  794. */
  795. header: null,
  796. /**
  797. * The body element, denoted with CSS class "bd"
  798. * @property body
  799. * @type HTMLElement
  800. */
  801. body: null,
  802. /**
  803. * The footer element, denoted with CSS class "ft"
  804. * @property footer
  805. * @type HTMLElement
  806. */
  807. footer: null,
  808. /**
  809. * The id of the element
  810. * @property id
  811. * @type String
  812. */
  813. id: null,
  814. /**
  815. * A string representing the root path for all images created by
  816. * a Module instance.
  817. * @deprecated It is recommend that any images for a Module be applied
  818. * via CSS using the "background-image" property.
  819. * @property imageRoot
  820. * @type String
  821. */
  822. imageRoot: Module.IMG_ROOT,
  823. /**
  824. * Initializes the custom events for Module which are fired
  825. * automatically at appropriate times by the Module class.
  826. * @method initEvents
  827. */
  828. initEvents: function () {
  829. var SIGNATURE = CustomEvent.LIST;
  830. /**
  831. * CustomEvent fired prior to class initalization.
  832. * @event beforeInitEvent
  833. * @param {class} classRef class reference of the initializing
  834. * class, such as this.beforeInitEvent.fire(Module)
  835. */
  836. this.beforeInitEvent = this.createEvent(EVENT_TYPES.BEFORE_INIT);
  837. this.beforeInitEvent.signature = SIGNATURE;
  838. /**
  839. * CustomEvent fired after class initalization.
  840. * @event initEvent
  841. * @param {class} classRef class reference of the initializing
  842. * class, such as this.beforeInitEvent.fire(Module)
  843. */
  844. this.initEvent = this.createEvent(EVENT_TYPES.INIT);
  845. this.initEvent.signature = SIGNATURE;
  846. /**
  847. * CustomEvent fired when the Module is appended to the DOM
  848. * @event appendEvent
  849. */
  850. this.appendEvent = this.createEvent(EVENT_TYPES.APPEND);
  851. this.appendEvent.signature = SIGNATURE;
  852. /**
  853. * CustomEvent fired before the Module is rendered
  854. * @event beforeRenderEvent
  855. */
  856. this.beforeRenderEvent = this.createEvent(EVENT_TYPES.BEFORE_RENDER);
  857. this.beforeRenderEvent.signature = SIGNATURE;
  858. /**
  859. * CustomEvent fired after the Module is rendered
  860. * @event renderEvent
  861. */
  862. this.renderEvent = this.createEvent(EVENT_TYPES.RENDER);
  863. this.renderEvent.signature = SIGNATURE;
  864. /**
  865. * CustomEvent fired when the header content of the Module
  866. * is modified
  867. * @event changeHeaderEvent
  868. * @param {String/HTMLElement} content String/element representing
  869. * the new header content
  870. */
  871. this.changeHeaderEvent = this.createEvent(EVENT_TYPES.CHANGE_HEADER);
  872. this.changeHeaderEvent.signature = SIGNATURE;
  873. /**
  874. * CustomEvent fired when the body content of the Module is modified
  875. * @event changeBodyEvent
  876. * @param {String/HTMLElement} content String/element representing
  877. * the new body content
  878. */
  879. this.changeBodyEvent = this.createEvent(EVENT_TYPES.CHANGE_BODY);
  880. this.changeBodyEvent.signature = SIGNATURE;
  881. /**
  882. * CustomEvent fired when the footer content of the Module
  883. * is modified
  884. * @event changeFooterEvent
  885. * @param {String/HTMLElement} content String/element representing
  886. * the new footer content
  887. */
  888. this.changeFooterEvent = this.createEvent(EVENT_TYPES.CHANGE_FOOTER);
  889. this.changeFooterEvent.signature = SIGNATURE;
  890. /**
  891. * CustomEvent fired when the content of the Module is modified
  892. * @event changeContentEvent
  893. */
  894. this.changeContentEvent = this.createEvent(EVENT_TYPES.CHANGE_CONTENT);
  895. this.changeContentEvent.signature = SIGNATURE;
  896. /**
  897. * CustomEvent fired when the Module is destroyed
  898. * @event destroyEvent
  899. */
  900. this.destroyEvent = this.createEvent(EVENT_TYPES.DESTROY);
  901. this.destroyEvent.signature = SIGNATURE;
  902. /**
  903. * CustomEvent fired before the Module is shown
  904. * @event beforeShowEvent
  905. */
  906. this.beforeShowEvent = this.createEvent(EVENT_TYPES.BEFORE_SHOW);
  907. this.beforeShowEvent.signature = SIGNATURE;
  908. /**
  909. * CustomEvent fired after the Module is shown
  910. * @event showEvent
  911. */
  912. this.showEvent = this.createEvent(EVENT_TYPES.SHOW);
  913. this.showEvent.signature = SIGNATURE;
  914. /**
  915. * CustomEvent fired before the Module is hidden
  916. * @event beforeHideEvent
  917. */
  918. this.beforeHideEvent = this.createEvent(EVENT_TYPES.BEFORE_HIDE);
  919. this.beforeHideEvent.signature = SIGNATURE;
  920. /**
  921. * CustomEvent fired after the Module is hidden
  922. * @event hideEvent
  923. */
  924. this.hideEvent = this.createEvent(EVENT_TYPES.HIDE);
  925. this.hideEvent.signature = SIGNATURE;
  926. },
  927. /**
  928. * String representing the current user-agent platform
  929. * @property platform
  930. * @type String
  931. */
  932. platform: function () {
  933. var ua = navigator.userAgent.toLowerCase();
  934. if (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1) {
  935. return "windows";
  936. } else if (ua.indexOf("macintosh") != -1) {
  937. return "mac";
  938. } else {
  939. return false;
  940. }
  941. }(),
  942. /**
  943. * String representing the user-agent of the browser
  944. * @deprecated Use YAHOO.env.ua
  945. * @property browser
  946. * @type String
  947. */
  948. browser: function () {
  949. var ua = navigator.userAgent.toLowerCase();
  950. /*
  951. Check Opera first in case of spoof and check Safari before
  952. Gecko since Safari's user agent string includes "like Gecko"
  953. */
  954. if (ua.indexOf('opera') != -1) {
  955. return 'opera';
  956. } else if (ua.indexOf('msie 7') != -1) {
  957. return 'ie7';
  958. } else if (ua.indexOf('msie') != -1) {
  959. return 'ie';
  960. } else if (ua.indexOf('safari') != -1) {
  961. return 'safari';
  962. } else if (ua.indexOf('gecko') != -1) {
  963. return 'gecko';
  964. } else {
  965. return false;
  966. }
  967. }(),
  968. /**
  969. * Boolean representing whether or not the current browsing context is
  970. * secure (https)
  971. * @property isSecure
  972. * @type Boolean
  973. */
  974. isSecure: function () {
  975. if (window.location.href.toLowerCase().indexOf("https") === 0) {
  976. return true;
  977. } else {
  978. return false;
  979. }
  980. }(),
  981. /**
  982. * Initializes the custom events for Module which are fired
  983. * automatically at appropriate times by the Module class.
  984. */
  985. initDefaultConfig: function () {
  986. // Add properties //
  987. /**
  988. * Specifies whether the Module is visible on the page.
  989. * @config visible
  990. * @type Boolean
  991. * @default true
  992. */
  993. this.cfg.addProperty(DEFAULT_CONFIG.VISIBLE.key, {
  994. handler: this.configVisible,
  995. value: DEFAULT_CONFIG.VISIBLE.value,
  996. validator: DEFAULT_CONFIG.VISIBLE.validator
  997. });
  998. /**
  999. * <p>
  1000. * Object or array of objects representing the ContainerEffect
  1001. * classes that are active for animating the container.
  1002. * </p>
  1003. * <p>
  1004. * <strong>NOTE:</strong> Although this configuration
  1005. * property is introduced at the Module level, an out of the box
  1006. * implementation is not shipped for the Module class so setting
  1007. * the proroperty on the Module class has no effect. The Overlay
  1008. * class is the first class to provide out of the box ContainerEffect
  1009. * support.
  1010. * </p>
  1011. * @config effect
  1012. * @type Object
  1013. * @default null
  1014. */
  1015. this.cfg.addProperty(DEFAULT_CONFIG.EFFECT.key, {
  1016. suppressEvent: DEFAULT_CONFIG.EFFECT.suppressEvent,
  1017. supercedes: DEFAULT_CONFIG.EFFECT.supercedes
  1018. });
  1019. /**
  1020. * Specifies whether to create a special proxy iframe to monitor
  1021. * for user font resizing in the document
  1022. * @config monitorresize
  1023. * @type Boolean
  1024. * @default true
  1025. */
  1026. this.cfg.addProperty(DEFAULT_CONFIG.MONITOR_RESIZE.key, {
  1027. handler: this.configMonitorResize,
  1028. value: DEFAULT_CONFIG.MONITOR_RESIZE.value
  1029. });
  1030. /**
  1031. * Specifies if the module should be rendered as the first child
  1032. * of document.body or appended as the last child when render is called
  1033. * with document.body as the "appendToNode".
  1034. * <p>
  1035. * Appending to the body while the DOM is still being constructed can
  1036. * lead to Operation Aborted errors in IE hence this flag is set to
  1037. * false by default.
  1038. * </p>
  1039. *
  1040. * @config appendtodocumentbody
  1041. * @type Boolean
  1042. * @default false
  1043. */
  1044. this.cfg.addProperty(DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.key, {
  1045. value: DEFAULT_CONFIG.APPEND_TO_DOCUMENT_BODY.value
  1046. });
  1047. },
  1048. /**
  1049. * The Module class's initialization method, which is executed for
  1050. * Module and all of its subclasses. This method is automatically
  1051. * called by the constructor, and sets up all DOM references for
  1052. * pre-existing markup, and creates required markup if it is not
  1053. * already present.
  1054. * <p>
  1055. * If the element passed in does not have an id, one will be generated
  1056. * for it.
  1057. * </p>
  1058. * @method init
  1059. * @param {String} el The element ID representing the Module <em>OR</em>
  1060. * @param {HTMLElement} el The element representing the Module
  1061. * @param {Object} userConfig The configuration Object literal
  1062. * containing the configuration that should be set for this module.
  1063. * See configuration documentation for more details.
  1064. */
  1065. init: function (el, userConfig) {
  1066. var elId, child;
  1067. this.initEvents();
  1068. this.beforeInitEvent.fire(Module);
  1069. /**
  1070. * The Module's Config object used for monitoring
  1071. * configuration properties.
  1072. * @property cfg
  1073. * @type YAHOO.util.Config
  1074. */
  1075. this.cfg = new Config(this);
  1076. if (this.isSecure) {
  1077. this.imageRoot = Module.IMG_ROOT_SSL;
  1078. }
  1079. if (typeof el == "string") {
  1080. elId = el;
  1081. el = document.getElementById(el);
  1082. if (! el) {
  1083. el = (createModuleTemplate()).cloneNode(false);
  1084. el.id = elId;
  1085. }
  1086. }
  1087. this.id = Dom.generateId(el);
  1088. this.element = el;
  1089. child = this.element.firstChild;
  1090. if (child) {
  1091. var fndHd = false, fndBd = false, fndFt = false;
  1092. do {
  1093. // We're looking for elements
  1094. if (1 == child.nodeType) {
  1095. if (!fndHd && Dom.hasClass(child, Module.CSS_HEADER)) {
  1096. this.header = child;
  1097. fndHd = true;
  1098. } else if (!fndBd && Dom.hasClass(child, Module.CSS_BODY)) {
  1099. this.body = child;
  1100. fndBd = true;
  1101. } else if (!fndFt && Dom.hasClass(child, Module.CSS_FOOTER)){
  1102. this.footer = child;
  1103. fndFt = true;
  1104. }
  1105. }
  1106. } while ((child = child.nextSibling));
  1107. }
  1108. this.initDefaultConfig();
  1109. Dom.addClass(this.element, Module.CSS_MODULE);
  1110. if (userConfig) {
  1111. this.cfg.applyConfig(userConfig, true);
  1112. }
  1113. /*
  1114. Subscribe to the fireQueue() method of Config so that any
  1115. queued configuration changes are excecuted upon render of
  1116. the Module
  1117. */
  1118. if (!Config.alreadySubscribed(this.renderEvent, this.cfg.fireQueue, this.cfg)) {
  1119. this.renderEvent.subscribe(this.cfg.fireQueue, this.cfg, true);
  1120. }
  1121. this.initEvent.fire(Module);
  1122. },
  1123. /**
  1124. * Initialize an empty IFRAME that is placed out of the visible area
  1125. * that can be used to detect text resize.
  1126. * @method initResizeMonitor
  1127. */
  1128. initResizeMonitor: function () {
  1129. var isGeckoWin = (UA.gecko && this.platform == "windows");
  1130. if (isGeckoWin) {
  1131. // Help prevent spinning loading icon which
  1132. // started with FireFox 2.0.0.8/Win
  1133. var self = this;
  1134. setTimeout(function(){self._initResizeMonitor();}, 0);
  1135. } else {
  1136. this._initResizeMonitor();
  1137. }
  1138. },
  1139. /**
  1140. * Create and initialize the text resize monitoring iframe.
  1141. *
  1142. * @protected
  1143. * @method _initResizeMonitor
  1144. */
  1145. _initResizeMonitor : function() {
  1146. var oDoc,
  1147. oIFrame,
  1148. sHTML;
  1149. function fireTextResize() {
  1150. Module.textResizeEvent.fire();
  1151. }
  1152. if (!UA.opera) {
  1153. oIFrame = Dom.get("_yuiResizeMonitor");
  1154. var supportsCWResize = this._supportsCWResize();
  1155. if (!oIFrame) {
  1156. oIFrame = document.createElement("iframe");
  1157. if (this.isSecure && Module.RESIZE_MONITOR_SECURE_URL && UA.ie) {
  1158. oIFrame.src = Module.RESIZE_MONITOR_SECURE_URL;
  1159. }
  1160. if (!supportsCWResize) {
  1161. // Can't monitor on contentWindow, so fire from inside iframe
  1162. sHTML = ["<html><head><script ",
  1163. "type=\"text/javascript\">",
  1164. "window.onresize=function(){window.parent.",
  1165. "YAHOO.widget.Module.textResizeEvent.",
  1166. "fire();};<",
  1167. "\/script></head>",
  1168. "<body></body></html>"].join('');
  1169. oIFrame.src = "data:text/html;charset=utf-8," + encodeURIComponent(sHTML);
  1170. }
  1171. oIFrame.id = "_yuiResizeMonitor";
  1172. oIFrame.title = "Text Resize Monitor";
  1173. /*
  1174. Need to set "position" property before inserting the
  1175. iframe into the document or Safari's status bar will
  1176. forever indicate the iframe is loading
  1177. (See YUILibrary bug #1723064)
  1178. */
  1179. oIFrame.style.position = "absolute";
  1180. oIFrame.style.visibility = "hidden";
  1181. var db = document.body,
  1182. fc = db.firstChild;
  1183. if (fc) {
  1184. db.insertBefore(oIFrame, fc);
  1185. } else {
  1186. db.appendChild(oIFrame);
  1187. }
  1188. // Setting the background color fixes an issue with IE6/IE7, where
  1189. // elements in the DOM, with -ve margin-top which positioned them
  1190. // offscreen (so they would be overlapped by the iframe and its -ve top
  1191. // setting), would have their -ve margin-top ignored, when the iframe
  1192. // was added.
  1193. oIFrame.style.backgroundColor = "transparent";
  1194. oIFrame.style.borderWidth = "0";
  1195. oIFrame.style.width = "2em";
  1196. oIFrame.style.height = "2em";
  1197. oIFrame.style.left = "0";
  1198. oIFrame.style.top = (-1 * (oIFrame.offsetHeight + Module.RESIZE_MONITOR_BUFFER)) + "px";
  1199. oIFrame.style.visibility = "visible";
  1200. /*
  1201. Don't open/close the document for Gecko like we used to, since it
  1202. leads to duplicate cookies. (See YUILibrary bug #1721755)
  1203. */
  1204. if (UA.webkit) {
  1205. oDoc = oIFrame.contentWindow.document;
  1206. oDoc.open();
  1207. oDoc.close();
  1208. }
  1209. }
  1210. if (oIFrame && oIFrame.contentWindow) {
  1211. Module.textResizeEvent.subscribe(this.onDomResize, this, true);
  1212. if (!Module.textResizeInitialized) {
  1213. if (supportsCWResize) {
  1214. if (!Event.on(oIFrame.contentWindow, "resize", fireTextResize)) {
  1215. /*
  1216. This will fail in IE if document.domain has
  1217. changed, so we must change the listener to
  1218. use the oIFrame element instead
  1219. */
  1220. Event.on(oIFrame, "resize", fireTextResize);
  1221. }
  1222. }
  1223. Module.textResizeInitialized = true;
  1224. }
  1225. this.resizeMonitor = oIFrame;
  1226. }
  1227. }
  1228. },
  1229. /**
  1230. * Text resize monitor helper method.
  1231. * Determines if the browser supports resize events on iframe content windows.
  1232. *
  1233. * @private
  1234. * @method _supportsCWResize
  1235. */
  1236. _supportsCWResize : function() {
  1237. /*
  1238. Gecko 1.8.0 (FF1.5), 1.8.1.0-5 (FF2) won't fire resize on contentWindow.
  1239. Gecko 1.8.1.6+ (FF2.0.0.6+) and all other browsers will fire resize on contentWindow.
  1240. We don't want to start sniffing for patch versions, so fire textResize the same
  1241. way on all FF2 flavors
  1242. */
  1243. var bSupported = true;
  1244. if (UA.gecko && UA.gecko <= 1.8) {
  1245. bSupported = false;
  1246. }
  1247. return bSupported;
  1248. },
  1249. /**
  1250. * Event handler fired when the resize monitor element is resized.
  1251. * @method onDomResize
  1252. * @param {DOMEvent} e The DOM resize event
  1253. * @param {Object} obj The scope object passed to the handler
  1254. */
  1255. onDomResize: function (e, obj) {
  1256. var nTop = -1 * (this.resizeMonitor.offsetHeight + Module.RESIZE_MONITOR_BUFFER);
  1257. this.resizeMonitor.style.top = nTop + "px";
  1258. this.resizeMonitor.style.left = "0";
  1259. },
  1260. /**
  1261. * Sets the Module's header content to the string specified, or appends
  1262. * the passed element to the header. If no header is present, one will
  1263. * be automatically created. An empty string can be passed to the method
  1264. * to clear the contents of the header.
  1265. *
  1266. * @method setHeader
  1267. * @param {String} headerContent The string used to set the header.
  1268. * As a convenience, non HTMLElement objects can also be passed into
  1269. * the method, and will be treated as strings, with the header innerHTML
  1270. * set to their default toString implementations.
  1271. * <em>OR</em>
  1272. * @param {HTMLElement} headerContent The HTMLElement to append to
  1273. * <em>OR</em>
  1274. * @param {DocumentFragment} headerContent The document fragment
  1275. * containing elements which are to be added to the header
  1276. */
  1277. setHeader: function (headerContent) {
  1278. var oHeader = this.header || (this.header = createHeader());
  1279. if (headerContent.nodeName) {
  1280. oHeader.innerHTML = "";
  1281. oHeader.appendChild(headerContent);
  1282. } else {
  1283. oHeader.innerHTML = headerContent;
  1284. }
  1285. if (this._rendered) {
  1286. this._renderHeader();
  1287. }
  1288. this.changeHeaderEvent.fire(headerContent);
  1289. this.changeContentEvent.fire();
  1290. },
  1291. /**
  1292. * Appends the passed element to the header. If no header is present,
  1293. * one will be automatically created.
  1294. * @method appendToHeader
  1295. * @param {HTMLElement | DocumentFragment} element The element to
  1296. * append to the header. In the case of a document fragment, the
  1297. * children of the fragment will be appended to the header.
  1298. */
  1299. appendToHeader: function (element) {
  1300. var oHeader = this.header || (this.header = createHeader());
  1301. oHeader.appendChild(element);
  1302. this.changeHeaderEvent.fire(element);
  1303. this.changeContentEvent.fire();
  1304. },
  1305. /**
  1306. * Sets the Module's body content to the HTML specified.
  1307. *
  1308. * If no body is present, one will be automatically created.
  1309. *
  1310. * An empty string can be passed to the method to clear the contents of the body.
  1311. * @method setBody
  1312. * @param {String} bodyContent The HTML used to set the body.
  1313. * As a convenience, non HTMLElement objects can also be passed into
  1314. * the method, and will be treated as strings, with the body innerHTML
  1315. * set to their default toString implementations.
  1316. * <em>OR</em>
  1317. * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only
  1318. * child of the body element.
  1319. * <em>OR</em>
  1320. * @param {DocumentFragment} bodyContent The document fragment
  1321. * containing elements which are to be added to the body
  1322. */
  1323. setBody: function (bodyContent) {
  1324. var oBody = this.body || (this.body = createBody());
  1325. if (bodyContent.nodeName) {
  1326. oBody.innerHTML = "";
  1327. oBody.appendChild(bodyContent);
  1328. } else {
  1329. oBody.innerHTML = bodyContent;
  1330. }
  1331. if (this._rendered) {
  1332. this._renderBody();
  1333. }
  1334. this.changeBodyEvent.fire(bodyContent);
  1335. this.changeContentEvent.fire();
  1336. },
  1337. /**
  1338. * Appends the passed element to the body. If no body is present, one
  1339. * will be automatically created.
  1340. * @method appendToBody
  1341. * @param {HTMLElement | DocumentFragment} element The element to
  1342. * append to the body. In the case of a document fragment, the
  1343. * children of the fragment will be appended to the body.
  1344. *
  1345. */
  1346. appendToBody: function (element) {
  1347. var oBody = this.body || (this.body = createBody());
  1348. oBody.appendChild(element);
  1349. this.changeBodyEvent.fire(element);
  1350. this.changeContentEvent.fire();
  1351. },
  1352. /**
  1353. * Sets the Module's footer content to the HTML specified, or appends
  1354. * the passed element to the footer. If no footer is present, one will
  1355. * be automatically created. An empty string can be passed to the method
  1356. * to clear the contents of the footer.
  1357. * @method setFooter
  1358. * @param {String} footerContent The HTML used to set the footer
  1359. * As a convenience, non HTMLElement objects can also be passed into
  1360. * the method, and will be treated as strings, with the footer innerHTML
  1361. * set to their default toString implementations.
  1362. * <em>OR</em>
  1363. * @param {HTMLElement} footerContent The HTMLElement to append to
  1364. * the footer
  1365. * <em>OR</em>
  1366. * @param {DocumentFragment} footerContent The document fragment containing
  1367. * elements which are to be added to the footer
  1368. */
  1369. setFooter: function (footerContent) {
  1370. var oFooter = this.footer || (this.footer = createFooter());
  1371. if (footerContent.nodeName) {
  1372. oFooter.innerHTML = "";
  1373. oFooter.appendChild(footerContent);
  1374. } else {
  1375. oFooter.innerHTML = footerContent;
  1376. }
  1377. if (this._rendered) {
  1378. this._renderFooter();
  1379. }
  1380. this.changeFooterEvent.fire(footerContent);
  1381. this.changeContentEvent.fire();
  1382. },
  1383. /**
  1384. * Appends the passed element to the footer. If no footer is present,
  1385. * one will be automatically created.
  1386. * @method appendToFooter
  1387. * @param {HTMLElement | DocumentFragment} element The element to
  1388. * append to the footer. In the case of a document fragment, the
  1389. * children of the fragment will be appended to the footer
  1390. */
  1391. appendToFooter: function (element) {
  1392. var oFooter = this.footer || (this.footer = createFooter());
  1393. oFooter.appendChild(element);
  1394. this.changeFooterEvent.fire(element);
  1395. this.changeContentEvent.fire();
  1396. },
  1397. /**
  1398. * Renders the Module by inserting the elements that are not already
  1399. * in the main Module into their correct places. Optionally appends
  1400. * the Module to the specified node prior to the render's execution.
  1401. * <p>
  1402. * For Modules without existing markup, the appendToNode argument
  1403. * is REQUIRED. If this argument is ommitted and the current element is
  1404. * not present in the document, the function will return false,
  1405. * indicating that the render was a failure.
  1406. * </p>
  1407. * <p>
  1408. * NOTE: As of 2.3.1, if the appendToNode is the document's body element
  1409. * then the module is rendered as the first child of the body element,
  1410. * and not appended to it, to avoid Operation Aborted errors in IE when
  1411. * rendering the module before window's load event is fired. You can
  1412. * use the appendtodocumentbody configuration property to change this
  1413. * to append to document.body if required.
  1414. * </p>
  1415. * @method render
  1416. * @param {String} appendToNode The element id to which the Module
  1417. * should be appended to prior to rendering <em>OR</em>
  1418. * @param {HTMLElement} appendToNode The element to which the Module
  1419. * should be appended to prior to rendering
  1420. * @param {HTMLElement} moduleElement OPTIONAL. The element that
  1421. * represents the actual Standard Module container.
  1422. * @return {Boolean} Success or failure of the render
  1423. */
  1424. render: function (appendToNode, moduleElement) {
  1425. var me = this;
  1426. function appendTo(parentNode) {
  1427. if (typeof parentNode == "string") {
  1428. parentNode = document.getElementById(parentNode);
  1429. }
  1430. if (parentNode) {
  1431. me._addToParent(parentNode, me.element);
  1432. me.appendEvent.fire();
  1433. }
  1434. }
  1435. this.beforeRenderEvent.fire();
  1436. if (! moduleElement) {
  1437. moduleElement = this.element;
  1438. }
  1439. if (appendToNode) {
  1440. appendTo(appendToNode);
  1441. } else {
  1442. // No node was passed in. If the element is not already in the Dom, this fails
  1443. if (! Dom.inDocument(this.element)) {
  1444. YAHOO.log("Render failed. Must specify appendTo node if " + " Module isn't already in the DOM.", "error");
  1445. return false;
  1446. }
  1447. }
  1448. this._renderHeader(moduleElement);
  1449. this._renderBody(moduleElement);
  1450. this._renderFooter(moduleElement);
  1451. this._rendered = true;
  1452. this.renderEvent.fire();
  1453. return true;
  1454. },
  1455. /**
  1456. * Renders the currently set header into it's proper position under the
  1457. * module element. If the module element is not provided, "this.element"
  1458. * is used.
  1459. *
  1460. * @method _renderHeader
  1461. * @protected
  1462. * @param {HTMLElement} moduleElement Optional. A reference to the module element
  1463. */
  1464. _renderHeader: function(moduleElement){
  1465. moduleElement = moduleElement || this.element;
  1466. // Need to get everything into the DOM if it isn't already
  1467. if (this.header && !Dom.inDocument(this.header)) {
  1468. // There is a header, but it's not in the DOM yet. Need to add it.
  1469. var firstChild = moduleElement.firstChild;
  1470. if (firstChild) {
  1471. moduleElement.insertBefore(this.header, firstChild);
  1472. } else {
  1473. moduleElement.appendChild(this.header);
  1474. }
  1475. }
  1476. },
  1477. /**
  1478. * Renders the currently set body into it's proper position under the
  1479. * module element. If the module element is not provided, "this.element"
  1480. * is used.
  1481. *
  1482. * @method _renderBody
  1483. * @protected
  1484. * @param {HTMLElement} moduleElement Optional. A reference to the module element.
  1485. */
  1486. _renderBody: function(moduleElement){
  1487. moduleElement = moduleElement || this.element;
  1488. if (this.body && !Dom.inDocument(this.body)) {
  1489. // There is a body, but it's not in the DOM yet. Need to add it.
  1490. if (this.footer && Dom.isAncestor(moduleElement, this.footer)) {
  1491. moduleElement.insertBefore(this.body, this.footer);
  1492. } else {
  1493. moduleElement.appendChild(this.body);
  1494. }
  1495. }
  1496. },
  1497. /**
  1498. * Renders the currently set footer into it's proper position under the
  1499. * module element. If the module element is not provided, "this.element"
  1500. * is used.
  1501. *
  1502. * @method _renderFooter
  1503. * @protected
  1504. * @param {HTMLElement} moduleElement Optional. A reference to the module element
  1505. */
  1506. _renderFooter: function(moduleElement){
  1507. moduleElement = moduleElement || this.element;
  1508. if (this.footer && !Dom.inDocument(this.footer)) {
  1509. // There is a footer, but it's not in the DOM yet. Need to add it.
  1510. moduleElement.appendChild(this.footer);
  1511. }
  1512. },
  1513. /**
  1514. * Removes the Module element from the DOM and sets all child elements
  1515. * to null.
  1516. * @method destroy
  1517. */
  1518. destroy: function () {
  1519. var parent;
  1520. if (this.element) {
  1521. Event.purgeElement(this.element, true);
  1522. parent = this.element.parentNode;
  1523. }
  1524. if (parent) {
  1525. parent.removeChild(this.element);
  1526. }
  1527. this.element = null;
  1528. this.header = null;
  1529. this.body = null;
  1530. this.footer = null;
  1531. Module.textResizeEvent.unsubscribe(this.onDomResize, this);
  1532. this.cfg.destroy();
  1533. this.cfg = null;
  1534. this.destroyEvent.fire();
  1535. },
  1536. /**
  1537. * Shows the Module element by setting the visible configuration
  1538. * property to true. Also fires two events: beforeShowEvent prior to
  1539. * the visibility change, and showEvent after.
  1540. * @method show
  1541. */
  1542. show: function () {
  1543. this.cfg.setProperty("visible", true);
  1544. },
  1545. /**
  1546. * Hides the Module element by setting the visible configuration
  1547. * property to false. Also fires two events: beforeHideEvent prior to
  1548. * the visibility change, and hideEvent after.
  1549. * @method hide
  1550. */
  1551. hide: function () {
  1552. this.cfg.setProperty("visible", false);
  1553. },
  1554. // BUILT-IN EVENT HANDLERS FOR MODULE //
  1555. /**
  1556. * Default event handler for changing the visibility property of a
  1557. * Module. By default, this is achieved by switching the "display" style
  1558. * between "block" and "none".
  1559. * This method is responsible for firing showEvent and hideEvent.
  1560. * @param {String} type The CustomEvent type (usually the property name)
  1561. * @param {Object[]} args The CustomEvent arguments. For configuration
  1562. * handlers, args[0] will equal the newly applied value for the property.
  1563. * @param {Object} obj The scope object. For configuration handlers,
  1564. * this will usually equal the owner.
  1565. * @method configVisible
  1566. */
  1567. configVisible: function (type, args, obj) {
  1568. var visible = args[0];
  1569. if (visible) {
  1570. this.beforeShowEvent.fire();
  1571. Dom.setStyle(this.element, "display", "block");
  1572. this.showEvent.fire();
  1573. } else {
  1574. this.beforeHideEvent.fire();
  1575. Dom.setStyle(this.element, "display", "none");
  1576. this.hideEvent.fire();
  1577. }
  1578. },
  1579. /**
  1580. * Default event handler for the "monitorresize" configuration property
  1581. * @param {String} type The CustomEvent type (usually the property name)
  1582. * @param {Object[]} args The CustomEvent arguments. For configuration
  1583. * handlers, args[0] will equal the newly applied value for the property.
  1584. * @param {Object} obj The scope object. For configuration handlers,
  1585. * this will usually equal the owner.
  1586. * @method configMonitorResize
  1587. */
  1588. configMonitorResize: function (type, args, obj) {
  1589. var monitor = args[0];
  1590. if (monitor) {
  1591. this.initResizeMonitor();
  1592. } else {
  1593. Module.textResizeEvent.unsubscribe(this.onDomResize, this, true);
  1594. this.resizeMonitor = null;
  1595. }
  1596. },
  1597. /**
  1598. * This method is a protected helper, used when constructing the DOM structure for the module
  1599. * to account for situations which may cause Operation Aborted errors in IE. It should not
  1600. * be used for general DOM construction.
  1601. * <p>
  1602. * If the parentNode is not document.body, the element is appended as the last element.
  1603. * </p>
  1604. * <p>
  1605. * If the parentNode is document.body the element is added as the first child to help
  1606. * prevent Operation Aborted errors in IE.
  1607. * </p>
  1608. *
  1609. * @param {parentNode} The HTML element to which the element will be added
  1610. * @param {element} The HTML element to be added to parentNode's children
  1611. * @method _addToParent
  1612. * @protected
  1613. */
  1614. _addToParent: function(parentNode, element) {
  1615. if (!this.cfg.getProperty("appendtodocumentbody") && parentNode === document.body && parentNode.firstChild) {
  1616. parentNode.insertBefore(element, parentNode.firstChild);
  1617. } else {
  1618. parentNode.appendChild(element);
  1619. }
  1620. },
  1621. /**
  1622. * Returns a String representation of the Object.
  1623. * @method toString
  1624. * @return {String} The string representation of the Module
  1625. */
  1626. toString: function () {
  1627. return "Module " + this.id;
  1628. }
  1629. };
  1630. YAHOO.lang.augmentProto(Module, YAHOO.util.EventProvider);
  1631. }());
  1632. (function () {
  1633. /**
  1634. * Overlay is a Module that is absolutely positioned above the page flow. It
  1635. * has convenience methods for positioning and sizing, as well as options for
  1636. * controlling zIndex and constraining the Overlay's position to the current
  1637. * visible viewport. Overlay also contains a dynamicly generated IFRAME which
  1638. * is placed beneath it for Internet Explorer 6 and 5.x so that it will be
  1639. * properly rendered above SELECT elements.
  1640. * @namespace YAHOO.widget
  1641. * @class Overlay
  1642. * @extends YAHOO.widget.Module
  1643. * @param {String} el The element ID representing the Overlay <em>OR</em>
  1644. * @param {HTMLElement} el The element representing the Overlay
  1645. * @param {Object} userConfig The configuration object literal containing
  1646. * the configuration that should be set for this Overlay. See configuration
  1647. * documentation for more details.
  1648. * @constructor
  1649. */
  1650. YAHOO.widget.Overlay = function (el, userConfig) {
  1651. YAHOO.widget.Overlay.superclass.constructor.call(this, el, userConfig);
  1652. };
  1653. var Lang = YAHOO.lang,
  1654. CustomEvent = YAHOO.util.CustomEvent,
  1655. Module = YAHOO.widget.Module,
  1656. Event = YAHOO.util.Event,
  1657. Dom = YAHOO.util.Dom,
  1658. Config = YAHOO.util.Config,
  1659. UA = YAHOO.env.ua,
  1660. Overlay = YAHOO.widget.Overlay,
  1661. _SUBSCRIBE = "subscribe",
  1662. _UNSUBSCRIBE = "unsubscribe",
  1663. _CONTAINED = "contained",
  1664. m_oIFrameTemplate,
  1665. /**
  1666. * Constant representing the name of the Overlay's events
  1667. * @property EVENT_TYPES
  1668. * @private
  1669. * @final
  1670. * @type Object
  1671. */
  1672. EVENT_TYPES = {
  1673. "BEFORE_MOVE": "beforeMove",
  1674. "MOVE": "move"
  1675. },
  1676. /**
  1677. * Constant representing the Overlay's configuration properties
  1678. * @property DEFAULT_CONFIG
  1679. * @private
  1680. * @final
  1681. * @type Object
  1682. */
  1683. DEFAULT_CONFIG = {
  1684. "X": {
  1685. key: "x",
  1686. validator: Lang.isNumber,
  1687. suppressEvent: true,
  1688. supercedes: ["iframe"]
  1689. },
  1690. "Y": {
  1691. key: "y",
  1692. validator: Lang.isNumber,
  1693. suppressEvent: true,
  1694. supercedes: ["iframe"]
  1695. },
  1696. "XY": {
  1697. key: "xy",
  1698. suppressEvent: true,
  1699. supercedes: ["iframe"]
  1700. },
  1701. "CONTEXT": {
  1702. key: "context",
  1703. suppressEvent: true,
  1704. supercedes: ["iframe"]
  1705. },
  1706. "FIXED_CENTER": {
  1707. key: "fixedcenter",
  1708. value: false,
  1709. supercedes: ["iframe", "visible"]
  1710. },
  1711. "WIDTH": {
  1712. key: "width",
  1713. suppressEvent: true,
  1714. supercedes: ["context", "fixedcenter", "iframe"]
  1715. },
  1716. "HEIGHT": {
  1717. key: "height",
  1718. suppressEvent: true,
  1719. supercedes: ["context", "fixedcenter", "iframe"]
  1720. },
  1721. "AUTO_FILL_HEIGHT" : {
  1722. key: "autofillheight",
  1723. supercedes: ["height"],
  1724. value:"body"
  1725. },
  1726. "ZINDEX": {
  1727. key: "zindex",
  1728. value: null
  1729. },
  1730. "CONSTRAIN_TO_VIEWPORT": {
  1731. key: "constraintoviewport",
  1732. value: false,
  1733. validator: Lang.isBoolean,
  1734. supercedes: ["iframe", "x", "y", "xy"]
  1735. },
  1736. "IFRAME": {
  1737. key: "iframe",
  1738. value: (UA.ie == 6 ? true : false),
  1739. validator: Lang.isBoolean,
  1740. supercedes: ["zindex"]
  1741. },
  1742. "PREVENT_CONTEXT_OVERLAP": {
  1743. key: "preventcontextoverlap",
  1744. value: false,
  1745. validator: Lang.isBoolean,
  1746. supercedes: ["constraintoviewport"]
  1747. }
  1748. };
  1749. /**
  1750. * The URL that will be placed in the iframe
  1751. * @property YAHOO.widget.Overlay.IFRAME_SRC
  1752. * @static
  1753. * @final
  1754. * @type String
  1755. */
  1756. Overlay.IFRAME_SRC = "javascript:false;";
  1757. /**
  1758. * Number representing how much the iframe shim should be offset from each
  1759. * side of an Overlay instance, in pixels.
  1760. * @property YAHOO.widget.Overlay.IFRAME_SRC
  1761. * @default 3
  1762. * @static
  1763. * @final
  1764. * @type Number
  1765. */
  1766. Overlay.IFRAME_OFFSET = 3;
  1767. /**
  1768. * Number representing the minimum distance an Overlay instance should be
  1769. * positioned relative to the boundaries of the browser's viewport, in pixels.
  1770. * @property YAHOO.widget.Overlay.VIEWPORT_OFFSET
  1771. * @default 10
  1772. * @static
  1773. * @final
  1774. * @type Number
  1775. */
  1776. Overlay.VIEWPORT_OFFSET = 10;
  1777. /**
  1778. * Constant representing the top left corner of an element, used for
  1779. * configuring the context element alignment
  1780. * @property YAHOO.widget.Overlay.TOP_LEFT
  1781. * @static
  1782. * @final
  1783. * @type String
  1784. */
  1785. Overlay.TOP_LEFT = "tl";
  1786. /**
  1787. * Constant representing the top right corner of an element, used for
  1788. * configuring the context element alignment
  1789. * @property YAHOO.widget.Overlay.TOP_RIGHT
  1790. * @static
  1791. * @final
  1792. * @type String
  1793. */
  1794. Overlay.TOP_RIGHT = "tr";
  1795. /**
  1796. * Constant representing the top bottom left corner of an element, used for
  1797. * configuring the context element alignment
  1798. * @property YAHOO.widget.Overlay.BOTTOM_LEFT
  1799. * @static
  1800. * @final
  1801. * @type String
  1802. */
  1803. Overlay.BOTTOM_LEFT = "bl";
  1804. /**
  1805. * Constant representing the bottom right corner of an element, used for
  1806. * configuring the context element alignment
  1807. * @property YAHOO.widget.Overlay.BOTTOM_RIGHT
  1808. * @static
  1809. * @final
  1810. * @type String
  1811. */
  1812. Overlay.BOTTOM_RIGHT = "br";
  1813. Overlay.PREVENT_OVERLAP_X = {
  1814. "tltr": true,
  1815. "blbr": true,
  1816. "brbl": true,
  1817. "trtl": true
  1818. };
  1819. Overlay.PREVENT_OVERLAP_Y = {
  1820. "trbr": true,
  1821. "tlbl": true,
  1822. "bltl": true,
  1823. "brtr": true
  1824. };
  1825. /**
  1826. * Constant representing the default CSS class used for an Overlay
  1827. * @property YAHOO.widget.Overlay.CSS_OVERLAY
  1828. * @static
  1829. * @final
  1830. * @type String
  1831. */
  1832. Overlay.CSS_OVERLAY = "yui-overlay";
  1833. /**
  1834. * Constant representing the default hidden CSS class used for an Overlay. This class is
  1835. * applied to the overlay's outer DIV whenever it's hidden.
  1836. *
  1837. * @property YAHOO.widget.Overlay.CSS_HIDDEN
  1838. * @static
  1839. * @final
  1840. * @type String
  1841. */
  1842. Overlay.CSS_HIDDEN = "yui-overlay-hidden";
  1843. /**
  1844. * Constant representing the default CSS class used for an Overlay iframe shim.
  1845. *
  1846. * @property YAHOO.widget.Overlay.CSS_IFRAME
  1847. * @static
  1848. * @final
  1849. * @type String
  1850. */
  1851. Overlay.CSS_IFRAME = "yui-overlay-iframe";
  1852. /**
  1853. * Constant representing the names of the standard module elements
  1854. * used in the overlay.
  1855. * @property YAHOO.widget.Overlay.STD_MOD_RE
  1856. * @static
  1857. * @final
  1858. * @type RegExp
  1859. */
  1860. Overlay.STD_MOD_RE = /^\s*?(body|footer|header)\s*?$/i;
  1861. /**
  1862. * A singleton CustomEvent used for reacting to the DOM event for
  1863. * window scroll
  1864. * @event YAHOO.widget.Overlay.windowScrollEvent
  1865. */
  1866. Overlay.windowScrollEvent = new CustomEvent("windowScroll");
  1867. /**
  1868. * A singleton CustomEvent used for reacting to the DOM event for
  1869. * window resize
  1870. * @event YAHOO.widget.Overlay.windowResizeEvent
  1871. */
  1872. Overlay.windowResizeEvent = new CustomEvent("windowResize");
  1873. /**
  1874. * The DOM event handler used to fire the CustomEvent for window scroll
  1875. * @method YAHOO.widget.Overlay.windowScrollHandler
  1876. * @static
  1877. * @param {DOMEvent} e The DOM scroll event
  1878. */
  1879. Overlay.windowScrollHandler = function (e) {
  1880. var t = Event.getTarget(e);
  1881. // - Webkit (Safari 2/3) and Opera 9.2x bubble scroll events from elements to window
  1882. // - FF2/3 and IE6/7, Opera 9.5x don't bubble scroll events from elements to window
  1883. // - IE doesn't recognize scroll registered on the document.
  1884. //
  1885. // Also, when document view is scrolled, IE doesn't provide a target,
  1886. // rest of the browsers set target to window.document, apart from opera
  1887. // which sets target to window.
  1888. if (!t || t === window || t === window.document) {
  1889. if (UA.ie) {
  1890. if (! window.scrollEnd) {
  1891. window.scrollEnd = -1;
  1892. }
  1893. clearTimeout(window.scrollEnd);
  1894. window.scrollEnd = setTimeout(function () {
  1895. Overlay.windowScrollEvent.fire();
  1896. }, 1);
  1897. } else {
  1898. Overlay.windowScrollEvent.fire();
  1899. }
  1900. }
  1901. };
  1902. /**
  1903. * The DOM event handler used to fire the CustomEvent for window resize
  1904. * @method YAHOO.widget.Overlay.windowResizeHandler
  1905. * @static
  1906. * @param {DOMEvent} e The DOM resize event
  1907. */
  1908. Overlay.windowResizeHandler = function (e) {
  1909. if (UA.ie) {
  1910. if (! window.resizeEnd) {
  1911. window.resizeEnd = -1;
  1912. }
  1913. clearTimeout(window.resizeEnd);
  1914. window.resizeEnd = setTimeout(function () {
  1915. Overlay.windowResizeEvent.fire();
  1916. }, 100);
  1917. } else {
  1918. Overlay.windowResizeEvent.fire();
  1919. }
  1920. };
  1921. /**
  1922. * A boolean that indicated whether the window resize and scroll events have
  1923. * already been subscribed to.
  1924. * @property YAHOO.widget.Overlay._initialized
  1925. * @private
  1926. * @type Boolean
  1927. */
  1928. Overlay._initialized = null;
  1929. if (Overlay._initialized === null) {
  1930. Event.on(window, "scroll", Overlay.windowScrollHandler);
  1931. Event.on(window, "resize", Overlay.windowResizeHandler);
  1932. Overlay._initialized = true;
  1933. }
  1934. /**
  1935. * Internal map of special event types, which are provided
  1936. * by the instance. It maps the event type to the custom event
  1937. * instance. Contains entries for the "windowScroll", "windowResize" and
  1938. * "textResize" static container events.
  1939. *
  1940. * @property YAHOO.widget.Overlay._TRIGGER_MAP
  1941. * @type Object
  1942. * @static
  1943. * @private
  1944. */
  1945. Overlay._TRIGGER_MAP = {
  1946. "windowScroll" : Overlay.windowScrollEvent,
  1947. "windowResize" : Overlay.windowResizeEvent,
  1948. "textResize" : Module.textResizeEvent
  1949. };
  1950. YAHOO.extend(Overlay, Module, {
  1951. /**
  1952. * <p>
  1953. * Array of default event types which will trigger
  1954. * context alignment for the Overlay class.
  1955. * </p>
  1956. * <p>The array is empty by default for Overlay,
  1957. * but maybe populated in future releases, so classes extending
  1958. * Overlay which need to define their own set of CONTEXT_TRIGGERS
  1959. * should concatenate their super class's prototype.CONTEXT_TRIGGERS
  1960. * value with their own array of values.
  1961. * </p>
  1962. * <p>
  1963. * E.g.:
  1964. * <code>CustomOverlay.prototype.CONTEXT_TRIGGERS = YAHOO.widget.Overlay.prototype.CONTEXT_TRIGGERS.concat(["windowScroll"]);</code>
  1965. * </p>
  1966. *
  1967. * @property CONTEXT_TRIGGERS
  1968. * @type Array
  1969. * @final
  1970. */
  1971. CONTEXT_TRIGGERS : [],
  1972. /**
  1973. * The Overlay initialization method, which is executed for Overlay and
  1974. * all of its subclasses. This method is automatically called by the
  1975. * constructor, and sets up all DOM references for pre-existing markup,
  1976. * and creates required markup if it is not already present.
  1977. * @method init
  1978. * @param {String} el The element ID representing the Overlay <em>OR</em>
  1979. * @param {HTMLElement} el The element representing the Overlay
  1980. * @param {Object} userConfig The configuration object literal
  1981. * containing the configuration that should be set for this Overlay.
  1982. * See configuration documentation for more details.
  1983. */
  1984. init: function (el, userConfig) {
  1985. /*
  1986. Note that we don't pass the user config in here yet because we
  1987. only want it executed once, at the lowest subclass level
  1988. */
  1989. Overlay.superclass.init.call(this, el/*, userConfig*/);
  1990. this.beforeInitEvent.fire(Overlay);
  1991. Dom.addClass(this.element, Overlay.CSS_OVERLAY);
  1992. if (userConfig) {
  1993. this.cfg.applyConfig(userConfig, true);
  1994. }
  1995. if (this.platform == "mac" && UA.gecko) {
  1996. if (! Config.alreadySubscribed(this.showEvent,
  1997. this.showMacGeckoScrollbars, this)) {
  1998. this.showEvent.subscribe(this.showMacGeckoScrollbars,
  1999. this, true);
  2000. }
  2001. if (! Config.alreadySubscribed(this.hideEvent,
  2002. this.hideMacGeckoScrollbars, this)) {
  2003. this.hideEvent.subscribe(this.hideMacGeckoScrollbars,
  2004. this, true);
  2005. }
  2006. }
  2007. this.initEvent.fire(Overlay);
  2008. },
  2009. /**
  2010. * Initializes the custom events for Overlay which are fired
  2011. * automatically at appropriate times by the Overlay class.
  2012. * @method initEvents
  2013. */
  2014. initEvents: function () {
  2015. Overlay.superclass.initEvents.call(this);
  2016. var SIGNATURE = CustomEvent.LIST;
  2017. /**
  2018. * CustomEvent fired before the Overlay is moved.
  2019. * @event beforeMoveEvent
  2020. * @param {Number} x x coordinate
  2021. * @param {Number} y y coordinate
  2022. */
  2023. this.beforeMoveEvent = this.createEvent(EVENT_TYPES.BEFORE_MOVE);
  2024. this.beforeMoveEvent.signature = SIGNATURE;
  2025. /**
  2026. * CustomEvent fired after the Overlay is moved.
  2027. * @event moveEvent
  2028. * @param {Number} x x coordinate
  2029. * @param {Number} y y coordinate
  2030. */
  2031. this.moveEvent = this.createEvent(EVENT_TYPES.MOVE);
  2032. this.moveEvent.signature = SIGNATURE;
  2033. },
  2034. /**
  2035. * Initializes the class's configurable properties which can be changed
  2036. * using the Overlay's Config object (cfg).
  2037. * @method initDefaultConfig
  2038. */
  2039. initDefaultConfig: function () {
  2040. Overlay.superclass.initDefaultConfig.call(this);
  2041. var cfg = this.cfg;
  2042. // Add overlay config properties //
  2043. /**
  2044. * The absolute x-coordinate position of the Overlay
  2045. * @config x
  2046. * @type Number
  2047. * @default null
  2048. */
  2049. cfg.addProperty(DEFAULT_CONFIG.X.key, {
  2050. handler: this.configX,
  2051. validator: DEFAULT_CONFIG.X.validator,
  2052. suppressEvent: DEFAULT_CONFIG.X.suppressEvent,
  2053. supercedes: DEFAULT_CONFIG.X.supercedes
  2054. });
  2055. /**
  2056. * The absolute y-coordinate position of the Overlay
  2057. * @config y
  2058. * @type Number
  2059. * @default null
  2060. */
  2061. cfg.addProperty(DEFAULT_CONFIG.Y.key, {
  2062. handler: this.configY,
  2063. validator: DEFAULT_CONFIG.Y.validator,
  2064. suppressEvent: DEFAULT_CONFIG.Y.suppressEvent,
  2065. supercedes: DEFAULT_CONFIG.Y.supercedes
  2066. });
  2067. /**
  2068. * An array with the absolute x and y positions of the Overlay
  2069. * @config xy
  2070. * @type Number[]
  2071. * @default null
  2072. */
  2073. cfg.addProperty(DEFAULT_CONFIG.XY.key, {
  2074. handler: this.configXY,
  2075. suppressEvent: DEFAULT_CONFIG.XY.suppressEvent,
  2076. supercedes: DEFAULT_CONFIG.XY.supercedes
  2077. });
  2078. /**
  2079. * <p>
  2080. * The array of context arguments for context-sensitive positioning.
  2081. * </p>
  2082. *
  2083. * <p>
  2084. * The format of the array is: <code>[contextElementOrId, overlayCorner, contextCorner, arrayOfTriggerEvents (optional), xyOffset (optional)]</code>, the
  2085. * the 5 array elements described in detail below:
  2086. * </p>
  2087. *
  2088. * <dl>
  2089. * <dt>contextElementOrId &#60;String|HTMLElement&#62;</dt>
  2090. * <dd>A reference to the context element to which the overlay should be aligned (or it's id).</dd>
  2091. * <dt>overlayCorner &#60;String&#62;</dt>
  2092. * <dd>The corner of the overlay which is to be used for alignment. This corner will be aligned to the
  2093. * corner of the context element defined by the "contextCorner" entry which follows. Supported string values are:
  2094. * "tr" (top right), "tl" (top left), "br" (bottom right), or "bl" (bottom left).</dd>
  2095. * <dt>contextCorner &#60;String&#62;</dt>
  2096. * <dd>The corner of the context element which is to be used for alignment. Supported string values are the same ones listed for the "overlayCorner" entry above.</dd>
  2097. * <dt>arrayOfTriggerEvents (optional) &#60;Array[String|CustomEvent]&#62;</dt>
  2098. * <dd>
  2099. * <p>
  2100. * By default, context alignment is a one time operation, aligning the Overlay to the context element when context configuration property is set, or when the <a href="#method_align">align</a>
  2101. * method is invoked. However, you can use the optional "arrayOfTriggerEvents" entry to define the list of events which should force the overlay to re-align itself with the context element.
  2102. * This is useful in situations where the layout of the document may change, resulting in the context element's position being modified.
  2103. * </p>
  2104. * <p>
  2105. * The array can contain either event type strings for events the instance publishes (e.g. "beforeShow") or CustomEvent instances. Additionally the following
  2106. * 3 static container event types are also currently supported : <code>"windowResize", "windowScroll", "textResize"</code> (defined in <a href="#property__TRIGGER_MAP">_TRIGGER_MAP</a> private property).
  2107. * </p>
  2108. * </dd>
  2109. * <dt>xyOffset &#60;Number[]&#62;</dt>
  2110. * <dd>
  2111. * A 2 element Array specifying the X and Y pixel amounts by which the Overlay should be offset from the aligned corner. e.g. [5,0] offsets the Overlay 5 pixels to the left, <em>after</em> aligning the given context corners.
  2112. * NOTE: If using this property and no triggers need to be defined, the arrayOfTriggerEvents property should be set to null to maintain correct array positions for the arguments.
  2113. * </dd>
  2114. * </dl>
  2115. *
  2116. * <p>
  2117. * For example, setting this property to <code>["img1", "tl", "bl"]</code> will
  2118. * align the Overlay's top left corner to the bottom left corner of the
  2119. * context element with id "img1".
  2120. * </p>
  2121. * <p>
  2122. * Setting this property to <code>["img1", "tl", "bl", null, [0,5]</code> will
  2123. * align the Overlay's top left corner to the bottom left corner of the
  2124. * context element with id "img1", and then offset it by 5 pixels on the Y axis (providing a 5 pixel gap between the bottom of the context element and top of the overlay).
  2125. * </p>
  2126. * <p>
  2127. * Adding the optional trigger values: <code>["img1", "tl", "bl", ["beforeShow", "windowResize"], [0,5]]</code>,
  2128. * will re-align the overlay position, whenever the "beforeShow" or "windowResize" events are fired.
  2129. * </p>
  2130. *
  2131. * @config context
  2132. * @type Array
  2133. * @default null
  2134. */
  2135. cfg.addProperty(DEFAULT_CONFIG.CONTEXT.key, {
  2136. handler: this.configContext,
  2137. suppressEvent: DEFAULT_CONFIG.CONTEXT.suppressEvent,
  2138. supercedes: DEFAULT_CONFIG.CONTEXT.supercedes
  2139. });
  2140. /**
  2141. * Determines whether or not the Overlay should be anchored
  2142. * to the center of the viewport.
  2143. *
  2144. * <p>This property can be set to:</p>
  2145. *
  2146. * <dl>
  2147. * <dt>true</dt>
  2148. * <dd>
  2149. * To enable fixed center positioning
  2150. * <p>
  2151. * When enabled, the overlay will
  2152. * be positioned in the center of viewport when initially displayed, and
  2153. * will remain in the center of the viewport whenever the window is
  2154. * scrolled or resized.
  2155. * </p>
  2156. * <p>
  2157. * If the overlay is too big for the viewport,
  2158. * it's top left corner will be aligned with the top left corner of the viewport.
  2159. * </p>
  2160. * </dd>
  2161. * <dt>false</dt>
  2162. * <dd>
  2163. * To disable fixed center positioning.
  2164. * <p>In this case the overlay can still be
  2165. * centered as a one-off operation, by invoking the <code>center()</code> method,
  2166. * however it will not remain centered when the window is scrolled/resized.
  2167. * </dd>
  2168. * <dt>"contained"<dt>
  2169. * <dd>To enable fixed center positioning, as with the <code>true</code> option.
  2170. * <p>However, unlike setting the property to <code>true</code>,
  2171. * when the property is set to <code>"contained"</code>, if the overlay is
  2172. * too big for the viewport, it will not get automatically centered when the
  2173. * user scrolls or resizes the window (until the window is large enough to contain the
  2174. * overlay). This is useful in cases where the Overlay has both header and footer
  2175. * UI controls which the user may need to access.
  2176. * </p>
  2177. * </dd>
  2178. * </dl>
  2179. *
  2180. * @config fixedcenter
  2181. * @type Boolean | String
  2182. * @default false
  2183. */
  2184. cfg.addProperty(DEFAULT_CONFIG.FIXED_CENTER.key, {
  2185. handler: this.configFixedCenter,
  2186. value: DEFAULT_CONFIG.FIXED_CENTER.value,
  2187. validator: DEFAULT_CONFIG.FIXED_CENTER.validator,
  2188. supercedes: DEFAULT_CONFIG.FIXED_CENTER.supercedes
  2189. });
  2190. /**
  2191. * CSS width of the Overlay.
  2192. * @config width
  2193. * @type String
  2194. * @default null
  2195. */
  2196. cfg.addProperty(DEFAULT_CONFIG.WIDTH.key, {
  2197. handler: this.configWidth,
  2198. suppressEvent: DEFAULT_CONFIG.WIDTH.suppressEvent,
  2199. supercedes: DEFAULT_CONFIG.WIDTH.supercedes
  2200. });
  2201. /**
  2202. * CSS height of the Overlay.
  2203. * @config height
  2204. * @type String
  2205. * @default null
  2206. */
  2207. cfg.addProperty(DEFAULT_CONFIG.HEIGHT.key, {
  2208. handler: this.configHeight,
  2209. suppressEvent: DEFAULT_CONFIG.HEIGHT.suppressEvent,
  2210. supercedes: DEFAULT_CONFIG.HEIGHT.supercedes
  2211. });
  2212. /**
  2213. * Standard module element which should auto fill out the height of the Overlay if the height config property is set.
  2214. * Supported values are "header", "body", "footer".
  2215. *
  2216. * @config autofillheight
  2217. * @type String
  2218. * @default null
  2219. */
  2220. cfg.addProperty(DEFAULT_CONFIG.AUTO_FILL_HEIGHT.key, {
  2221. handler: this.configAutoFillHeight,
  2222. value : DEFAULT_CONFIG.AUTO_FILL_HEIGHT.value,
  2223. validator : this._validateAutoFill,
  2224. supercedes: DEFAULT_CONFIG.AUTO_FILL_HEIGHT.supercedes
  2225. });
  2226. /**
  2227. * CSS z-index of the Overlay.
  2228. * @config zIndex
  2229. * @type Number
  2230. * @default null
  2231. */
  2232. cfg.addProperty(DEFAULT_CONFIG.ZINDEX.key, {
  2233. handler: this.configzIndex,
  2234. value: DEFAULT_CONFIG.ZINDEX.value
  2235. });
  2236. /**
  2237. * True if the Overlay should be prevented from being positioned
  2238. * out of the viewport.
  2239. * @config constraintoviewport
  2240. * @type Boolean
  2241. * @default false
  2242. */
  2243. cfg.addProperty(DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.key, {
  2244. handler: this.configConstrainToViewport,
  2245. value: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.value,
  2246. validator: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.validator,
  2247. supercedes: DEFAULT_CONFIG.CONSTRAIN_TO_VIEWPORT.supercedes
  2248. });
  2249. /**
  2250. * @config iframe
  2251. * @description Boolean indicating whether or not the Overlay should
  2252. * have an IFRAME shim; used to prevent SELECT elements from
  2253. * poking through an Overlay instance in IE6. When set to "true",
  2254. * the iframe shim is created when the Overlay instance is intially
  2255. * made visible.
  2256. * @type Boolean
  2257. * @default true for IE6 and below, false for all other browsers.
  2258. */
  2259. cfg.addProperty(DEFAULT_CONFIG.IFRAME.key, {
  2260. handler: this.configIframe,
  2261. value: DEFAULT_CONFIG.IFRAME.value,
  2262. validator: DEFAULT_CONFIG.IFRAME.validator,
  2263. supercedes: DEFAULT_CONFIG.IFRAME.supercedes
  2264. });
  2265. /**
  2266. * @config preventcontextoverlap
  2267. * @description Boolean indicating whether or not the Overlay should overlap its
  2268. * context element (defined using the "context" configuration property) when the
  2269. * "constraintoviewport" configuration property is set to "true".
  2270. * @type Boolean
  2271. * @default false
  2272. */
  2273. cfg.addProperty(DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.key, {
  2274. value: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.value,
  2275. validator: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.validator,
  2276. supercedes: DEFAULT_CONFIG.PREVENT_CONTEXT_OVERLAP.supercedes
  2277. });
  2278. },
  2279. /**
  2280. * Moves the Overlay to the specified position. This function is
  2281. * identical to calling this.cfg.setProperty("xy", [x,y]);
  2282. * @method moveTo
  2283. * @param {Number} x The Overlay's new x position
  2284. * @param {Number} y The Overlay's new y position
  2285. */
  2286. moveTo: function (x, y) {
  2287. this.cfg.setProperty("xy", [x, y]);
  2288. },
  2289. /**
  2290. * Adds a CSS class ("hide-scrollbars") and removes a CSS class
  2291. * ("show-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
  2292. * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
  2293. * @method hideMacGeckoScrollbars
  2294. */
  2295. hideMacGeckoScrollbars: function () {
  2296. Dom.replaceClass(this.element, "show-scrollbars", "hide-scrollbars");
  2297. },
  2298. /**
  2299. * Adds a CSS class ("show-scrollbars") and removes a CSS class
  2300. * ("hide-scrollbars") to the Overlay to fix a bug in Gecko on Mac OS X
  2301. * (https://bugzilla.mozilla.org/show_bug.cgi?id=187435)
  2302. * @method showMacGeckoScrollbars
  2303. */
  2304. showMacGeckoScrollbars: function () {
  2305. Dom.replaceClass(this.element, "hide-scrollbars", "show-scrollbars");
  2306. },
  2307. /**
  2308. * Internal implementation to set the visibility of the overlay in the DOM.
  2309. *
  2310. * @method _setDomVisibility
  2311. * @param {boolean} visible Whether to show or hide the Overlay's outer element
  2312. * @protected
  2313. */
  2314. _setDomVisibility : function(show) {
  2315. Dom.setStyle(this.element, "visibility", (show) ? "visible" : "hidden");
  2316. var hiddenClass = Overlay.CSS_HIDDEN;
  2317. if (show) {
  2318. Dom.removeClass(this.element, hiddenClass);
  2319. } else {
  2320. Dom.addClass(this.element, hiddenClass);
  2321. }
  2322. },
  2323. // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
  2324. /**
  2325. * The default event handler fired when the "visible" property is
  2326. * changed. This method is responsible for firing showEvent
  2327. * and hideEvent.
  2328. * @method configVisible
  2329. * @param {String} type The CustomEvent type (usually the property name)
  2330. * @param {Object[]} args The CustomEvent arguments. For configuration
  2331. * handlers, args[0] will equal the newly applied value for the property.
  2332. * @param {Object} obj The scope object. For configuration handlers,
  2333. * this will usually equal the owner.
  2334. */
  2335. configVisible: function (type, args, obj) {
  2336. var visible = args[0],
  2337. currentVis = Dom.getStyle(this.element, "visibility"),
  2338. effect = this.cfg.getProperty("effect"),
  2339. effectInstances = [],
  2340. isMacGecko = (this.platform == "mac" && UA.gecko),
  2341. alreadySubscribed = Config.alreadySubscribed,
  2342. eff, ei, e, i, j, k, h,
  2343. nEffects,
  2344. nEffectInstances;
  2345. if (currentVis == "inherit") {
  2346. e = this.element.parentNode;
  2347. while (e.nodeType != 9 && e.nodeType != 11) {
  2348. currentVis = Dom.getStyle(e, "visibility");
  2349. if (currentVis != "inherit") {
  2350. break;
  2351. }
  2352. e = e.parentNode;
  2353. }
  2354. if (currentVis == "inherit") {
  2355. currentVis = "visible";
  2356. }
  2357. }
  2358. if (effect) {
  2359. if (effect instanceof Array) {
  2360. nEffects = effect.length;
  2361. for (i = 0; i < nEffects; i++) {
  2362. eff = effect[i];
  2363. effectInstances[effectInstances.length] =
  2364. eff.effect(this, eff.duration);
  2365. }
  2366. } else {
  2367. effectInstances[effectInstances.length] =
  2368. effect.effect(this, effect.duration);
  2369. }
  2370. }
  2371. if (visible) { // Show
  2372. if (isMacGecko) {
  2373. this.showMacGeckoScrollbars();
  2374. }
  2375. if (effect) { // Animate in
  2376. if (visible) { // Animate in if not showing
  2377. if (currentVis != "visible" || currentVis === "") {
  2378. this.beforeShowEvent.fire();
  2379. nEffectInstances = effectInstances.length;
  2380. for (j = 0; j < nEffectInstances; j++) {
  2381. ei = effectInstances[j];
  2382. if (j === 0 && !alreadySubscribed(
  2383. ei.animateInCompleteEvent,
  2384. this.showEvent.fire, this.showEvent)) {
  2385. /*
  2386. Delegate showEvent until end
  2387. of animateInComplete
  2388. */
  2389. ei.animateInCompleteEvent.subscribe(
  2390. this.showEvent.fire, this.showEvent, true);
  2391. }
  2392. ei.animateIn();
  2393. }
  2394. }
  2395. }
  2396. } else { // Show
  2397. if (currentVis != "visible" || currentVis === "") {
  2398. this.beforeShowEvent.fire();
  2399. this._setDomVisibility(true);
  2400. this.cfg.refireEvent("iframe");
  2401. this.showEvent.fire();
  2402. } else {
  2403. this._setDomVisibility(true);
  2404. }
  2405. }
  2406. } else { // Hide
  2407. if (isMacGecko) {
  2408. this.hideMacGeckoScrollbars();
  2409. }
  2410. if (effect) { // Animate out if showing
  2411. if (currentVis == "visible") {
  2412. this.beforeHideEvent.fire();
  2413. nEffectInstances = effectInstances.length;
  2414. for (k = 0; k < nEffectInstances; k++) {
  2415. h = effectInstances[k];
  2416. if (k === 0 && !alreadySubscribed(
  2417. h.animateOutCompleteEvent, this.hideEvent.fire,
  2418. this.hideEvent)) {
  2419. /*
  2420. Delegate hideEvent until end
  2421. of animateOutComplete
  2422. */
  2423. h.animateOutCompleteEvent.subscribe(
  2424. this.hideEvent.fire, this.hideEvent, true);
  2425. }
  2426. h.animateOut();
  2427. }
  2428. } else if (currentVis === "") {
  2429. this._setDomVisibility(false);
  2430. }
  2431. } else { // Simple hide
  2432. if (currentVis == "visible" || currentVis === "") {
  2433. this.beforeHideEvent.fire();
  2434. this._setDomVisibility(false);
  2435. this.hideEvent.fire();
  2436. } else {
  2437. this._setDomVisibility(false);
  2438. }
  2439. }
  2440. }
  2441. },
  2442. /**
  2443. * Fixed center event handler used for centering on scroll/resize, but only if
  2444. * the overlay is visible and, if "fixedcenter" is set to "contained", only if
  2445. * the overlay fits within the viewport.
  2446. *
  2447. * @method doCenterOnDOMEvent
  2448. */
  2449. doCenterOnDOMEvent: function () {
  2450. var cfg = this.cfg,
  2451. fc = cfg.getProperty("fixedcenter");
  2452. if (cfg.getProperty("visible")) {
  2453. if (fc && (fc !== _CONTAINED || this.fitsInViewport())) {
  2454. this.center();
  2455. }
  2456. }
  2457. },
  2458. /**
  2459. * Determines if the Overlay (including the offset value defined by Overlay.VIEWPORT_OFFSET)
  2460. * will fit entirely inside the viewport, in both dimensions - width and height.
  2461. *
  2462. * @method fitsInViewport
  2463. * @return boolean true if the Overlay will fit, false if not
  2464. */
  2465. fitsInViewport : function() {
  2466. var nViewportOffset = Overlay.VIEWPORT_OFFSET,
  2467. element = this.element,
  2468. elementWidth = element.offsetWidth,
  2469. elementHeight = element.offsetHeight,
  2470. viewportWidth = Dom.getViewportWidth(),
  2471. viewportHeight = Dom.getViewportHeight();
  2472. return ((elementWidth + nViewportOffset < viewportWidth) && (elementHeight + nViewportOffset < viewportHeight));
  2473. },
  2474. /**
  2475. * The default event handler fired when the "fixedcenter" property
  2476. * is changed.
  2477. * @method configFixedCenter
  2478. * @param {String} type The CustomEvent type (usually the property name)
  2479. * @param {Object[]} args The CustomEvent arguments. For configuration
  2480. * handlers, args[0] will equal the newly applied value for the property.
  2481. * @param {Object} obj The scope object. For configuration handlers,
  2482. * this will usually equal the owner.
  2483. */
  2484. configFixedCenter: function (type, args, obj) {
  2485. var val = args[0],
  2486. alreadySubscribed = Config.alreadySubscribed,
  2487. windowResizeEvent = Overlay.windowResizeEvent,
  2488. windowScrollEvent = Overlay.windowScrollEvent;
  2489. if (val) {
  2490. this.center();
  2491. if (!alreadySubscribed(this.beforeShowEvent, this.center)) {
  2492. this.beforeShowEvent.subscribe(this.center);
  2493. }
  2494. if (!alreadySubscribed(windowResizeEvent, this.doCenterOnDOMEvent, this)) {
  2495. windowResizeEvent.subscribe(this.doCenterOnDOMEvent, this, true);
  2496. }
  2497. if (!alreadySubscribed(windowScrollEvent, this.doCenterOnDOMEvent, this)) {
  2498. windowScrollEvent.subscribe(this.doCenterOnDOMEvent, this, true);
  2499. }
  2500. } else {
  2501. this.beforeShowEvent.unsubscribe(this.center);
  2502. windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent, this);
  2503. windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent, this);
  2504. }
  2505. },
  2506. /**
  2507. * The default event handler fired when the "height" property is changed.
  2508. * @method configHeight
  2509. * @param {String} type The CustomEvent type (usually the property name)
  2510. * @param {Object[]} args The CustomEvent arguments. For configuration
  2511. * handlers, args[0] will equal the newly applied value for the property.
  2512. * @param {Object} obj The scope object. For configuration handlers,
  2513. * this will usually equal the owner.
  2514. */
  2515. configHeight: function (type, args, obj) {
  2516. var height = args[0],
  2517. el = this.element;
  2518. Dom.setStyle(el, "height", height);
  2519. this.cfg.refireEvent("iframe");
  2520. },
  2521. /**
  2522. * The default event handler fired when the "autofillheight" property is changed.
  2523. * @method configAutoFillHeight
  2524. *
  2525. * @param {String} type The CustomEvent type (usually the property name)
  2526. * @param {Object[]} args The CustomEvent arguments. For configuration
  2527. * handlers, args[0] will equal the newly applied value for the property.
  2528. * @param {Object} obj The scope object. For configuration handlers,
  2529. * this will usually equal the owner.
  2530. */
  2531. configAutoFillHeight: function (type, args, obj) {
  2532. var fillEl = args[0],
  2533. cfg = this.cfg,
  2534. autoFillHeight = "autofillheight",
  2535. height = "height",
  2536. currEl = cfg.getProperty(autoFillHeight),
  2537. autoFill = this._autoFillOnHeightChange;
  2538. cfg.unsubscribeFromConfigEvent(height, autoFill);
  2539. Module.textResizeEvent.unsubscribe(autoFill);
  2540. this.changeContentEvent.unsubscribe(autoFill);
  2541. if (currEl && fillEl !== currEl && this[currEl]) {
  2542. Dom.setStyle(this[currEl], height, "");
  2543. }
  2544. if (fillEl) {
  2545. fillEl = Lang.trim(fillEl.toLowerCase());
  2546. cfg.subscribeToConfigEvent(height, autoFill, this[fillEl], this);
  2547. Module.textResizeEvent.subscribe(autoFill, this[fillEl], this);
  2548. this.changeContentEvent.subscribe(autoFill, this[fillEl], this);
  2549. cfg.setProperty(autoFillHeight, fillEl, true);
  2550. }
  2551. },
  2552. /**
  2553. * The default event handler fired when the "width" property is changed.
  2554. * @method configWidth
  2555. * @param {String} type The CustomEvent type (usually the property name)
  2556. * @param {Object[]} args The CustomEvent arguments. For configuration
  2557. * handlers, args[0] will equal the newly applied value for the property.
  2558. * @param {Object} obj The scope object. For configuration handlers,
  2559. * this will usually equal the owner.
  2560. */
  2561. configWidth: function (type, args, obj) {
  2562. var width = args[0],
  2563. el = this.element;
  2564. Dom.setStyle(el, "width", width);
  2565. this.cfg.refireEvent("iframe");
  2566. },
  2567. /**
  2568. * The default event handler fired when the "zIndex" property is changed.
  2569. * @method configzIndex
  2570. * @param {String} type The CustomEvent type (usually the property name)
  2571. * @param {Object[]} args The CustomEvent arguments. For configuration
  2572. * handlers, args[0] will equal the newly applied value for the property.
  2573. * @param {Object} obj The scope object. For configuration handlers,
  2574. * this will usually equal the owner.
  2575. */
  2576. configzIndex: function (type, args, obj) {
  2577. var zIndex = args[0],
  2578. el = this.element;
  2579. if (! zIndex) {
  2580. zIndex = Dom.getStyle(el, "zIndex");
  2581. if (! zIndex || isNaN(zIndex)) {
  2582. zIndex = 0;
  2583. }
  2584. }
  2585. if (this.iframe || this.cfg.getProperty("iframe") === true) {
  2586. if (zIndex <= 0) {
  2587. zIndex = 1;
  2588. }
  2589. }
  2590. Dom.setStyle(el, "zIndex", zIndex);
  2591. this.cfg.setProperty("zIndex", zIndex, true);
  2592. if (this.iframe) {
  2593. this.stackIframe();
  2594. }
  2595. },
  2596. /**
  2597. * The default event handler fired when the "xy" property is changed.
  2598. * @method configXY
  2599. * @param {String} type The CustomEvent type (usually the property name)
  2600. * @param {Object[]} args The CustomEvent arguments. For configuration
  2601. * handlers, args[0] will equal the newly applied value for the property.
  2602. * @param {Object} obj The scope object. For configuration handlers,
  2603. * this will usually equal the owner.
  2604. */
  2605. configXY: function (type, args, obj) {
  2606. var pos = args[0],
  2607. x = pos[0],
  2608. y = pos[1];
  2609. this.cfg.setProperty("x", x);
  2610. this.cfg.setProperty("y", y);
  2611. this.beforeMoveEvent.fire([x, y]);
  2612. x = this.cfg.getProperty("x");
  2613. y = this.cfg.getProperty("y");
  2614. YAHOO.log(("xy: " + [x, y]), "iframe");
  2615. this.cfg.refireEvent("iframe");
  2616. this.moveEvent.fire([x, y]);
  2617. },
  2618. /**
  2619. * The default event handler fired when the "x" property is changed.
  2620. * @method configX
  2621. * @param {String} type The CustomEvent type (usually the property name)
  2622. * @param {Object[]} args The CustomEvent arguments. For configuration
  2623. * handlers, args[0] will equal the newly applied value for the property.
  2624. * @param {Object} obj The scope object. For configuration handlers,
  2625. * this will usually equal the owner.
  2626. */
  2627. configX: function (type, args, obj) {
  2628. var x = args[0],
  2629. y = this.cfg.getProperty("y");
  2630. this.cfg.setProperty("x", x, true);
  2631. this.cfg.setProperty("y", y, true);
  2632. this.beforeMoveEvent.fire([x, y]);
  2633. x = this.cfg.getProperty("x");
  2634. y = this.cfg.getProperty("y");
  2635. Dom.setX(this.element, x, true);
  2636. this.cfg.setProperty("xy", [x, y], true);
  2637. this.cfg.refireEvent("iframe");
  2638. this.moveEvent.fire([x, y]);
  2639. },
  2640. /**
  2641. * The default event handler fired when the "y" property is changed.
  2642. * @method configY
  2643. * @param {String} type The CustomEvent type (usually the property name)
  2644. * @param {Object[]} args The CustomEvent arguments. For configuration
  2645. * handlers, args[0] will equal the newly applied value for the property.
  2646. * @param {Object} obj The scope object. For configuration handlers,
  2647. * this will usually equal the owner.
  2648. */
  2649. configY: function (type, args, obj) {
  2650. var x = this.cfg.getProperty("x"),
  2651. y = args[0];
  2652. this.cfg.setProperty("x", x, true);
  2653. this.cfg.setProperty("y", y, true);
  2654. this.beforeMoveEvent.fire([x, y]);
  2655. x = this.cfg.getProperty("x");
  2656. y = this.cfg.getProperty("y");
  2657. Dom.setY(this.element, y, true);
  2658. this.cfg.setProperty("xy", [x, y], true);
  2659. this.cfg.refireEvent("iframe");
  2660. this.moveEvent.fire([x, y]);
  2661. },
  2662. /**
  2663. * Shows the iframe shim, if it has been enabled.
  2664. * @method showIframe
  2665. */
  2666. showIframe: function () {
  2667. var oIFrame = this.iframe,
  2668. oParentNode;
  2669. if (oIFrame) {
  2670. oParentNode = this.element.parentNode;
  2671. if (oParentNode != oIFrame.parentNode) {
  2672. this._addToParent(oParentNode, oIFrame);
  2673. }
  2674. oIFrame.style.display = "block";
  2675. }
  2676. },
  2677. /**
  2678. * Hides the iframe shim, if it has been enabled.
  2679. * @method hideIframe
  2680. */
  2681. hideIframe: function () {
  2682. if (this.iframe) {
  2683. this.iframe.style.display = "none";
  2684. }
  2685. },
  2686. /**
  2687. * Syncronizes the size and position of iframe shim to that of its
  2688. * corresponding Overlay instance.
  2689. * @method syncIframe
  2690. */
  2691. syncIframe: function () {
  2692. var oIFrame = this.iframe,
  2693. oElement = this.element,
  2694. nOffset = Overlay.IFRAME_OFFSET,
  2695. nDimensionOffset = (nOffset * 2),
  2696. aXY;
  2697. if (oIFrame) {
  2698. // Size <iframe>
  2699. oIFrame.style.width = (oElement.offsetWidth + nDimensionOffset + "px");
  2700. oIFrame.style.height = (oElement.offsetHeight + nDimensionOffset + "px");
  2701. // Position <iframe>
  2702. aXY = this.cfg.getProperty("xy");
  2703. if (!Lang.isArray(aXY) || (isNaN(aXY[0]) || isNaN(aXY[1]))) {
  2704. this.syncPosition();
  2705. aXY = this.cfg.getProperty("xy");
  2706. }
  2707. Dom.setXY(oIFrame, [(aXY[0] - nOffset), (aXY[1] - nOffset)]);
  2708. }
  2709. },
  2710. /**
  2711. * Sets the zindex of the iframe shim, if it exists, based on the zindex of
  2712. * the Overlay element. The zindex of the iframe is set to be one less
  2713. * than the Overlay element's zindex.
  2714. *
  2715. * <p>NOTE: This method will not bump up the zindex of the Overlay element
  2716. * to ensure that the iframe shim has a non-negative zindex.
  2717. * If you require the iframe zindex to be 0 or higher, the zindex of
  2718. * the Overlay element should be set to a value greater than 0, before
  2719. * this method is called.
  2720. * </p>
  2721. * @method stackIframe
  2722. */
  2723. stackIframe: function () {
  2724. if (this.iframe) {
  2725. var overlayZ = Dom.getStyle(this.element, "zIndex");
  2726. if (!YAHOO.lang.isUndefined(overlayZ) && !isNaN(overlayZ)) {
  2727. Dom.setStyle(this.iframe, "zIndex", (overlayZ - 1));
  2728. }
  2729. }
  2730. },
  2731. /**
  2732. * The default event handler fired when the "iframe" property is changed.
  2733. * @method configIframe
  2734. * @param {String} type The CustomEvent type (usually the property name)
  2735. * @param {Object[]} args The CustomEvent arguments. For configuration
  2736. * handlers, args[0] will equal the newly applied value for the property.
  2737. * @param {Object} obj The scope object. For configuration handlers,
  2738. * this will usually equal the owner.
  2739. */
  2740. configIframe: function (type, args, obj) {
  2741. var bIFrame = args[0];
  2742. function createIFrame() {
  2743. var oIFrame = this.iframe,
  2744. oElement = this.element,
  2745. oParent;
  2746. if (!oIFrame) {
  2747. if (!m_oIFrameTemplate) {
  2748. m_oIFrameTemplate = document.createElement("iframe");
  2749. if (this.isSecure) {
  2750. m_oIFrameTemplate.src = Overlay.IFRAME_SRC;
  2751. }
  2752. /*
  2753. Set the opacity of the <iframe> to 0 so that it
  2754. doesn't modify the opacity of any transparent
  2755. elements that may be on top of it (like a shadow).
  2756. */
  2757. if (UA.ie) {
  2758. m_oIFrameTemplate.style.filter = "alpha(opacity=0)";
  2759. /*
  2760. Need to set the "frameBorder" property to 0
  2761. supress the default <iframe> border in IE.
  2762. Setting the CSS "border" property alone
  2763. doesn't supress it.
  2764. */
  2765. m_oIFrameTemplate.frameBorder = 0;
  2766. }
  2767. else {
  2768. m_oIFrameTemplate.style.opacity = "0";
  2769. }
  2770. m_oIFrameTemplate.style.position = "absolute";
  2771. m_oIFrameTemplate.style.border = "none";
  2772. m_oIFrameTemplate.style.margin = "0";
  2773. m_oIFrameTemplate.style.padding = "0";
  2774. m_oIFrameTemplate.style.display = "none";
  2775. m_oIFrameTemplate.tabIndex = -1;
  2776. m_oIFrameTemplate.className = Overlay.CSS_IFRAME;
  2777. }
  2778. oIFrame = m_oIFrameTemplate.cloneNode(false);
  2779. oIFrame.id = this.id + "_f";
  2780. oParent = oElement.parentNode;
  2781. var parentNode = oParent || document.body;
  2782. this._addToParent(parentNode, oIFrame);
  2783. this.iframe = oIFrame;
  2784. }
  2785. /*
  2786. Show the <iframe> before positioning it since the "setXY"
  2787. method of DOM requires the element be in the document
  2788. and visible.
  2789. */
  2790. this.showIframe();
  2791. /*
  2792. Syncronize the size and position of the <iframe> to that
  2793. of the Overlay.
  2794. */
  2795. this.syncIframe();
  2796. this.stackIframe();
  2797. // Add event listeners to update the <iframe> when necessary
  2798. if (!this._hasIframeEventListeners) {
  2799. this.showEvent.subscribe(this.showIframe);
  2800. this.hideEvent.subscribe(this.hideIframe);
  2801. this.changeContentEvent.subscribe(this.syncIframe);
  2802. this._hasIframeEventListeners = true;
  2803. }
  2804. }
  2805. function onBeforeShow() {
  2806. createIFrame.call(this);
  2807. this.beforeShowEvent.unsubscribe(onBeforeShow);
  2808. this._iframeDeferred = false;
  2809. }
  2810. if (bIFrame) { // <iframe> shim is enabled
  2811. if (this.cfg.getProperty("visible")) {
  2812. createIFrame.call(this);
  2813. } else {
  2814. if (!this._iframeDeferred) {
  2815. this.beforeShowEvent.subscribe(onBeforeShow);
  2816. this._iframeDeferred = true;
  2817. }
  2818. }
  2819. } else { // <iframe> shim is disabled
  2820. this.hideIframe();
  2821. if (this._hasIframeEventListeners) {
  2822. this.showEvent.unsubscribe(this.showIframe);
  2823. this.hideEvent.unsubscribe(this.hideIframe);
  2824. this.changeContentEvent.unsubscribe(this.syncIframe);
  2825. this._hasIframeEventListeners = false;
  2826. }
  2827. }
  2828. },
  2829. /**
  2830. * Set's the container's XY value from DOM if not already set.
  2831. *
  2832. * Differs from syncPosition, in that the XY value is only sync'd with DOM if
  2833. * not already set. The method also refire's the XY config property event, so any
  2834. * beforeMove, Move event listeners are invoked.
  2835. *
  2836. * @method _primeXYFromDOM
  2837. * @protected
  2838. */
  2839. _primeXYFromDOM : function() {
  2840. if (YAHOO.lang.isUndefined(this.cfg.getProperty("xy"))) {
  2841. // Set CFG XY based on DOM XY
  2842. this.syncPosition();
  2843. // Account for XY being set silently in syncPosition (no moveTo fired/called)
  2844. this.cfg.refireEvent("xy");
  2845. this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
  2846. }
  2847. },
  2848. /**
  2849. * The default event handler fired when the "constraintoviewport"
  2850. * property is changed.
  2851. * @method configConstrainToViewport
  2852. * @param {String} type The CustomEvent type (usually the property name)
  2853. * @param {Object[]} args The CustomEvent arguments. For configuration
  2854. * handlers, args[0] will equal the newly applied value for
  2855. * the property.
  2856. * @param {Object} obj The scope object. For configuration handlers,
  2857. * this will usually equal the owner.
  2858. */
  2859. configConstrainToViewport: function (type, args, obj) {
  2860. var val = args[0];
  2861. if (val) {
  2862. if (! Config.alreadySubscribed(this.beforeMoveEvent, this.enforceConstraints, this)) {
  2863. this.beforeMoveEvent.subscribe(this.enforceConstraints, this, true);
  2864. }
  2865. if (! Config.alreadySubscribed(this.beforeShowEvent, this._primeXYFromDOM)) {
  2866. this.beforeShowEvent.subscribe(this._primeXYFromDOM);
  2867. }
  2868. } else {
  2869. this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);
  2870. this.beforeMoveEvent.unsubscribe(this.enforceConstraints, this);
  2871. }
  2872. },
  2873. /**
  2874. * The default event handler fired when the "context" property
  2875. * is changed.
  2876. *
  2877. * @method configContext
  2878. * @param {String} type The CustomEvent type (usually the property name)
  2879. * @param {Object[]} args The CustomEvent arguments. For configuration
  2880. * handlers, args[0] will equal the newly applied value for the property.
  2881. * @param {Object} obj The scope object. For configuration handlers,
  2882. * this will usually equal the owner.
  2883. */
  2884. configContext: function (type, args, obj) {
  2885. var contextArgs = args[0],
  2886. contextEl,
  2887. elementMagnetCorner,
  2888. contextMagnetCorner,
  2889. triggers,
  2890. offset,
  2891. defTriggers = this.CONTEXT_TRIGGERS;
  2892. if (contextArgs) {
  2893. contextEl = contextArgs[0];
  2894. elementMagnetCorner = contextArgs[1];
  2895. contextMagnetCorner = contextArgs[2];
  2896. triggers = contextArgs[3];
  2897. offset = contextArgs[4];
  2898. if (defTriggers && defTriggers.length > 0) {
  2899. triggers = (triggers || []).concat(defTriggers);
  2900. }
  2901. if (contextEl) {
  2902. if (typeof contextEl == "string") {
  2903. this.cfg.setProperty("context", [
  2904. document.getElementById(contextEl),
  2905. elementMagnetCorner,
  2906. contextMagnetCorner,
  2907. triggers,
  2908. offset],
  2909. true);
  2910. }
  2911. if (elementMagnetCorner && contextMagnetCorner) {
  2912. this.align(elementMagnetCorner, contextMagnetCorner, offset);
  2913. }
  2914. if (this._contextTriggers) {
  2915. // Unsubscribe Old Set
  2916. this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
  2917. }
  2918. if (triggers) {
  2919. // Subscribe New Set
  2920. this._processTriggers(triggers, _SUBSCRIBE, this._alignOnTrigger);
  2921. this._contextTriggers = triggers;
  2922. }
  2923. }
  2924. }
  2925. },
  2926. /**
  2927. * Custom Event handler for context alignment triggers. Invokes the align method
  2928. *
  2929. * @method _alignOnTrigger
  2930. * @protected
  2931. *
  2932. * @param {String} type The event type (not used by the default implementation)
  2933. * @param {Any[]} args The array of arguments for the trigger event (not used by the default implementation)
  2934. */
  2935. _alignOnTrigger: function(type, args) {
  2936. this.align();
  2937. },
  2938. /**
  2939. * Helper method to locate the custom event instance for the event name string
  2940. * passed in. As a convenience measure, any custom events passed in are returned.
  2941. *
  2942. * @method _findTriggerCE
  2943. * @private
  2944. *
  2945. * @param {String|CustomEvent} t Either a CustomEvent, or event type (e.g. "windowScroll") for which a
  2946. * custom event instance needs to be looked up from the Overlay._TRIGGER_MAP.
  2947. */
  2948. _findTriggerCE : function(t) {
  2949. var tce = null;
  2950. if (t instanceof CustomEvent) {
  2951. tce = t;
  2952. } else if (Overlay._TRIGGER_MAP[t]) {
  2953. tce = Overlay._TRIGGER_MAP[t];
  2954. }
  2955. return tce;
  2956. },
  2957. /**
  2958. * Utility method that subscribes or unsubscribes the given
  2959. * function from the list of trigger events provided.
  2960. *
  2961. * @method _processTriggers
  2962. * @protected
  2963. *
  2964. * @param {Array[String|CustomEvent]} triggers An array of either CustomEvents, event type strings
  2965. * (e.g. "beforeShow", "windowScroll") to/from which the provided function should be
  2966. * subscribed/unsubscribed respectively.
  2967. *
  2968. * @param {String} mode Either "subscribe" or "unsubscribe", specifying whether or not
  2969. * we are subscribing or unsubscribing trigger listeners
  2970. *
  2971. * @param {Function} fn The function to be subscribed/unsubscribed to/from the trigger event.
  2972. * Context is always set to the overlay instance, and no additional object argument
  2973. * get passed to the subscribed function.
  2974. */
  2975. _processTriggers : function(triggers, mode, fn) {
  2976. var t, tce;
  2977. for (var i = 0, l = triggers.length; i < l; ++i) {
  2978. t = triggers[i];
  2979. tce = this._findTriggerCE(t);
  2980. if (tce) {
  2981. tce[mode](fn, this, true);
  2982. } else {
  2983. this[mode](t, fn);
  2984. }
  2985. }
  2986. },
  2987. // END BUILT-IN PROPERTY EVENT HANDLERS //
  2988. /**
  2989. * Aligns the Overlay to its context element using the specified corner
  2990. * points (represented by the constants TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT,
  2991. * and BOTTOM_RIGHT.
  2992. * @method align
  2993. * @param {String} elementAlign The String representing the corner of
  2994. * the Overlay that should be aligned to the context element
  2995. * @param {String} contextAlign The corner of the context element
  2996. * that the elementAlign corner should stick to.
  2997. * @param {Number[]} xyOffset Optional. A 2 element array specifying the x and y pixel offsets which should be applied
  2998. * after aligning the element and context corners. For example, passing in [5, -10] for this value, would offset the
  2999. * Overlay by 5 pixels along the X axis (horizontally) and -10 pixels along the Y axis (vertically) after aligning the specified corners.
  3000. */
  3001. align: function (elementAlign, contextAlign, xyOffset) {
  3002. var contextArgs = this.cfg.getProperty("context"),
  3003. me = this,
  3004. context,
  3005. element,
  3006. contextRegion;
  3007. function doAlign(v, h) {
  3008. var alignX = null, alignY = null;
  3009. switch (elementAlign) {
  3010. case Overlay.TOP_LEFT:
  3011. alignX = h;
  3012. alignY = v;
  3013. break;
  3014. case Overlay.TOP_RIGHT:
  3015. alignX = h - element.offsetWidth;
  3016. alignY = v;
  3017. break;
  3018. case Overlay.BOTTOM_LEFT:
  3019. alignX = h;
  3020. alignY = v - element.offsetHeight;
  3021. break;
  3022. case Overlay.BOTTOM_RIGHT:
  3023. alignX = h - element.offsetWidth;
  3024. alignY = v - element.offsetHeight;
  3025. break;
  3026. }
  3027. if (alignX !== null && alignY !== null) {
  3028. if (xyOffset) {
  3029. alignX += xyOffset[0];
  3030. alignY += xyOffset[1];
  3031. }
  3032. me.moveTo(alignX, alignY);
  3033. }
  3034. }
  3035. if (contextArgs) {
  3036. context = contextArgs[0];
  3037. element = this.element;
  3038. me = this;
  3039. if (! elementAlign) {
  3040. elementAlign = contextArgs[1];
  3041. }
  3042. if (! contextAlign) {
  3043. contextAlign = contextArgs[2];
  3044. }
  3045. if (!xyOffset && contextArgs[4]) {
  3046. xyOffset = contextArgs[4];
  3047. }
  3048. if (element && context) {
  3049. contextRegion = Dom.getRegion(context);
  3050. switch (contextAlign) {
  3051. case Overlay.TOP_LEFT:
  3052. doAlign(contextRegion.top, contextRegion.left);
  3053. break;
  3054. case Overlay.TOP_RIGHT:
  3055. doAlign(contextRegion.top, contextRegion.right);
  3056. break;
  3057. case Overlay.BOTTOM_LEFT:
  3058. doAlign(contextRegion.bottom, contextRegion.left);
  3059. break;
  3060. case Overlay.BOTTOM_RIGHT:
  3061. doAlign(contextRegion.bottom, contextRegion.right);
  3062. break;
  3063. }
  3064. }
  3065. }
  3066. },
  3067. /**
  3068. * The default event handler executed when the moveEvent is fired, if the
  3069. * "constraintoviewport" is set to true.
  3070. * @method enforceConstraints
  3071. * @param {String} type The CustomEvent type (usually the property name)
  3072. * @param {Object[]} args The CustomEvent arguments. For configuration
  3073. * handlers, args[0] will equal the newly applied value for the property.
  3074. * @param {Object} obj The scope object. For configuration handlers,
  3075. * this will usually equal the owner.
  3076. */
  3077. enforceConstraints: function (type, args, obj) {
  3078. var pos = args[0];
  3079. var cXY = this.getConstrainedXY(pos[0], pos[1]);
  3080. this.cfg.setProperty("x", cXY[0], true);
  3081. this.cfg.setProperty("y", cXY[1], true);
  3082. this.cfg.setProperty("xy", cXY, true);
  3083. },
  3084. /**
  3085. * Shared implementation method for getConstrainedX and getConstrainedY.
  3086. *
  3087. * <p>
  3088. * Given a coordinate value, returns the calculated coordinate required to
  3089. * position the Overlay if it is to be constrained to the viewport, based on the
  3090. * current element size, viewport dimensions, scroll values and preventoverlap
  3091. * settings
  3092. * </p>
  3093. *
  3094. * @method _getConstrainedPos
  3095. * @protected
  3096. * @param {String} pos The coordinate which needs to be constrained, either "x" or "y"
  3097. * @param {Number} The coordinate value which needs to be constrained
  3098. * @return {Number} The constrained coordinate value
  3099. */
  3100. _getConstrainedPos: function(pos, val) {
  3101. var overlayEl = this.element,
  3102. buffer = Overlay.VIEWPORT_OFFSET,
  3103. x = (pos == "x"),
  3104. overlaySize = (x) ? overlayEl.offsetWidth : overlayEl.offsetHeight,
  3105. viewportSize = (x) ? Dom.getViewportWidth() : Dom.getViewportHeight(),
  3106. docScroll = (x) ? Dom.getDocumentScrollLeft() : Dom.getDocumentScrollTop(),
  3107. overlapPositions = (x) ? Overlay.PREVENT_OVERLAP_X : Overlay.PREVENT_OVERLAP_Y,
  3108. context = this.cfg.getProperty("context"),
  3109. bOverlayFitsInViewport = (overlaySize + buffer < viewportSize),
  3110. bPreventContextOverlap = this.cfg.getProperty("preventcontextoverlap") && context && overlapPositions[(context[1] + context[2])],
  3111. minConstraint = docScroll + buffer,
  3112. maxConstraint = docScroll + viewportSize - overlaySize - buffer,
  3113. constrainedVal = val;
  3114. if (val < minConstraint || val > maxConstraint) {
  3115. if (bPreventContextOverlap) {
  3116. constrainedVal = this._preventOverlap(pos, context[0], overlaySize, viewportSize, docScroll);
  3117. } else {
  3118. if (bOverlayFitsInViewport) {
  3119. if (val < minConstraint) {
  3120. constrainedVal = minConstraint;
  3121. } else if (val > maxConstraint) {
  3122. constrainedVal = maxConstraint;
  3123. }
  3124. } else {
  3125. constrainedVal = minConstraint;
  3126. }
  3127. }
  3128. }
  3129. return constrainedVal;
  3130. },
  3131. /**
  3132. * Helper method, used to position the Overlap to prevent overlap with the
  3133. * context element (used when preventcontextoverlap is enabled)
  3134. *
  3135. * @method _preventOverlap
  3136. * @protected
  3137. * @param {String} pos The coordinate to prevent overlap for, either "x" or "y".
  3138. * @param {HTMLElement} contextEl The context element
  3139. * @param {Number} overlaySize The related overlay dimension value (for "x", the width, for "y", the height)
  3140. * @param {Number} viewportSize The related viewport dimension value (for "x", the width, for "y", the height)
  3141. * @param {Object} docScroll The related document scroll value (for "x", the scrollLeft, for "y", the scrollTop)
  3142. *
  3143. * @return {Number} The new coordinate value which was set to prevent overlap
  3144. */
  3145. _preventOverlap : function(pos, contextEl, overlaySize, viewportSize, docScroll) {
  3146. var x = (pos == "x"),
  3147. buffer = Overlay.VIEWPORT_OFFSET,
  3148. overlay = this,
  3149. contextElPos = ((x) ? Dom.getX(contextEl) : Dom.getY(contextEl)) - docScroll,
  3150. contextElSize = (x) ? contextEl.offsetWidth : contextEl.offsetHeight,
  3151. minRegionSize = contextElPos - buffer,
  3152. maxRegionSize = (viewportSize - (contextElPos + contextElSize)) - buffer,
  3153. bFlipped = false,
  3154. flip = function () {
  3155. var flippedVal;
  3156. if ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) {
  3157. flippedVal = (contextElPos - overlaySize);
  3158. } else {
  3159. flippedVal = (contextElPos + contextElSize);
  3160. }
  3161. overlay.cfg.setProperty(pos, (flippedVal + docScroll), true);
  3162. return flippedVal;
  3163. },
  3164. setPosition = function () {
  3165. var displayRegionSize = ((overlay.cfg.getProperty(pos) - docScroll) > contextElPos) ? maxRegionSize : minRegionSize,
  3166. position;
  3167. if (overlaySize > displayRegionSize) {
  3168. if (bFlipped) {
  3169. /*
  3170. All possible positions and values have been
  3171. tried, but none were successful, so fall back
  3172. to the original size and position.
  3173. */
  3174. flip();
  3175. } else {
  3176. flip();
  3177. bFlipped = true;
  3178. position = setPosition();
  3179. }
  3180. }
  3181. return position;
  3182. };
  3183. setPosition();
  3184. return this.cfg.getProperty(pos);
  3185. },
  3186. /**
  3187. * Given x coordinate value, returns the calculated x coordinate required to
  3188. * position the Overlay if it is to be constrained to the viewport, based on the
  3189. * current element size, viewport dimensions and scroll values.
  3190. *
  3191. * @param {Number} x The X coordinate value to be constrained
  3192. * @return {Number} The constrained x coordinate
  3193. */
  3194. getConstrainedX: function (x) {
  3195. return this._getConstrainedPos("x", x);
  3196. },
  3197. /**
  3198. * Given y coordinate value, returns the calculated y coordinate required to
  3199. * position the Overlay if it is to be constrained to the viewport, based on the
  3200. * current element size, viewport dimensions and scroll values.
  3201. *
  3202. * @param {Number} y The Y coordinate value to be constrained
  3203. * @return {Number} The constrained y coordinate
  3204. */
  3205. getConstrainedY : function (y) {
  3206. return this._getConstrainedPos("y", y);
  3207. },
  3208. /**
  3209. * Given x, y coordinate values, returns the calculated coordinates required to
  3210. * position the Overlay if it is to be constrained to the viewport, based on the
  3211. * current element size, viewport dimensions and scroll values.
  3212. *
  3213. * @param {Number} x The X coordinate value to be constrained
  3214. * @param {Number} y The Y coordinate value to be constrained
  3215. * @return {Array} The constrained x and y coordinates at index 0 and 1 respectively;
  3216. */
  3217. getConstrainedXY: function(x, y) {
  3218. return [this.getConstrainedX(x), this.getConstrainedY(y)];
  3219. },
  3220. /**
  3221. * Centers the container in the viewport.
  3222. * @method center
  3223. */
  3224. center: function () {
  3225. var nViewportOffset = Overlay.VIEWPORT_OFFSET,
  3226. elementWidth = this.element.offsetWidth,
  3227. elementHeight = this.element.offsetHeight,
  3228. viewPortWidth = Dom.getViewportWidth(),
  3229. viewPortHeight = Dom.getViewportHeight(),
  3230. x,
  3231. y;
  3232. if (elementWidth < viewPortWidth) {
  3233. x = (viewPortWidth / 2) - (elementWidth / 2) + Dom.getDocumentScrollLeft();
  3234. } else {
  3235. x = nViewportOffset + Dom.getDocumentScrollLeft();
  3236. }
  3237. if (elementHeight < viewPortHeight) {
  3238. y = (viewPortHeight / 2) - (elementHeight / 2) + Dom.getDocumentScrollTop();
  3239. } else {
  3240. y = nViewportOffset + Dom.getDocumentScrollTop();
  3241. }
  3242. this.cfg.setProperty("xy", [parseInt(x, 10), parseInt(y, 10)]);
  3243. this.cfg.refireEvent("iframe");
  3244. if (UA.webkit) {
  3245. this.forceContainerRedraw();
  3246. }
  3247. },
  3248. /**
  3249. * Synchronizes the Panel's "xy", "x", and "y" properties with the
  3250. * Panel's position in the DOM. This is primarily used to update
  3251. * position information during drag & drop.
  3252. * @method syncPosition
  3253. */
  3254. syncPosition: function () {
  3255. var pos = Dom.getXY(this.element);
  3256. this.cfg.setProperty("x", pos[0], true);
  3257. this.cfg.setProperty("y", pos[1], true);
  3258. this.cfg.setProperty("xy", pos, true);
  3259. },
  3260. /**
  3261. * Event handler fired when the resize monitor element is resized.
  3262. * @method onDomResize
  3263. * @param {DOMEvent} e The resize DOM event
  3264. * @param {Object} obj The scope object
  3265. */
  3266. onDomResize: function (e, obj) {
  3267. var me = this;
  3268. Overlay.superclass.onDomResize.call(this, e, obj);
  3269. setTimeout(function () {
  3270. me.syncPosition();
  3271. me.cfg.refireEvent("iframe");
  3272. me.cfg.refireEvent("context");
  3273. }, 0);
  3274. },
  3275. /**
  3276. * Determines the content box height of the given element (height of the element, without padding or borders) in pixels.
  3277. *
  3278. * @method _getComputedHeight
  3279. * @private
  3280. * @param {HTMLElement} el The element for which the content height needs to be determined
  3281. * @return {Number} The content box height of the given element, or null if it could not be determined.
  3282. */
  3283. _getComputedHeight : (function() {
  3284. if (document.defaultView && document.defaultView.getComputedStyle) {
  3285. return function(el) {
  3286. var height = null;
  3287. if (el.ownerDocument && el.ownerDocument.defaultView) {
  3288. var computed = el.ownerDocument.defaultView.getComputedStyle(el, '');
  3289. if (computed) {
  3290. height = parseInt(computed.height, 10);
  3291. }
  3292. }
  3293. return (Lang.isNumber(height)) ? height : null;
  3294. };
  3295. } else {
  3296. return function(el) {
  3297. var height = null;
  3298. if (el.style.pixelHeight) {
  3299. height = el.style.pixelHeight;
  3300. }
  3301. return (Lang.isNumber(height)) ? height : null;
  3302. };
  3303. }
  3304. })(),
  3305. /**
  3306. * autofillheight validator. Verifies that the autofill value is either null
  3307. * or one of the strings : "body", "header" or "footer".
  3308. *
  3309. * @method _validateAutoFillHeight
  3310. * @protected
  3311. * @param {String} val
  3312. * @return true, if valid, false otherwise
  3313. */
  3314. _validateAutoFillHeight : function(val) {
  3315. return (!val) || (Lang.isString(val) && Overlay.STD_MOD_RE.test(val));
  3316. },
  3317. /**
  3318. * The default custom event handler executed when the overlay's height is changed,
  3319. * if the autofillheight property has been set.
  3320. *
  3321. * @method _autoFillOnHeightChange
  3322. * @protected
  3323. * @param {String} type The event type
  3324. * @param {Array} args The array of arguments passed to event subscribers
  3325. * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
  3326. * out the containers height
  3327. */
  3328. _autoFillOnHeightChange : function(type, args, el) {
  3329. var height = this.cfg.getProperty("height");
  3330. if ((height && height !== "auto") || (height === 0)) {
  3331. this.fillHeight(el);
  3332. }
  3333. },
  3334. /**
  3335. * Returns the sub-pixel height of the el, using getBoundingClientRect, if available,
  3336. * otherwise returns the offsetHeight
  3337. * @method _getPreciseHeight
  3338. * @private
  3339. * @param {HTMLElement} el
  3340. * @return {Float} The sub-pixel height if supported by the browser, else the rounded height.
  3341. */
  3342. _getPreciseHeight : function(el) {
  3343. var height = el.offsetHeight;
  3344. if (el.getBoundingClientRect) {
  3345. var rect = el.getBoundingClientRect();
  3346. height = rect.bottom - rect.top;
  3347. }
  3348. return height;
  3349. },
  3350. /**
  3351. * <p>
  3352. * Sets the height on the provided header, body or footer element to
  3353. * fill out the height of the container. It determines the height of the
  3354. * containers content box, based on it's configured height value, and
  3355. * sets the height of the autofillheight element to fill out any
  3356. * space remaining after the other standard module element heights
  3357. * have been accounted for.
  3358. * </p>
  3359. * <p><strong>NOTE:</strong> This method is not designed to work if an explicit
  3360. * height has not been set on the container, since for an "auto" height container,
  3361. * the heights of the header/body/footer will drive the height of the container.</p>
  3362. *
  3363. * @method fillHeight
  3364. * @param {HTMLElement} el The element which should be resized to fill out the height
  3365. * of the container element.
  3366. */
  3367. fillHeight : function(el) {
  3368. if (el) {
  3369. var container = this.innerElement || this.element,
  3370. containerEls = [this.header, this.body, this.footer],
  3371. containerEl,
  3372. total = 0,
  3373. filled = 0,
  3374. remaining = 0,
  3375. validEl = false;
  3376. for (var i = 0, l = containerEls.length; i < l; i++) {
  3377. containerEl = containerEls[i];
  3378. if (containerEl) {
  3379. if (el !== containerEl) {
  3380. filled += this._getPreciseHeight(containerEl);
  3381. } else {
  3382. validEl = true;
  3383. }
  3384. }
  3385. }
  3386. if (validEl) {
  3387. if (UA.ie || UA.opera) {
  3388. // Need to set height to 0, to allow height to be reduced
  3389. Dom.setStyle(el, 'height', 0 + 'px');
  3390. }
  3391. total = this._getComputedHeight(container);
  3392. // Fallback, if we can't get computed value for content height
  3393. if (total === null) {
  3394. Dom.addClass(container, "yui-override-padding");
  3395. total = container.clientHeight; // Content, No Border, 0 Padding (set by yui-override-padding)
  3396. Dom.removeClass(container, "yui-override-padding");
  3397. }
  3398. remaining = Math.max(total - filled, 0);
  3399. Dom.setStyle(el, "height", remaining + "px");
  3400. // Re-adjust height if required, to account for el padding and border
  3401. if (el.offsetHeight != remaining) {
  3402. remaining = Math.max(remaining - (el.offsetHeight - remaining), 0);
  3403. }
  3404. Dom.setStyle(el, "height", remaining + "px");
  3405. }
  3406. }
  3407. },
  3408. /**
  3409. * Places the Overlay on top of all other instances of
  3410. * YAHOO.widget.Overlay.
  3411. * @method bringToTop
  3412. */
  3413. bringToTop: function () {
  3414. var aOverlays = [],
  3415. oElement = this.element;
  3416. function compareZIndexDesc(p_oOverlay1, p_oOverlay2) {
  3417. var sZIndex1 = Dom.getStyle(p_oOverlay1, "zIndex"),
  3418. sZIndex2 = Dom.getStyle(p_oOverlay2, "zIndex"),
  3419. nZIndex1 = (!sZIndex1 || isNaN(sZIndex1)) ? 0 : parseInt(sZIndex1, 10),
  3420. nZIndex2 = (!sZIndex2 || isNaN(sZIndex2)) ? 0 : parseInt(sZIndex2, 10);
  3421. if (nZIndex1 > nZIndex2) {
  3422. return -1;
  3423. } else if (nZIndex1 < nZIndex2) {
  3424. return 1;
  3425. } else {
  3426. return 0;
  3427. }
  3428. }
  3429. function isOverlayElement(p_oElement) {
  3430. var isOverlay = Dom.hasClass(p_oElement, Overlay.CSS_OVERLAY),
  3431. Panel = YAHOO.widget.Panel;
  3432. if (isOverlay && !Dom.isAncestor(oElement, p_oElement)) {
  3433. if (Panel && Dom.hasClass(p_oElement, Panel.CSS_PANEL)) {
  3434. aOverlays[aOverlays.length] = p_oElement.parentNode;
  3435. } else {
  3436. aOverlays[aOverlays.length] = p_oElement;
  3437. }
  3438. }
  3439. }
  3440. Dom.getElementsBy(isOverlayElement, "DIV", document.body);
  3441. aOverlays.sort(compareZIndexDesc);
  3442. var oTopOverlay = aOverlays[0],
  3443. nTopZIndex;
  3444. if (oTopOverlay) {
  3445. nTopZIndex = Dom.getStyle(oTopOverlay, "zIndex");
  3446. if (!isNaN(nTopZIndex)) {
  3447. var bRequiresBump = false;
  3448. if (oTopOverlay != oElement) {
  3449. bRequiresBump = true;
  3450. } else if (aOverlays.length > 1) {
  3451. var nNextZIndex = Dom.getStyle(aOverlays[1], "zIndex");
  3452. // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
  3453. if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
  3454. bRequiresBump = true;
  3455. }
  3456. }
  3457. if (bRequiresBump) {
  3458. this.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
  3459. }
  3460. }
  3461. }
  3462. },
  3463. /**
  3464. * Removes the Overlay element from the DOM and sets all child
  3465. * elements to null.
  3466. * @method destroy
  3467. */
  3468. destroy: function () {
  3469. if (this.iframe) {
  3470. this.iframe.parentNode.removeChild(this.iframe);
  3471. }
  3472. this.iframe = null;
  3473. Overlay.windowResizeEvent.unsubscribe(
  3474. this.doCenterOnDOMEvent, this);
  3475. Overlay.windowScrollEvent.unsubscribe(
  3476. this.doCenterOnDOMEvent, this);
  3477. Module.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);
  3478. if (this._contextTriggers) {
  3479. // Unsubscribe context triggers - to cover context triggers which listen for global
  3480. // events such as windowResize and windowScroll. Easier just to unsubscribe all
  3481. this._processTriggers(this._contextTriggers, _UNSUBSCRIBE, this._alignOnTrigger);
  3482. }
  3483. Overlay.superclass.destroy.call(this);
  3484. },
  3485. /**
  3486. * Can be used to force the container to repaint/redraw it's contents.
  3487. * <p>
  3488. * By default applies and then removes a 1px bottom margin through the
  3489. * application/removal of a "yui-force-redraw" class.
  3490. * </p>
  3491. * <p>
  3492. * It is currently used by Overlay to force a repaint for webkit
  3493. * browsers, when centering.
  3494. * </p>
  3495. * @method forceContainerRedraw
  3496. */
  3497. forceContainerRedraw : function() {
  3498. var c = this;
  3499. Dom.addClass(c.element, "yui-force-redraw");
  3500. setTimeout(function() {
  3501. Dom.removeClass(c.element, "yui-force-redraw");
  3502. }, 0);
  3503. },
  3504. /**
  3505. * Returns a String representation of the object.
  3506. * @method toString
  3507. * @return {String} The string representation of the Overlay.
  3508. */
  3509. toString: function () {
  3510. return "Overlay " + this.id;
  3511. }
  3512. });
  3513. }());
  3514. (function () {
  3515. /**
  3516. * OverlayManager is used for maintaining the focus status of
  3517. * multiple Overlays.
  3518. * @namespace YAHOO.widget
  3519. * @namespace YAHOO.widget
  3520. * @class OverlayManager
  3521. * @constructor
  3522. * @param {Array} overlays Optional. A collection of Overlays to register
  3523. * with the manager.
  3524. * @param {Object} userConfig The object literal representing the user
  3525. * configuration of the OverlayManager
  3526. */
  3527. YAHOO.widget.OverlayManager = function (userConfig) {
  3528. this.init(userConfig);
  3529. };
  3530. var Overlay = YAHOO.widget.Overlay,
  3531. Event = YAHOO.util.Event,
  3532. Dom = YAHOO.util.Dom,
  3533. Config = YAHOO.util.Config,
  3534. CustomEvent = YAHOO.util.CustomEvent,
  3535. OverlayManager = YAHOO.widget.OverlayManager;
  3536. /**
  3537. * The CSS class representing a focused Overlay
  3538. * @property OverlayManager.CSS_FOCUSED
  3539. * @static
  3540. * @final
  3541. * @type String
  3542. */
  3543. OverlayManager.CSS_FOCUSED = "focused";
  3544. OverlayManager.prototype = {
  3545. /**
  3546. * The class's constructor function
  3547. * @property contructor
  3548. * @type Function
  3549. */
  3550. constructor: OverlayManager,
  3551. /**
  3552. * The array of Overlays that are currently registered
  3553. * @property overlays
  3554. * @type YAHOO.widget.Overlay[]
  3555. */
  3556. overlays: null,
  3557. /**
  3558. * Initializes the default configuration of the OverlayManager
  3559. * @method initDefaultConfig
  3560. */
  3561. initDefaultConfig: function () {
  3562. /**
  3563. * The collection of registered Overlays in use by
  3564. * the OverlayManager
  3565. * @config overlays
  3566. * @type YAHOO.widget.Overlay[]
  3567. * @default null
  3568. */
  3569. this.cfg.addProperty("overlays", { suppressEvent: true } );
  3570. /**
  3571. * The default DOM event that should be used to focus an Overlay
  3572. * @config focusevent
  3573. * @type String
  3574. * @default "mousedown"
  3575. */
  3576. this.cfg.addProperty("focusevent", { value: "mousedown" } );
  3577. },
  3578. /**
  3579. * Initializes the OverlayManager
  3580. * @method init
  3581. * @param {Overlay[]} overlays Optional. A collection of Overlays to
  3582. * register with the manager.
  3583. * @param {Object} userConfig The object literal representing the user
  3584. * configuration of the OverlayManager
  3585. */
  3586. init: function (userConfig) {
  3587. /**
  3588. * The OverlayManager's Config object used for monitoring
  3589. * configuration properties.
  3590. * @property cfg
  3591. * @type Config
  3592. */
  3593. this.cfg = new Config(this);
  3594. this.initDefaultConfig();
  3595. if (userConfig) {
  3596. this.cfg.applyConfig(userConfig, true);
  3597. }
  3598. this.cfg.fireQueue();
  3599. /**
  3600. * The currently activated Overlay
  3601. * @property activeOverlay
  3602. * @private
  3603. * @type YAHOO.widget.Overlay
  3604. */
  3605. var activeOverlay = null;
  3606. /**
  3607. * Returns the currently focused Overlay
  3608. * @method getActive
  3609. * @return {Overlay} The currently focused Overlay
  3610. */
  3611. this.getActive = function () {
  3612. return activeOverlay;
  3613. };
  3614. /**
  3615. * Focuses the specified Overlay
  3616. * @method focus
  3617. * @param {Overlay} overlay The Overlay to focus
  3618. * @param {String} overlay The id of the Overlay to focus
  3619. */
  3620. this.focus = function (overlay) {
  3621. var o = this.find(overlay);
  3622. if (o) {
  3623. o.focus();
  3624. }
  3625. };
  3626. /**
  3627. * Removes the specified Overlay from the manager
  3628. * @method remove
  3629. * @param {Overlay} overlay The Overlay to remove
  3630. * @param {String} overlay The id of the Overlay to remove
  3631. */
  3632. this.remove = function (overlay) {
  3633. var o = this.find(overlay),
  3634. originalZ;
  3635. if (o) {
  3636. if (activeOverlay == o) {
  3637. activeOverlay = null;
  3638. }
  3639. var bDestroyed = (o.element === null && o.cfg === null) ? true : false;
  3640. if (!bDestroyed) {
  3641. // Set it's zindex so that it's sorted to the end.
  3642. originalZ = Dom.getStyle(o.element, "zIndex");
  3643. o.cfg.setProperty("zIndex", -1000, true);
  3644. }
  3645. this.overlays.sort(this.compareZIndexDesc);
  3646. this.overlays = this.overlays.slice(0, (this.overlays.length - 1));
  3647. o.hideEvent.unsubscribe(o.blur);
  3648. o.destroyEvent.unsubscribe(this._onOverlayDestroy, o);
  3649. o.focusEvent.unsubscribe(this._onOverlayFocusHandler, o);
  3650. o.blurEvent.unsubscribe(this._onOverlayBlurHandler, o);
  3651. if (!bDestroyed) {
  3652. Event.removeListener(o.element, this.cfg.getProperty("focusevent"), this._onOverlayElementFocus);
  3653. o.cfg.setProperty("zIndex", originalZ, true);
  3654. o.cfg.setProperty("manager", null);
  3655. }
  3656. /* _managed Flag for custom or existing. Don't want to remove existing */
  3657. if (o.focusEvent._managed) { o.focusEvent = null; }
  3658. if (o.blurEvent._managed) { o.blurEvent = null; }
  3659. if (o.focus._managed) { o.focus = null; }
  3660. if (o.blur._managed) { o.blur = null; }
  3661. }
  3662. };
  3663. /**
  3664. * Removes focus from all registered Overlays in the manager
  3665. * @method blurAll
  3666. */
  3667. this.blurAll = function () {
  3668. var nOverlays = this.overlays.length,
  3669. i;
  3670. if (nOverlays > 0) {
  3671. i = nOverlays - 1;
  3672. do {
  3673. this.overlays[i].blur();
  3674. }
  3675. while(i--);
  3676. }
  3677. };
  3678. /**
  3679. * Updates the state of the OverlayManager and overlay, as a result of the overlay
  3680. * being blurred.
  3681. *
  3682. * @method _manageBlur
  3683. * @param {Overlay} overlay The overlay instance which got blurred.
  3684. * @protected
  3685. */
  3686. this._manageBlur = function (overlay) {
  3687. var changed = false;
  3688. if (activeOverlay == overlay) {
  3689. Dom.removeClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
  3690. activeOverlay = null;
  3691. changed = true;
  3692. }
  3693. return changed;
  3694. };
  3695. /**
  3696. * Updates the state of the OverlayManager and overlay, as a result of the overlay
  3697. * receiving focus.
  3698. *
  3699. * @method _manageFocus
  3700. * @param {Overlay} overlay The overlay instance which got focus.
  3701. * @protected
  3702. */
  3703. this._manageFocus = function(overlay) {
  3704. var changed = false;
  3705. if (activeOverlay != overlay) {
  3706. if (activeOverlay) {
  3707. activeOverlay.blur();
  3708. }
  3709. activeOverlay = overlay;
  3710. this.bringToTop(activeOverlay);
  3711. Dom.addClass(activeOverlay.element, OverlayManager.CSS_FOCUSED);
  3712. changed = true;
  3713. }
  3714. return changed;
  3715. };
  3716. var overlays = this.cfg.getProperty("overlays");
  3717. if (! this.overlays) {
  3718. this.overlays = [];
  3719. }
  3720. if (overlays) {
  3721. this.register(overlays);
  3722. this.overlays.sort(this.compareZIndexDesc);
  3723. }
  3724. },
  3725. /**
  3726. * @method _onOverlayElementFocus
  3727. * @description Event handler for the DOM event that is used to focus
  3728. * the Overlay instance as specified by the "focusevent"
  3729. * configuration property.
  3730. * @private
  3731. * @param {Event} p_oEvent Object representing the DOM event
  3732. * object passed back by the event utility (Event).
  3733. */
  3734. _onOverlayElementFocus: function (p_oEvent) {
  3735. var oTarget = Event.getTarget(p_oEvent),
  3736. oClose = this.close;
  3737. if (oClose && (oTarget == oClose || Dom.isAncestor(oClose, oTarget))) {
  3738. this.blur();
  3739. } else {
  3740. this.focus();
  3741. }
  3742. },
  3743. /**
  3744. * @method _onOverlayDestroy
  3745. * @description "destroy" event handler for the Overlay.
  3746. * @private
  3747. * @param {String} p_sType String representing the name of the event
  3748. * that was fired.
  3749. * @param {Array} p_aArgs Array of arguments sent when the event
  3750. * was fired.
  3751. * @param {Overlay} p_oOverlay Object representing the overlay that
  3752. * fired the event.
  3753. */
  3754. _onOverlayDestroy: function (p_sType, p_aArgs, p_oOverlay) {
  3755. this.remove(p_oOverlay);
  3756. },
  3757. /**
  3758. * @method _onOverlayFocusHandler
  3759. *
  3760. * @description focusEvent Handler, used to delegate to _manageFocus with the correct arguments.
  3761. *
  3762. * @private
  3763. * @param {String} p_sType String representing the name of the event
  3764. * that was fired.
  3765. * @param {Array} p_aArgs Array of arguments sent when the event
  3766. * was fired.
  3767. * @param {Overlay} p_oOverlay Object representing the overlay that
  3768. * fired the event.
  3769. */
  3770. _onOverlayFocusHandler: function(p_sType, p_aArgs, p_oOverlay) {
  3771. this._manageFocus(p_oOverlay);
  3772. },
  3773. /**
  3774. * @method _onOverlayBlurHandler
  3775. * @description blurEvent Handler, used to delegate to _manageBlur with the correct arguments.
  3776. *
  3777. * @private
  3778. * @param {String} p_sType String representing the name of the event
  3779. * that was fired.
  3780. * @param {Array} p_aArgs Array of arguments sent when the event
  3781. * was fired.
  3782. * @param {Overlay} p_oOverlay Object representing the overlay that
  3783. * fired the event.
  3784. */
  3785. _onOverlayBlurHandler: function(p_sType, p_aArgs, p_oOverlay) {
  3786. this._manageBlur(p_oOverlay);
  3787. },
  3788. /**
  3789. * Subscribes to the Overlay based instance focusEvent, to allow the OverlayManager to
  3790. * monitor focus state.
  3791. *
  3792. * If the instance already has a focusEvent (e.g. Menu), OverlayManager will subscribe
  3793. * to the existing focusEvent, however if a focusEvent or focus method does not exist
  3794. * on the instance, the _bindFocus method will add them, and the focus method will
  3795. * update the OverlayManager's state directly.
  3796. *
  3797. * @method _bindFocus
  3798. * @param {Overlay} overlay The overlay for which focus needs to be managed
  3799. * @protected
  3800. */
  3801. _bindFocus : function(overlay) {
  3802. var mgr = this;
  3803. if (!overlay.focusEvent) {
  3804. overlay.focusEvent = overlay.createEvent("focus");
  3805. overlay.focusEvent.signature = CustomEvent.LIST;
  3806. overlay.focusEvent._managed = true;
  3807. } else {
  3808. overlay.focusEvent.subscribe(mgr._onOverlayFocusHandler, overlay, mgr);
  3809. }
  3810. if (!overlay.focus) {
  3811. Event.on(overlay.element, mgr.cfg.getProperty("focusevent"), mgr._onOverlayElementFocus, null, overlay);
  3812. overlay.focus = function () {
  3813. if (mgr._manageFocus(this)) {
  3814. // For Panel/Dialog
  3815. if (this.cfg.getProperty("visible") && this.focusFirst) {
  3816. this.focusFirst();
  3817. }
  3818. this.focusEvent.fire();
  3819. }
  3820. };
  3821. overlay.focus._managed = true;
  3822. }
  3823. },
  3824. /**
  3825. * Subscribes to the Overlay based instance's blurEvent to allow the OverlayManager to
  3826. * monitor blur state.
  3827. *
  3828. * If the instance already has a blurEvent (e.g. Menu), OverlayManager will subscribe
  3829. * to the existing blurEvent, however if a blurEvent or blur method does not exist
  3830. * on the instance, the _bindBlur method will add them, and the blur method
  3831. * update the OverlayManager's state directly.
  3832. *
  3833. * @method _bindBlur
  3834. * @param {Overlay} overlay The overlay for which blur needs to be managed
  3835. * @protected
  3836. */
  3837. _bindBlur : function(overlay) {
  3838. var mgr = this;
  3839. if (!overlay.blurEvent) {
  3840. overlay.blurEvent = overlay.createEvent("blur");
  3841. overlay.blurEvent.signature = CustomEvent.LIST;
  3842. overlay.focusEvent._managed = true;
  3843. } else {
  3844. overlay.blurEvent.subscribe(mgr._onOverlayBlurHandler, overlay, mgr);
  3845. }
  3846. if (!overlay.blur) {
  3847. overlay.blur = function () {
  3848. if (mgr._manageBlur(this)) {
  3849. this.blurEvent.fire();
  3850. }
  3851. };
  3852. overlay.blur._managed = true;
  3853. }
  3854. overlay.hideEvent.subscribe(overlay.blur);
  3855. },
  3856. /**
  3857. * Subscribes to the Overlay based instance's destroyEvent, to allow the Overlay
  3858. * to be removed for the OverlayManager when destroyed.
  3859. *
  3860. * @method _bindDestroy
  3861. * @param {Overlay} overlay The overlay instance being managed
  3862. * @protected
  3863. */
  3864. _bindDestroy : function(overlay) {
  3865. var mgr = this;
  3866. overlay.destroyEvent.subscribe(mgr._onOverlayDestroy, overlay, mgr);
  3867. },
  3868. /**
  3869. * Ensures the zIndex configuration property on the managed overlay based instance
  3870. * is set to the computed zIndex value from the DOM (with "auto" translating to 0).
  3871. *
  3872. * @method _syncZIndex
  3873. * @param {Overlay} overlay The overlay instance being managed
  3874. * @protected
  3875. */
  3876. _syncZIndex : function(overlay) {
  3877. var zIndex = Dom.getStyle(overlay.element, "zIndex");
  3878. if (!isNaN(zIndex)) {
  3879. overlay.cfg.setProperty("zIndex", parseInt(zIndex, 10));
  3880. } else {
  3881. overlay.cfg.setProperty("zIndex", 0);
  3882. }
  3883. },
  3884. /**
  3885. * Registers an Overlay or an array of Overlays with the manager. Upon
  3886. * registration, the Overlay receives functions for focus and blur,
  3887. * along with CustomEvents for each.
  3888. *
  3889. * @method register
  3890. * @param {Overlay} overlay An Overlay to register with the manager.
  3891. * @param {Overlay[]} overlay An array of Overlays to register with
  3892. * the manager.
  3893. * @return {boolean} true if any Overlays are registered.
  3894. */
  3895. register: function (overlay) {
  3896. var registered = false,
  3897. i,
  3898. n;
  3899. if (overlay instanceof Overlay) {
  3900. overlay.cfg.addProperty("manager", { value: this } );
  3901. this._bindFocus(overlay);
  3902. this._bindBlur(overlay);
  3903. this._bindDestroy(overlay);
  3904. this._syncZIndex(overlay);
  3905. this.overlays.push(overlay);
  3906. this.bringToTop(overlay);
  3907. registered = true;
  3908. } else if (overlay instanceof Array) {
  3909. for (i = 0, n = overlay.length; i < n; i++) {
  3910. registered = this.register(overlay[i]) || registered;
  3911. }
  3912. }
  3913. return registered;
  3914. },
  3915. /**
  3916. * Places the specified Overlay instance on top of all other
  3917. * Overlay instances.
  3918. * @method bringToTop
  3919. * @param {YAHOO.widget.Overlay} p_oOverlay Object representing an
  3920. * Overlay instance.
  3921. * @param {String} p_oOverlay String representing the id of an
  3922. * Overlay instance.
  3923. */
  3924. bringToTop: function (p_oOverlay) {
  3925. var oOverlay = this.find(p_oOverlay),
  3926. nTopZIndex,
  3927. oTopOverlay,
  3928. aOverlays;
  3929. if (oOverlay) {
  3930. aOverlays = this.overlays;
  3931. aOverlays.sort(this.compareZIndexDesc);
  3932. oTopOverlay = aOverlays[0];
  3933. if (oTopOverlay) {
  3934. nTopZIndex = Dom.getStyle(oTopOverlay.element, "zIndex");
  3935. if (!isNaN(nTopZIndex)) {
  3936. var bRequiresBump = false;
  3937. if (oTopOverlay !== oOverlay) {
  3938. bRequiresBump = true;
  3939. } else if (aOverlays.length > 1) {
  3940. var nNextZIndex = Dom.getStyle(aOverlays[1].element, "zIndex");
  3941. // Don't rely on DOM order to stack if 2 overlays are at the same zindex.
  3942. if (!isNaN(nNextZIndex) && (nTopZIndex == nNextZIndex)) {
  3943. bRequiresBump = true;
  3944. }
  3945. }
  3946. if (bRequiresBump) {
  3947. oOverlay.cfg.setProperty("zindex", (parseInt(nTopZIndex, 10) + 2));
  3948. }
  3949. }
  3950. aOverlays.sort(this.compareZIndexDesc);
  3951. }
  3952. }
  3953. },
  3954. /**
  3955. * Attempts to locate an Overlay by instance or ID.
  3956. * @method find
  3957. * @param {Overlay} overlay An Overlay to locate within the manager
  3958. * @param {String} overlay An Overlay id to locate within the manager
  3959. * @return {Overlay} The requested Overlay, if found, or null if it
  3960. * cannot be located.
  3961. */
  3962. find: function (overlay) {
  3963. var isInstance = overlay instanceof Overlay,
  3964. overlays = this.overlays,
  3965. n = overlays.length,
  3966. found = null,
  3967. o,
  3968. i;
  3969. if (isInstance || typeof overlay == "string") {
  3970. for (i = n-1; i >= 0; i--) {
  3971. o = overlays[i];
  3972. if ((isInstance && (o === overlay)) || (o.id == overlay)) {
  3973. found = o;
  3974. break;
  3975. }
  3976. }
  3977. }
  3978. return found;
  3979. },
  3980. /**
  3981. * Used for sorting the manager's Overlays by z-index.
  3982. * @method compareZIndexDesc
  3983. * @private
  3984. * @return {Number} 0, 1, or -1, depending on where the Overlay should
  3985. * fall in the stacking order.
  3986. */
  3987. compareZIndexDesc: function (o1, o2) {
  3988. var zIndex1 = (o1.cfg) ? o1.cfg.getProperty("zIndex") : null, // Sort invalid (destroyed)
  3989. zIndex2 = (o2.cfg) ? o2.cfg.getProperty("zIndex") : null; // objects at bottom.
  3990. if (zIndex1 === null && zIndex2 === null) {
  3991. return 0;
  3992. } else if (zIndex1 === null){
  3993. return 1;
  3994. } else if (zIndex2 === null) {
  3995. return -1;
  3996. } else if (zIndex1 > zIndex2) {
  3997. return -1;
  3998. } else if (zIndex1 < zIndex2) {
  3999. return 1;
  4000. } else {
  4001. return 0;
  4002. }
  4003. },
  4004. /**
  4005. * Shows all Overlays in the manager.
  4006. * @method showAll
  4007. */
  4008. showAll: function () {
  4009. var overlays = this.overlays,
  4010. n = overlays.length,
  4011. i;
  4012. for (i = n - 1; i >= 0; i--) {
  4013. overlays[i].show();
  4014. }
  4015. },
  4016. /**
  4017. * Hides all Overlays in the manager.
  4018. * @method hideAll
  4019. */
  4020. hideAll: function () {
  4021. var overlays = this.overlays,
  4022. n = overlays.length,
  4023. i;
  4024. for (i = n - 1; i >= 0; i--) {
  4025. overlays[i].hide();
  4026. }
  4027. },
  4028. /**
  4029. * Returns a string representation of the object.
  4030. * @method toString
  4031. * @return {String} The string representation of the OverlayManager
  4032. */
  4033. toString: function () {
  4034. return "OverlayManager";
  4035. }
  4036. };
  4037. }());
  4038. (function () {
  4039. /**
  4040. * Tooltip is an implementation of Overlay that behaves like an OS tooltip,
  4041. * displaying when the user mouses over a particular element, and
  4042. * disappearing on mouse out.
  4043. * @namespace YAHOO.widget
  4044. * @class Tooltip
  4045. * @extends YAHOO.widget.Overlay
  4046. * @constructor
  4047. * @param {String} el The element ID representing the Tooltip <em>OR</em>
  4048. * @param {HTMLElement} el The element representing the Tooltip
  4049. * @param {Object} userConfig The configuration object literal containing
  4050. * the configuration that should be set for this Overlay. See configuration
  4051. * documentation for more details.
  4052. */
  4053. YAHOO.widget.Tooltip = function (el, userConfig) {
  4054. YAHOO.widget.Tooltip.superclass.constructor.call(this, el, userConfig);
  4055. };
  4056. var Lang = YAHOO.lang,
  4057. Event = YAHOO.util.Event,
  4058. CustomEvent = YAHOO.util.CustomEvent,
  4059. Dom = YAHOO.util.Dom,
  4060. Tooltip = YAHOO.widget.Tooltip,
  4061. UA = YAHOO.env.ua,
  4062. bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
  4063. m_oShadowTemplate,
  4064. /**
  4065. * Constant representing the Tooltip's configuration properties
  4066. * @property DEFAULT_CONFIG
  4067. * @private
  4068. * @final
  4069. * @type Object
  4070. */
  4071. DEFAULT_CONFIG = {
  4072. "PREVENT_OVERLAP": {
  4073. key: "preventoverlap",
  4074. value: true,
  4075. validator: Lang.isBoolean,
  4076. supercedes: ["x", "y", "xy"]
  4077. },
  4078. "SHOW_DELAY": {
  4079. key: "showdelay",
  4080. value: 200,
  4081. validator: Lang.isNumber
  4082. },
  4083. "AUTO_DISMISS_DELAY": {
  4084. key: "autodismissdelay",
  4085. value: 5000,
  4086. validator: Lang.isNumber
  4087. },
  4088. "HIDE_DELAY": {
  4089. key: "hidedelay",
  4090. value: 250,
  4091. validator: Lang.isNumber
  4092. },
  4093. "TEXT": {
  4094. key: "text",
  4095. suppressEvent: true
  4096. },
  4097. "CONTAINER": {
  4098. key: "container"
  4099. },
  4100. "DISABLED": {
  4101. key: "disabled",
  4102. value: false,
  4103. suppressEvent: true
  4104. },
  4105. "XY_OFFSET": {
  4106. key: "xyoffset",
  4107. value: [0, 25],
  4108. suppressEvent: true
  4109. }
  4110. },
  4111. /**
  4112. * Constant representing the name of the Tooltip's events
  4113. * @property EVENT_TYPES
  4114. * @private
  4115. * @final
  4116. * @type Object
  4117. */
  4118. EVENT_TYPES = {
  4119. "CONTEXT_MOUSE_OVER": "contextMouseOver",
  4120. "CONTEXT_MOUSE_OUT": "contextMouseOut",
  4121. "CONTEXT_TRIGGER": "contextTrigger"
  4122. };
  4123. /**
  4124. * Constant representing the Tooltip CSS class
  4125. * @property YAHOO.widget.Tooltip.CSS_TOOLTIP
  4126. * @static
  4127. * @final
  4128. * @type String
  4129. */
  4130. Tooltip.CSS_TOOLTIP = "yui-tt";
  4131. function restoreOriginalWidth(sOriginalWidth, sForcedWidth) {
  4132. var oConfig = this.cfg,
  4133. sCurrentWidth = oConfig.getProperty("width");
  4134. if (sCurrentWidth == sForcedWidth) {
  4135. oConfig.setProperty("width", sOriginalWidth);
  4136. }
  4137. }
  4138. /*
  4139. changeContent event handler that sets a Tooltip instance's "width"
  4140. configuration property to the value of its root HTML
  4141. elements's offsetWidth if a specific width has not been set.
  4142. */
  4143. function setWidthToOffsetWidth(p_sType, p_aArgs) {
  4144. if ("_originalWidth" in this) {
  4145. restoreOriginalWidth.call(this, this._originalWidth, this._forcedWidth);
  4146. }
  4147. var oBody = document.body,
  4148. oConfig = this.cfg,
  4149. sOriginalWidth = oConfig.getProperty("width"),
  4150. sNewWidth,
  4151. oClone;
  4152. if ((!sOriginalWidth || sOriginalWidth == "auto") &&
  4153. (oConfig.getProperty("container") != oBody ||
  4154. oConfig.getProperty("x") >= Dom.getViewportWidth() ||
  4155. oConfig.getProperty("y") >= Dom.getViewportHeight())) {
  4156. oClone = this.element.cloneNode(true);
  4157. oClone.style.visibility = "hidden";
  4158. oClone.style.top = "0px";
  4159. oClone.style.left = "0px";
  4160. oBody.appendChild(oClone);
  4161. sNewWidth = (oClone.offsetWidth + "px");
  4162. oBody.removeChild(oClone);
  4163. oClone = null;
  4164. oConfig.setProperty("width", sNewWidth);
  4165. oConfig.refireEvent("xy");
  4166. this._originalWidth = sOriginalWidth || "";
  4167. this._forcedWidth = sNewWidth;
  4168. }
  4169. }
  4170. // "onDOMReady" that renders the ToolTip
  4171. function onDOMReady(p_sType, p_aArgs, p_oObject) {
  4172. this.render(p_oObject);
  4173. }
  4174. // "init" event handler that automatically renders the Tooltip
  4175. function onInit() {
  4176. Event.onDOMReady(onDOMReady, this.cfg.getProperty("container"), this);
  4177. }
  4178. YAHOO.extend(Tooltip, YAHOO.widget.Overlay, {
  4179. /**
  4180. * The Tooltip initialization method. This method is automatically
  4181. * called by the constructor. A Tooltip is automatically rendered by
  4182. * the init method, and it also is set to be invisible by default,
  4183. * and constrained to viewport by default as well.
  4184. * @method init
  4185. * @param {String} el The element ID representing the Tooltip <em>OR</em>
  4186. * @param {HTMLElement} el The element representing the Tooltip
  4187. * @param {Object} userConfig The configuration object literal
  4188. * containing the configuration that should be set for this Tooltip.
  4189. * See configuration documentation for more details.
  4190. */
  4191. init: function (el, userConfig) {
  4192. this.logger = new YAHOO.widget.LogWriter(this.toString());
  4193. Tooltip.superclass.init.call(this, el);
  4194. this.beforeInitEvent.fire(Tooltip);
  4195. Dom.addClass(this.element, Tooltip.CSS_TOOLTIP);
  4196. if (userConfig) {
  4197. this.cfg.applyConfig(userConfig, true);
  4198. }
  4199. this.cfg.queueProperty("visible", false);
  4200. this.cfg.queueProperty("constraintoviewport", true);
  4201. this.setBody("");
  4202. this.subscribe("changeContent", setWidthToOffsetWidth);
  4203. this.subscribe("init", onInit);
  4204. this.subscribe("render", this.onRender);
  4205. this.initEvent.fire(Tooltip);
  4206. },
  4207. /**
  4208. * Initializes the custom events for Tooltip
  4209. * @method initEvents
  4210. */
  4211. initEvents: function () {
  4212. Tooltip.superclass.initEvents.call(this);
  4213. var SIGNATURE = CustomEvent.LIST;
  4214. /**
  4215. * CustomEvent fired when user mouses over a context element. Returning false from
  4216. * a subscriber to this event will prevent the tooltip from being displayed for
  4217. * the current context element.
  4218. *
  4219. * @event contextMouseOverEvent
  4220. * @param {HTMLElement} context The context element which the user just moused over
  4221. * @param {DOMEvent} e The DOM event object, associated with the mouse over
  4222. */
  4223. this.contextMouseOverEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OVER);
  4224. this.contextMouseOverEvent.signature = SIGNATURE;
  4225. /**
  4226. * CustomEvent fired when the user mouses out of a context element.
  4227. *
  4228. * @event contextMouseOutEvent
  4229. * @param {HTMLElement} context The context element which the user just moused out of
  4230. * @param {DOMEvent} e The DOM event object, associated with the mouse out
  4231. */
  4232. this.contextMouseOutEvent = this.createEvent(EVENT_TYPES.CONTEXT_MOUSE_OUT);
  4233. this.contextMouseOutEvent.signature = SIGNATURE;
  4234. /**
  4235. * CustomEvent fired just before the tooltip is displayed for the current context.
  4236. * <p>
  4237. * You can subscribe to this event if you need to set up the text for the
  4238. * tooltip based on the context element for which it is about to be displayed.
  4239. * </p>
  4240. * <p>This event differs from the beforeShow event in following respects:</p>
  4241. * <ol>
  4242. * <li>
  4243. * When moving from one context element to another, if the tooltip is not
  4244. * hidden (the <code>hidedelay</code> is not reached), the beforeShow and Show events will not
  4245. * be fired when the tooltip is displayed for the new context since it is already visible.
  4246. * However the contextTrigger event is always fired before displaying the tooltip for
  4247. * a new context.
  4248. * </li>
  4249. * <li>
  4250. * The trigger event provides access to the context element, allowing you to
  4251. * set the text of the tooltip based on context element for which the tooltip is
  4252. * triggered.
  4253. * </li>
  4254. * </ol>
  4255. * <p>
  4256. * It is not possible to prevent the tooltip from being displayed
  4257. * using this event. You can use the contextMouseOverEvent if you need to prevent
  4258. * the tooltip from being displayed.
  4259. * </p>
  4260. * @event contextTriggerEvent
  4261. * @param {HTMLElement} context The context element for which the tooltip is triggered
  4262. */
  4263. this.contextTriggerEvent = this.createEvent(EVENT_TYPES.CONTEXT_TRIGGER);
  4264. this.contextTriggerEvent.signature = SIGNATURE;
  4265. },
  4266. /**
  4267. * Initializes the class's configurable properties which can be
  4268. * changed using the Overlay's Config object (cfg).
  4269. * @method initDefaultConfig
  4270. */
  4271. initDefaultConfig: function () {
  4272. Tooltip.superclass.initDefaultConfig.call(this);
  4273. /**
  4274. * Specifies whether the Tooltip should be kept from overlapping
  4275. * its context element.
  4276. * @config preventoverlap
  4277. * @type Boolean
  4278. * @default true
  4279. */
  4280. this.cfg.addProperty(DEFAULT_CONFIG.PREVENT_OVERLAP.key, {
  4281. value: DEFAULT_CONFIG.PREVENT_OVERLAP.value,
  4282. validator: DEFAULT_CONFIG.PREVENT_OVERLAP.validator,
  4283. supercedes: DEFAULT_CONFIG.PREVENT_OVERLAP.supercedes
  4284. });
  4285. /**
  4286. * The number of milliseconds to wait before showing a Tooltip
  4287. * on mouseover.
  4288. * @config showdelay
  4289. * @type Number
  4290. * @default 200
  4291. */
  4292. this.cfg.addProperty(DEFAULT_CONFIG.SHOW_DELAY.key, {
  4293. handler: this.configShowDelay,
  4294. value: 200,
  4295. validator: DEFAULT_CONFIG.SHOW_DELAY.validator
  4296. });
  4297. /**
  4298. * The number of milliseconds to wait before automatically
  4299. * dismissing a Tooltip after the mouse has been resting on the
  4300. * context element.
  4301. * @config autodismissdelay
  4302. * @type Number
  4303. * @default 5000
  4304. */
  4305. this.cfg.addProperty(DEFAULT_CONFIG.AUTO_DISMISS_DELAY.key, {
  4306. handler: this.configAutoDismissDelay,
  4307. value: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.value,
  4308. validator: DEFAULT_CONFIG.AUTO_DISMISS_DELAY.validator
  4309. });
  4310. /**
  4311. * The number of milliseconds to wait before hiding a Tooltip
  4312. * after mouseout.
  4313. * @config hidedelay
  4314. * @type Number
  4315. * @default 250
  4316. */
  4317. this.cfg.addProperty(DEFAULT_CONFIG.HIDE_DELAY.key, {
  4318. handler: this.configHideDelay,
  4319. value: DEFAULT_CONFIG.HIDE_DELAY.value,
  4320. validator: DEFAULT_CONFIG.HIDE_DELAY.validator
  4321. });
  4322. /**
  4323. * Specifies the Tooltip's text.
  4324. * @config text
  4325. * @type String
  4326. * @default null
  4327. */
  4328. this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
  4329. handler: this.configText,
  4330. suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent
  4331. });
  4332. /**
  4333. * Specifies the container element that the Tooltip's markup
  4334. * should be rendered into.
  4335. * @config container
  4336. * @type HTMLElement/String
  4337. * @default document.body
  4338. */
  4339. this.cfg.addProperty(DEFAULT_CONFIG.CONTAINER.key, {
  4340. handler: this.configContainer,
  4341. value: document.body
  4342. });
  4343. /**
  4344. * Specifies whether or not the tooltip is disabled. Disabled tooltips
  4345. * will not be displayed. If the tooltip is driven by the title attribute
  4346. * of the context element, the title attribute will still be removed for
  4347. * disabled tooltips, to prevent default tooltip behavior.
  4348. *
  4349. * @config disabled
  4350. * @type Boolean
  4351. * @default false
  4352. */
  4353. this.cfg.addProperty(DEFAULT_CONFIG.DISABLED.key, {
  4354. handler: this.configContainer,
  4355. value: DEFAULT_CONFIG.DISABLED.value,
  4356. supressEvent: DEFAULT_CONFIG.DISABLED.suppressEvent
  4357. });
  4358. /**
  4359. * Specifies the XY offset from the mouse position, where the tooltip should be displayed, specified
  4360. * as a 2 element array (e.g. [10, 20]);
  4361. *
  4362. * @config xyoffset
  4363. * @type Array
  4364. * @default [0, 25]
  4365. */
  4366. this.cfg.addProperty(DEFAULT_CONFIG.XY_OFFSET.key, {
  4367. value: DEFAULT_CONFIG.XY_OFFSET.value.concat(),
  4368. supressEvent: DEFAULT_CONFIG.XY_OFFSET.suppressEvent
  4369. });
  4370. /**
  4371. * Specifies the element or elements that the Tooltip should be
  4372. * anchored to on mouseover.
  4373. * @config context
  4374. * @type HTMLElement[]/String[]
  4375. * @default null
  4376. */
  4377. /**
  4378. * String representing the width of the Tooltip. <em>Please note:
  4379. * </em> As of version 2.3 if either no value or a value of "auto"
  4380. * is specified, and the Toolip's "container" configuration property
  4381. * is set to something other than <code>document.body</code> or
  4382. * its "context" element resides outside the immediately visible
  4383. * portion of the document, the width of the Tooltip will be
  4384. * calculated based on the offsetWidth of its root HTML and set just
  4385. * before it is made visible. The original value will be
  4386. * restored when the Tooltip is hidden. This ensures the Tooltip is
  4387. * rendered at a usable width. For more information see
  4388. * YUILibrary bug #1685496 and YUILibrary
  4389. * bug #1735423.
  4390. * @config width
  4391. * @type String
  4392. * @default null
  4393. */
  4394. },
  4395. // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
  4396. /**
  4397. * The default event handler fired when the "text" property is changed.
  4398. * @method configText
  4399. * @param {String} type The CustomEvent type (usually the property name)
  4400. * @param {Object[]} args The CustomEvent arguments. For configuration
  4401. * handlers, args[0] will equal the newly applied value for the property.
  4402. * @param {Object} obj The scope object. For configuration handlers,
  4403. * this will usually equal the owner.
  4404. */
  4405. configText: function (type, args, obj) {
  4406. var text = args[0];
  4407. if (text) {
  4408. this.setBody(text);
  4409. }
  4410. },
  4411. /**
  4412. * The default event handler fired when the "container" property
  4413. * is changed.
  4414. * @method configContainer
  4415. * @param {String} type The CustomEvent type (usually the property name)
  4416. * @param {Object[]} args The CustomEvent arguments. For
  4417. * configuration handlers, args[0] will equal the newly applied value
  4418. * for the property.
  4419. * @param {Object} obj The scope object. For configuration handlers,
  4420. * this will usually equal the owner.
  4421. */
  4422. configContainer: function (type, args, obj) {
  4423. var container = args[0];
  4424. if (typeof container == 'string') {
  4425. this.cfg.setProperty("container", document.getElementById(container), true);
  4426. }
  4427. },
  4428. /**
  4429. * @method _removeEventListeners
  4430. * @description Removes all of the DOM event handlers from the HTML
  4431. * element(s) that trigger the display of the tooltip.
  4432. * @protected
  4433. */
  4434. _removeEventListeners: function () {
  4435. var aElements = this._context,
  4436. nElements,
  4437. oElement,
  4438. i;
  4439. if (aElements) {
  4440. nElements = aElements.length;
  4441. if (nElements > 0) {
  4442. i = nElements - 1;
  4443. do {
  4444. oElement = aElements[i];
  4445. Event.removeListener(oElement, "mouseover", this.onContextMouseOver);
  4446. Event.removeListener(oElement, "mousemove", this.onContextMouseMove);
  4447. Event.removeListener(oElement, "mouseout", this.onContextMouseOut);
  4448. }
  4449. while (i--);
  4450. }
  4451. }
  4452. },
  4453. /**
  4454. * The default event handler fired when the "context" property
  4455. * is changed.
  4456. * @method configContext
  4457. * @param {String} type The CustomEvent type (usually the property name)
  4458. * @param {Object[]} args The CustomEvent arguments. For configuration
  4459. * handlers, args[0] will equal the newly applied value for the property.
  4460. * @param {Object} obj The scope object. For configuration handlers,
  4461. * this will usually equal the owner.
  4462. */
  4463. configContext: function (type, args, obj) {
  4464. var context = args[0],
  4465. aElements,
  4466. nElements,
  4467. oElement,
  4468. i;
  4469. if (context) {
  4470. // Normalize parameter into an array
  4471. if (! (context instanceof Array)) {
  4472. if (typeof context == "string") {
  4473. this.cfg.setProperty("context", [document.getElementById(context)], true);
  4474. } else { // Assuming this is an element
  4475. this.cfg.setProperty("context", [context], true);
  4476. }
  4477. context = this.cfg.getProperty("context");
  4478. }
  4479. // Remove any existing mouseover/mouseout listeners
  4480. this._removeEventListeners();
  4481. // Add mouseover/mouseout listeners to context elements
  4482. this._context = context;
  4483. aElements = this._context;
  4484. if (aElements) {
  4485. nElements = aElements.length;
  4486. if (nElements > 0) {
  4487. i = nElements - 1;
  4488. do {
  4489. oElement = aElements[i];
  4490. Event.on(oElement, "mouseover", this.onContextMouseOver, this);
  4491. Event.on(oElement, "mousemove", this.onContextMouseMove, this);
  4492. Event.on(oElement, "mouseout", this.onContextMouseOut, this);
  4493. }
  4494. while (i--);
  4495. }
  4496. }
  4497. }
  4498. },
  4499. // END BUILT-IN PROPERTY EVENT HANDLERS //
  4500. // BEGIN BUILT-IN DOM EVENT HANDLERS //
  4501. /**
  4502. * The default event handler fired when the user moves the mouse while
  4503. * over the context element.
  4504. * @method onContextMouseMove
  4505. * @param {DOMEvent} e The current DOM event
  4506. * @param {Object} obj The object argument
  4507. */
  4508. onContextMouseMove: function (e, obj) {
  4509. obj.pageX = Event.getPageX(e);
  4510. obj.pageY = Event.getPageY(e);
  4511. },
  4512. /**
  4513. * The default event handler fired when the user mouses over the
  4514. * context element.
  4515. * @method onContextMouseOver
  4516. * @param {DOMEvent} e The current DOM event
  4517. * @param {Object} obj The object argument
  4518. */
  4519. onContextMouseOver: function (e, obj) {
  4520. var context = this;
  4521. if (context.title) {
  4522. obj._tempTitle = context.title;
  4523. context.title = "";
  4524. }
  4525. // Fire first, to honor disabled set in the listner
  4526. if (obj.fireEvent("contextMouseOver", context, e) !== false
  4527. && !obj.cfg.getProperty("disabled")) {
  4528. // Stop the tooltip from being hidden (set on last mouseout)
  4529. if (obj.hideProcId) {
  4530. clearTimeout(obj.hideProcId);
  4531. obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
  4532. obj.hideProcId = null;
  4533. }
  4534. Event.on(context, "mousemove", obj.onContextMouseMove, obj);
  4535. /**
  4536. * The unique process ID associated with the thread responsible
  4537. * for showing the Tooltip.
  4538. * @type int
  4539. */
  4540. obj.showProcId = obj.doShow(e, context);
  4541. obj.logger.log("Setting show tooltip timeout: " + obj.showProcId, "time");
  4542. }
  4543. },
  4544. /**
  4545. * The default event handler fired when the user mouses out of
  4546. * the context element.
  4547. * @method onContextMouseOut
  4548. * @param {DOMEvent} e The current DOM event
  4549. * @param {Object} obj The object argument
  4550. */
  4551. onContextMouseOut: function (e, obj) {
  4552. var el = this;
  4553. if (obj._tempTitle) {
  4554. el.title = obj._tempTitle;
  4555. obj._tempTitle = null;
  4556. }
  4557. if (obj.showProcId) {
  4558. clearTimeout(obj.showProcId);
  4559. obj.logger.log("Clearing show timer: " + obj.showProcId, "time");
  4560. obj.showProcId = null;
  4561. }
  4562. if (obj.hideProcId) {
  4563. clearTimeout(obj.hideProcId);
  4564. obj.logger.log("Clearing hide timer: " + obj.hideProcId, "time");
  4565. obj.hideProcId = null;
  4566. }
  4567. obj.fireEvent("contextMouseOut", el, e);
  4568. obj.hideProcId = setTimeout(function () {
  4569. obj.hide();
  4570. }, obj.cfg.getProperty("hidedelay"));
  4571. },
  4572. // END BUILT-IN DOM EVENT HANDLERS //
  4573. /**
  4574. * Processes the showing of the Tooltip by setting the timeout delay
  4575. * and offset of the Tooltip.
  4576. * @method doShow
  4577. * @param {DOMEvent} e The current DOM event
  4578. * @param {HTMLElement} context The current context element
  4579. * @return {Number} The process ID of the timeout function associated
  4580. * with doShow
  4581. */
  4582. doShow: function (e, context) {
  4583. var offset = this.cfg.getProperty("xyoffset"),
  4584. xOffset = offset[0],
  4585. yOffset = offset[1],
  4586. me = this;
  4587. if (UA.opera && context.tagName &&
  4588. context.tagName.toUpperCase() == "A") {
  4589. yOffset += 12;
  4590. }
  4591. return setTimeout(function () {
  4592. var txt = me.cfg.getProperty("text");
  4593. // title does not over-ride text
  4594. if (me._tempTitle && (txt === "" || YAHOO.lang.isUndefined(txt) || YAHOO.lang.isNull(txt))) {
  4595. me.setBody(me._tempTitle);
  4596. } else {
  4597. me.cfg.refireEvent("text");
  4598. }
  4599. me.logger.log("Show tooltip", "time");
  4600. me.moveTo(me.pageX + xOffset, me.pageY + yOffset);
  4601. if (me.cfg.getProperty("preventoverlap")) {
  4602. me.preventOverlap(me.pageX, me.pageY);
  4603. }
  4604. Event.removeListener(context, "mousemove", me.onContextMouseMove);
  4605. me.contextTriggerEvent.fire(context);
  4606. me.show();
  4607. me.hideProcId = me.doHide();
  4608. me.logger.log("Hide tooltip time active: " + me.hideProcId, "time");
  4609. }, this.cfg.getProperty("showdelay"));
  4610. },
  4611. /**
  4612. * Sets the timeout for the auto-dismiss delay, which by default is 5
  4613. * seconds, meaning that a tooltip will automatically dismiss itself
  4614. * after 5 seconds of being displayed.
  4615. * @method doHide
  4616. */
  4617. doHide: function () {
  4618. var me = this;
  4619. me.logger.log("Setting hide tooltip timeout", "time");
  4620. return setTimeout(function () {
  4621. me.logger.log("Hide tooltip", "time");
  4622. me.hide();
  4623. }, this.cfg.getProperty("autodismissdelay"));
  4624. },
  4625. /**
  4626. * Fired when the Tooltip is moved, this event handler is used to
  4627. * prevent the Tooltip from overlapping with its context element.
  4628. * @method preventOverlay
  4629. * @param {Number} pageX The x coordinate position of the mouse pointer
  4630. * @param {Number} pageY The y coordinate position of the mouse pointer
  4631. */
  4632. preventOverlap: function (pageX, pageY) {
  4633. var height = this.element.offsetHeight,
  4634. mousePoint = new YAHOO.util.Point(pageX, pageY),
  4635. elementRegion = Dom.getRegion(this.element);
  4636. elementRegion.top -= 5;
  4637. elementRegion.left -= 5;
  4638. elementRegion.right += 5;
  4639. elementRegion.bottom += 5;
  4640. this.logger.log("context " + elementRegion, "ttip");
  4641. this.logger.log("mouse " + mousePoint, "ttip");
  4642. if (elementRegion.contains(mousePoint)) {
  4643. this.logger.log("OVERLAP", "warn");
  4644. this.cfg.setProperty("y", (pageY - height - 5));
  4645. }
  4646. },
  4647. /**
  4648. * @method onRender
  4649. * @description "render" event handler for the Tooltip.
  4650. * @param {String} p_sType String representing the name of the event
  4651. * that was fired.
  4652. * @param {Array} p_aArgs Array of arguments sent when the event
  4653. * was fired.
  4654. */
  4655. onRender: function (p_sType, p_aArgs) {
  4656. function sizeShadow() {
  4657. var oElement = this.element,
  4658. oShadow = this.underlay;
  4659. if (oShadow) {
  4660. oShadow.style.width = (oElement.offsetWidth + 6) + "px";
  4661. oShadow.style.height = (oElement.offsetHeight + 1) + "px";
  4662. }
  4663. }
  4664. function addShadowVisibleClass() {
  4665. Dom.addClass(this.underlay, "yui-tt-shadow-visible");
  4666. if (UA.ie) {
  4667. this.forceUnderlayRedraw();
  4668. }
  4669. }
  4670. function removeShadowVisibleClass() {
  4671. Dom.removeClass(this.underlay, "yui-tt-shadow-visible");
  4672. }
  4673. function createShadow() {
  4674. var oShadow = this.underlay,
  4675. oElement,
  4676. Module,
  4677. nIE,
  4678. me;
  4679. if (!oShadow) {
  4680. oElement = this.element;
  4681. Module = YAHOO.widget.Module;
  4682. nIE = UA.ie;
  4683. me = this;
  4684. if (!m_oShadowTemplate) {
  4685. m_oShadowTemplate = document.createElement("div");
  4686. m_oShadowTemplate.className = "yui-tt-shadow";
  4687. }
  4688. oShadow = m_oShadowTemplate.cloneNode(false);
  4689. oElement.appendChild(oShadow);
  4690. this.underlay = oShadow;
  4691. // Backward compatibility, even though it's probably
  4692. // intended to be "private", it isn't marked as such in the api docs
  4693. this._shadow = this.underlay;
  4694. addShadowVisibleClass.call(this);
  4695. this.subscribe("beforeShow", addShadowVisibleClass);
  4696. this.subscribe("hide", removeShadowVisibleClass);
  4697. if (bIEQuirks) {
  4698. window.setTimeout(function () {
  4699. sizeShadow.call(me);
  4700. }, 0);
  4701. this.cfg.subscribeToConfigEvent("width", sizeShadow);
  4702. this.cfg.subscribeToConfigEvent("height", sizeShadow);
  4703. this.subscribe("changeContent", sizeShadow);
  4704. Module.textResizeEvent.subscribe(sizeShadow, this, true);
  4705. this.subscribe("destroy", function () {
  4706. Module.textResizeEvent.unsubscribe(sizeShadow, this);
  4707. });
  4708. }
  4709. }
  4710. }
  4711. function onBeforeShow() {
  4712. createShadow.call(this);
  4713. this.unsubscribe("beforeShow", onBeforeShow);
  4714. }
  4715. if (this.cfg.getProperty("visible")) {
  4716. createShadow.call(this);
  4717. } else {
  4718. this.subscribe("beforeShow", onBeforeShow);
  4719. }
  4720. },
  4721. /**
  4722. * Forces the underlay element to be repainted, through the application/removal
  4723. * of a yui-force-redraw class to the underlay element.
  4724. *
  4725. * @method forceUnderlayRedraw
  4726. */
  4727. forceUnderlayRedraw : function() {
  4728. var tt = this;
  4729. Dom.addClass(tt.underlay, "yui-force-redraw");
  4730. setTimeout(function() {Dom.removeClass(tt.underlay, "yui-force-redraw");}, 0);
  4731. },
  4732. /**
  4733. * Removes the Tooltip element from the DOM and sets all child
  4734. * elements to null.
  4735. * @method destroy
  4736. */
  4737. destroy: function () {
  4738. // Remove any existing mouseover/mouseout listeners
  4739. this._removeEventListeners();
  4740. Tooltip.superclass.destroy.call(this);
  4741. },
  4742. /**
  4743. * Returns a string representation of the object.
  4744. * @method toString
  4745. * @return {String} The string representation of the Tooltip
  4746. */
  4747. toString: function () {
  4748. return "Tooltip " + this.id;
  4749. }
  4750. });
  4751. }());
  4752. (function () {
  4753. /**
  4754. * Panel is an implementation of Overlay that behaves like an OS window,
  4755. * with a draggable header and an optional close icon at the top right.
  4756. * @namespace YAHOO.widget
  4757. * @class Panel
  4758. * @extends YAHOO.widget.Overlay
  4759. * @constructor
  4760. * @param {String} el The element ID representing the Panel <em>OR</em>
  4761. * @param {HTMLElement} el The element representing the Panel
  4762. * @param {Object} userConfig The configuration object literal containing
  4763. * the configuration that should be set for this Panel. See configuration
  4764. * documentation for more details.
  4765. */
  4766. YAHOO.widget.Panel = function (el, userConfig) {
  4767. YAHOO.widget.Panel.superclass.constructor.call(this, el, userConfig);
  4768. };
  4769. var _currentModal = null;
  4770. var Lang = YAHOO.lang,
  4771. Util = YAHOO.util,
  4772. Dom = Util.Dom,
  4773. Event = Util.Event,
  4774. CustomEvent = Util.CustomEvent,
  4775. KeyListener = YAHOO.util.KeyListener,
  4776. Config = Util.Config,
  4777. Overlay = YAHOO.widget.Overlay,
  4778. Panel = YAHOO.widget.Panel,
  4779. UA = YAHOO.env.ua,
  4780. bIEQuirks = (UA.ie && (UA.ie <= 6 || document.compatMode == "BackCompat")),
  4781. m_oMaskTemplate,
  4782. m_oUnderlayTemplate,
  4783. m_oCloseIconTemplate,
  4784. /**
  4785. * Constant representing the name of the Panel's events
  4786. * @property EVENT_TYPES
  4787. * @private
  4788. * @final
  4789. * @type Object
  4790. */
  4791. EVENT_TYPES = {
  4792. "SHOW_MASK": "showMask",
  4793. "HIDE_MASK": "hideMask",
  4794. "DRAG": "drag"
  4795. },
  4796. /**
  4797. * Constant representing the Panel's configuration properties
  4798. * @property DEFAULT_CONFIG
  4799. * @private
  4800. * @final
  4801. * @type Object
  4802. */
  4803. DEFAULT_CONFIG = {
  4804. "CLOSE": {
  4805. key: "close",
  4806. value: true,
  4807. validator: Lang.isBoolean,
  4808. supercedes: ["visible"]
  4809. },
  4810. "DRAGGABLE": {
  4811. key: "draggable",
  4812. value: (Util.DD ? true : false),
  4813. validator: Lang.isBoolean,
  4814. supercedes: ["visible"]
  4815. },
  4816. "DRAG_ONLY" : {
  4817. key: "dragonly",
  4818. value: false,
  4819. validator: Lang.isBoolean,
  4820. supercedes: ["draggable"]
  4821. },
  4822. "UNDERLAY": {
  4823. key: "underlay",
  4824. value: "shadow",
  4825. supercedes: ["visible"]
  4826. },
  4827. "MODAL": {
  4828. key: "modal",
  4829. value: false,
  4830. validator: Lang.isBoolean,
  4831. supercedes: ["visible", "zindex"]
  4832. },
  4833. "KEY_LISTENERS": {
  4834. key: "keylisteners",
  4835. suppressEvent: true,
  4836. supercedes: ["visible"]
  4837. },
  4838. "STRINGS" : {
  4839. key: "strings",
  4840. supercedes: ["close"],
  4841. validator: Lang.isObject,
  4842. value: {
  4843. close: "Close"
  4844. }
  4845. }
  4846. };
  4847. /**
  4848. * Constant representing the default CSS class used for a Panel
  4849. * @property YAHOO.widget.Panel.CSS_PANEL
  4850. * @static
  4851. * @final
  4852. * @type String
  4853. */
  4854. Panel.CSS_PANEL = "yui-panel";
  4855. /**
  4856. * Constant representing the default CSS class used for a Panel's
  4857. * wrapping container
  4858. * @property YAHOO.widget.Panel.CSS_PANEL_CONTAINER
  4859. * @static
  4860. * @final
  4861. * @type String
  4862. */
  4863. Panel.CSS_PANEL_CONTAINER = "yui-panel-container";
  4864. /**
  4865. * Constant representing the default set of focusable elements
  4866. * on the pagewhich Modal Panels will prevent access to, when
  4867. * the modal mask is displayed
  4868. *
  4869. * @property YAHOO.widget.Panel.FOCUSABLE
  4870. * @static
  4871. * @type Array
  4872. */
  4873. Panel.FOCUSABLE = [
  4874. "a",
  4875. "button",
  4876. "select",
  4877. "textarea",
  4878. "input",
  4879. "iframe"
  4880. ];
  4881. // Private CustomEvent listeners
  4882. /*
  4883. "beforeRender" event handler that creates an empty header for a Panel
  4884. instance if its "draggable" configuration property is set to "true"
  4885. and no header has been created.
  4886. */
  4887. function createHeader(p_sType, p_aArgs) {
  4888. if (!this.header && this.cfg.getProperty("draggable")) {
  4889. this.setHeader("&#160;");
  4890. }
  4891. }
  4892. /*
  4893. "hide" event handler that sets a Panel instance's "width"
  4894. configuration property back to its original value before
  4895. "setWidthToOffsetWidth" was called.
  4896. */
  4897. function restoreOriginalWidth(p_sType, p_aArgs, p_oObject) {
  4898. var sOriginalWidth = p_oObject[0],
  4899. sNewWidth = p_oObject[1],
  4900. oConfig = this.cfg,
  4901. sCurrentWidth = oConfig.getProperty("width");
  4902. if (sCurrentWidth == sNewWidth) {
  4903. oConfig.setProperty("width", sOriginalWidth);
  4904. }
  4905. this.unsubscribe("hide", restoreOriginalWidth, p_oObject);
  4906. }
  4907. /*
  4908. "beforeShow" event handler that sets a Panel instance's "width"
  4909. configuration property to the value of its root HTML
  4910. elements's offsetWidth
  4911. */
  4912. function setWidthToOffsetWidth(p_sType, p_aArgs) {
  4913. var oConfig,
  4914. sOriginalWidth,
  4915. sNewWidth;
  4916. if (bIEQuirks) {
  4917. oConfig = this.cfg;
  4918. sOriginalWidth = oConfig.getProperty("width");
  4919. if (!sOriginalWidth || sOriginalWidth == "auto") {
  4920. sNewWidth = (this.element.offsetWidth + "px");
  4921. oConfig.setProperty("width", sNewWidth);
  4922. this.subscribe("hide", restoreOriginalWidth,
  4923. [(sOriginalWidth || ""), sNewWidth]);
  4924. }
  4925. }
  4926. }
  4927. YAHOO.extend(Panel, Overlay, {
  4928. /**
  4929. * The Overlay initialization method, which is executed for Overlay and
  4930. * all of its subclasses. This method is automatically called by the
  4931. * constructor, and sets up all DOM references for pre-existing markup,
  4932. * and creates required markup if it is not already present.
  4933. * @method init
  4934. * @param {String} el The element ID representing the Overlay <em>OR</em>
  4935. * @param {HTMLElement} el The element representing the Overlay
  4936. * @param {Object} userConfig The configuration object literal
  4937. * containing the configuration that should be set for this Overlay.
  4938. * See configuration documentation for more details.
  4939. */
  4940. init: function (el, userConfig) {
  4941. /*
  4942. Note that we don't pass the user config in here yet because
  4943. we only want it executed once, at the lowest subclass level
  4944. */
  4945. Panel.superclass.init.call(this, el/*, userConfig*/);
  4946. this.beforeInitEvent.fire(Panel);
  4947. Dom.addClass(this.element, Panel.CSS_PANEL);
  4948. this.buildWrapper();
  4949. if (userConfig) {
  4950. this.cfg.applyConfig(userConfig, true);
  4951. }
  4952. this.subscribe("showMask", this._addFocusHandlers);
  4953. this.subscribe("hideMask", this._removeFocusHandlers);
  4954. this.subscribe("beforeRender", createHeader);
  4955. this.subscribe("render", function() {
  4956. this.setFirstLastFocusable();
  4957. this.subscribe("changeContent", this.setFirstLastFocusable);
  4958. });
  4959. this.subscribe("show", this.focusFirst);
  4960. this.initEvent.fire(Panel);
  4961. },
  4962. /**
  4963. * @method _onElementFocus
  4964. * @private
  4965. *
  4966. * "focus" event handler for a focuable element. Used to automatically
  4967. * blur the element when it receives focus to ensure that a Panel
  4968. * instance's modality is not compromised.
  4969. *
  4970. * @param {Event} e The DOM event object
  4971. */
  4972. _onElementFocus : function(e){
  4973. if(_currentModal === this) {
  4974. var target = Event.getTarget(e),
  4975. doc = document.documentElement,
  4976. insideDoc = (target !== doc && target !== window);
  4977. // mask and documentElement checks added for IE, which focuses on the mask when it's clicked on, and focuses on
  4978. // the documentElement, when the document scrollbars are clicked on
  4979. if (insideDoc && target !== this.element && target !== this.mask && !Dom.isAncestor(this.element, target)) {
  4980. try {
  4981. if (this.firstElement) {
  4982. this.firstElement.focus();
  4983. } else {
  4984. if (this._modalFocus) {
  4985. this._modalFocus.focus();
  4986. } else {
  4987. this.innerElement.focus();
  4988. }
  4989. }
  4990. } catch(err){
  4991. // Just in case we fail to focus
  4992. try {
  4993. if (insideDoc && target !== document.body) {
  4994. target.blur();
  4995. }
  4996. } catch(err2) { }
  4997. }
  4998. }
  4999. }
  5000. },
  5001. /**
  5002. * @method _addFocusHandlers
  5003. * @protected
  5004. *
  5005. * "showMask" event handler that adds a "focus" event handler to all
  5006. * focusable elements in the document to enforce a Panel instance's
  5007. * modality from being compromised.
  5008. *
  5009. * @param p_sType {String} Custom event type
  5010. * @param p_aArgs {Array} Custom event arguments
  5011. */
  5012. _addFocusHandlers: function(p_sType, p_aArgs) {
  5013. if (!this.firstElement) {
  5014. if (UA.webkit || UA.opera) {
  5015. if (!this._modalFocus) {
  5016. this._createHiddenFocusElement();
  5017. }
  5018. } else {
  5019. this.innerElement.tabIndex = 0;
  5020. }
  5021. }
  5022. this.setTabLoop(this.firstElement, this.lastElement);
  5023. Event.onFocus(document.documentElement, this._onElementFocus, this, true);
  5024. _currentModal = this;
  5025. },
  5026. /**
  5027. * Creates a hidden focusable element, used to focus on,
  5028. * to enforce modality for browsers in which focus cannot
  5029. * be applied to the container box.
  5030. *
  5031. * @method _createHiddenFocusElement
  5032. * @private
  5033. */
  5034. _createHiddenFocusElement : function() {
  5035. var e = document.createElement("button");
  5036. e.style.height = "1px";
  5037. e.style.width = "1px";
  5038. e.style.position = "absolute";
  5039. e.style.left = "-10000em";
  5040. e.style.opacity = 0;
  5041. e.tabIndex = -1;
  5042. this.innerElement.appendChild(e);
  5043. this._modalFocus = e;
  5044. },
  5045. /**
  5046. * @method _removeFocusHandlers
  5047. * @protected
  5048. *
  5049. * "hideMask" event handler that removes all "focus" event handlers added
  5050. * by the "addFocusEventHandlers" method.
  5051. *
  5052. * @param p_sType {String} Event type
  5053. * @param p_aArgs {Array} Event Arguments
  5054. */
  5055. _removeFocusHandlers: function(p_sType, p_aArgs) {
  5056. Event.removeFocusListener(document.documentElement, this._onElementFocus, this);
  5057. if (_currentModal == this) {
  5058. _currentModal = null;
  5059. }
  5060. },
  5061. /**
  5062. * Sets focus to the first element in the Panel.
  5063. *
  5064. * @method focusFirst
  5065. */
  5066. focusFirst: function (type, args, obj) {
  5067. var el = this.firstElement;
  5068. if (args && args[1]) {
  5069. Event.stopEvent(args[1]);
  5070. }
  5071. if (el) {
  5072. try {
  5073. el.focus();
  5074. } catch(err) {
  5075. // Ignore
  5076. }
  5077. }
  5078. },
  5079. /**
  5080. * Sets focus to the last element in the Panel.
  5081. *
  5082. * @method focusLast
  5083. */
  5084. focusLast: function (type, args, obj) {
  5085. var el = this.lastElement;
  5086. if (args && args[1]) {
  5087. Event.stopEvent(args[1]);
  5088. }
  5089. if (el) {
  5090. try {
  5091. el.focus();
  5092. } catch(err) {
  5093. // Ignore
  5094. }
  5095. }
  5096. },
  5097. /**
  5098. * Sets up a tab, shift-tab loop between the first and last elements
  5099. * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
  5100. * instance properties, which are reset everytime this method is invoked.
  5101. *
  5102. * @method setTabLoop
  5103. * @param {HTMLElement} firstElement
  5104. * @param {HTMLElement} lastElement
  5105. *
  5106. */
  5107. setTabLoop : function(firstElement, lastElement) {
  5108. var backTab = this.preventBackTab, tab = this.preventTabOut,
  5109. showEvent = this.showEvent, hideEvent = this.hideEvent;
  5110. if (backTab) {
  5111. backTab.disable();
  5112. showEvent.unsubscribe(backTab.enable, backTab);
  5113. hideEvent.unsubscribe(backTab.disable, backTab);
  5114. backTab = this.preventBackTab = null;
  5115. }
  5116. if (tab) {
  5117. tab.disable();
  5118. showEvent.unsubscribe(tab.enable, tab);
  5119. hideEvent.unsubscribe(tab.disable,tab);
  5120. tab = this.preventTabOut = null;
  5121. }
  5122. if (firstElement) {
  5123. this.preventBackTab = new KeyListener(firstElement,
  5124. {shift:true, keys:9},
  5125. {fn:this.focusLast, scope:this, correctScope:true}
  5126. );
  5127. backTab = this.preventBackTab;
  5128. showEvent.subscribe(backTab.enable, backTab, true);
  5129. hideEvent.subscribe(backTab.disable,backTab, true);
  5130. }
  5131. if (lastElement) {
  5132. this.preventTabOut = new KeyListener(lastElement,
  5133. {shift:false, keys:9},
  5134. {fn:this.focusFirst, scope:this, correctScope:true}
  5135. );
  5136. tab = this.preventTabOut;
  5137. showEvent.subscribe(tab.enable, tab, true);
  5138. hideEvent.subscribe(tab.disable,tab, true);
  5139. }
  5140. },
  5141. /**
  5142. * Returns an array of the currently focusable items which reside within
  5143. * Panel. The set of focusable elements the method looks for are defined
  5144. * in the Panel.FOCUSABLE static property
  5145. *
  5146. * @method getFocusableElements
  5147. * @param {HTMLElement} root element to start from.
  5148. */
  5149. getFocusableElements : function(root) {
  5150. root = root || this.innerElement;
  5151. var focusable = {};
  5152. for (var i = 0; i < Panel.FOCUSABLE.length; i++) {
  5153. focusable[Panel.FOCUSABLE[i]] = true;
  5154. }
  5155. function isFocusable(el) {
  5156. if (el.focus && el.type !== "hidden" && !el.disabled && focusable[el.tagName.toLowerCase()]) {
  5157. return true;
  5158. }
  5159. return false;
  5160. }
  5161. // Not looking by Tag, since we want elements in DOM order
  5162. return Dom.getElementsBy(isFocusable, null, root);
  5163. },
  5164. /**
  5165. * Sets the firstElement and lastElement instance properties
  5166. * to the first and last focusable elements in the Panel.
  5167. *
  5168. * @method setFirstLastFocusable
  5169. */
  5170. setFirstLastFocusable : function() {
  5171. this.firstElement = null;
  5172. this.lastElement = null;
  5173. var elements = this.getFocusableElements();
  5174. this.focusableElements = elements;
  5175. if (elements.length > 0) {
  5176. this.firstElement = elements[0];
  5177. this.lastElement = elements[elements.length - 1];
  5178. }
  5179. if (this.cfg.getProperty("modal")) {
  5180. this.setTabLoop(this.firstElement, this.lastElement);
  5181. }
  5182. },
  5183. /**
  5184. * Initializes the custom events for Module which are fired
  5185. * automatically at appropriate times by the Module class.
  5186. */
  5187. initEvents: function () {
  5188. Panel.superclass.initEvents.call(this);
  5189. var SIGNATURE = CustomEvent.LIST;
  5190. /**
  5191. * CustomEvent fired after the modality mask is shown
  5192. * @event showMaskEvent
  5193. */
  5194. this.showMaskEvent = this.createEvent(EVENT_TYPES.SHOW_MASK);
  5195. this.showMaskEvent.signature = SIGNATURE;
  5196. /**
  5197. * CustomEvent fired after the modality mask is hidden
  5198. * @event hideMaskEvent
  5199. */
  5200. this.hideMaskEvent = this.createEvent(EVENT_TYPES.HIDE_MASK);
  5201. this.hideMaskEvent.signature = SIGNATURE;
  5202. /**
  5203. * CustomEvent when the Panel is dragged
  5204. * @event dragEvent
  5205. */
  5206. this.dragEvent = this.createEvent(EVENT_TYPES.DRAG);
  5207. this.dragEvent.signature = SIGNATURE;
  5208. },
  5209. /**
  5210. * Initializes the class's configurable properties which can be changed
  5211. * using the Panel's Config object (cfg).
  5212. * @method initDefaultConfig
  5213. */
  5214. initDefaultConfig: function () {
  5215. Panel.superclass.initDefaultConfig.call(this);
  5216. // Add panel config properties //
  5217. /**
  5218. * True if the Panel should display a "close" button
  5219. * @config close
  5220. * @type Boolean
  5221. * @default true
  5222. */
  5223. this.cfg.addProperty(DEFAULT_CONFIG.CLOSE.key, {
  5224. handler: this.configClose,
  5225. value: DEFAULT_CONFIG.CLOSE.value,
  5226. validator: DEFAULT_CONFIG.CLOSE.validator,
  5227. supercedes: DEFAULT_CONFIG.CLOSE.supercedes
  5228. });
  5229. /**
  5230. * Boolean specifying if the Panel should be draggable. The default
  5231. * value is "true" if the Drag and Drop utility is included,
  5232. * otherwise it is "false." <strong>PLEASE NOTE:</strong> There is a
  5233. * known issue in IE 6 (Strict Mode and Quirks Mode) and IE 7
  5234. * (Quirks Mode) where Panels that either don't have a value set for
  5235. * their "width" configuration property, or their "width"
  5236. * configuration property is set to "auto" will only be draggable by
  5237. * placing the mouse on the text of the Panel's header element.
  5238. * To fix this bug, draggable Panels missing a value for their
  5239. * "width" configuration property, or whose "width" configuration
  5240. * property is set to "auto" will have it set to the value of
  5241. * their root HTML element's offsetWidth before they are made
  5242. * visible. The calculated width is then removed when the Panel is
  5243. * hidden. <em>This fix is only applied to draggable Panels in IE 6
  5244. * (Strict Mode and Quirks Mode) and IE 7 (Quirks Mode)</em>. For
  5245. * more information on this issue see:
  5246. * YUILibrary bugs #1726972 and #1589210.
  5247. * @config draggable
  5248. * @type Boolean
  5249. * @default true
  5250. */
  5251. this.cfg.addProperty(DEFAULT_CONFIG.DRAGGABLE.key, {
  5252. handler: this.configDraggable,
  5253. value: (Util.DD) ? true : false,
  5254. validator: DEFAULT_CONFIG.DRAGGABLE.validator,
  5255. supercedes: DEFAULT_CONFIG.DRAGGABLE.supercedes
  5256. });
  5257. /**
  5258. * Boolean specifying if the draggable Panel should be drag only, not interacting with drop
  5259. * targets on the page.
  5260. * <p>
  5261. * When set to true, draggable Panels will not check to see if they are over drop targets,
  5262. * or fire the DragDrop events required to support drop target interaction (onDragEnter,
  5263. * onDragOver, onDragOut, onDragDrop etc.).
  5264. * If the Panel is not designed to be dropped on any target elements on the page, then this
  5265. * flag can be set to true to improve performance.
  5266. * </p>
  5267. * <p>
  5268. * When set to false, all drop target related events will be fired.
  5269. * </p>
  5270. * <p>
  5271. * The property is set to false by default to maintain backwards compatibility but should be
  5272. * set to true if drop target interaction is not required for the Panel, to improve performance.</p>
  5273. *
  5274. * @config dragOnly
  5275. * @type Boolean
  5276. * @default false
  5277. */
  5278. this.cfg.addProperty(DEFAULT_CONFIG.DRAG_ONLY.key, {
  5279. value: DEFAULT_CONFIG.DRAG_ONLY.value,
  5280. validator: DEFAULT_CONFIG.DRAG_ONLY.validator,
  5281. supercedes: DEFAULT_CONFIG.DRAG_ONLY.supercedes
  5282. });
  5283. /**
  5284. * Sets the type of underlay to display for the Panel. Valid values
  5285. * are "shadow," "matte," and "none". <strong>PLEASE NOTE:</strong>
  5286. * The creation of the underlay element is deferred until the Panel
  5287. * is initially made visible. For Gecko-based browsers on Mac
  5288. * OS X the underlay elment is always created as it is used as a
  5289. * shim to prevent Aqua scrollbars below a Panel instance from poking
  5290. * through it (See YUILibrary bug #1723530).
  5291. * @config underlay
  5292. * @type String
  5293. * @default shadow
  5294. */
  5295. this.cfg.addProperty(DEFAULT_CONFIG.UNDERLAY.key, {
  5296. handler: this.configUnderlay,
  5297. value: DEFAULT_CONFIG.UNDERLAY.value,
  5298. supercedes: DEFAULT_CONFIG.UNDERLAY.supercedes
  5299. });
  5300. /**
  5301. * True if the Panel should be displayed in a modal fashion,
  5302. * automatically creating a transparent mask over the document that
  5303. * will not be removed until the Panel is dismissed.
  5304. * @config modal
  5305. * @type Boolean
  5306. * @default false
  5307. */
  5308. this.cfg.addProperty(DEFAULT_CONFIG.MODAL.key, {
  5309. handler: this.configModal,
  5310. value: DEFAULT_CONFIG.MODAL.value,
  5311. validator: DEFAULT_CONFIG.MODAL.validator,
  5312. supercedes: DEFAULT_CONFIG.MODAL.supercedes
  5313. });
  5314. /**
  5315. * A KeyListener (or array of KeyListeners) that will be enabled
  5316. * when the Panel is shown, and disabled when the Panel is hidden.
  5317. * @config keylisteners
  5318. * @type YAHOO.util.KeyListener[]
  5319. * @default null
  5320. */
  5321. this.cfg.addProperty(DEFAULT_CONFIG.KEY_LISTENERS.key, {
  5322. handler: this.configKeyListeners,
  5323. suppressEvent: DEFAULT_CONFIG.KEY_LISTENERS.suppressEvent,
  5324. supercedes: DEFAULT_CONFIG.KEY_LISTENERS.supercedes
  5325. });
  5326. /**
  5327. * UI Strings used by the Panel
  5328. *
  5329. * @config strings
  5330. * @type Object
  5331. * @default An object literal with the properties shown below:
  5332. * <dl>
  5333. * <dt>close</dt><dd><em>String</em> : The string to use for the close icon. Defaults to "Close".</dd>
  5334. * </dl>
  5335. */
  5336. this.cfg.addProperty(DEFAULT_CONFIG.STRINGS.key, {
  5337. value:DEFAULT_CONFIG.STRINGS.value,
  5338. handler:this.configStrings,
  5339. validator:DEFAULT_CONFIG.STRINGS.validator,
  5340. supercedes:DEFAULT_CONFIG.STRINGS.supercedes
  5341. });
  5342. },
  5343. // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
  5344. /**
  5345. * The default event handler fired when the "close" property is changed.
  5346. * The method controls the appending or hiding of the close icon at the
  5347. * top right of the Panel.
  5348. * @method configClose
  5349. * @param {String} type The CustomEvent type (usually the property name)
  5350. * @param {Object[]} args The CustomEvent arguments. For configuration
  5351. * handlers, args[0] will equal the newly applied value for the property.
  5352. * @param {Object} obj The scope object. For configuration handlers,
  5353. * this will usually equal the owner.
  5354. */
  5355. configClose: function (type, args, obj) {
  5356. var val = args[0],
  5357. oClose = this.close,
  5358. strings = this.cfg.getProperty("strings");
  5359. if (val) {
  5360. if (!oClose) {
  5361. if (!m_oCloseIconTemplate) {
  5362. m_oCloseIconTemplate = document.createElement("a");
  5363. m_oCloseIconTemplate.className = "container-close";
  5364. m_oCloseIconTemplate.href = "#";
  5365. }
  5366. oClose = m_oCloseIconTemplate.cloneNode(true);
  5367. this.innerElement.appendChild(oClose);
  5368. oClose.innerHTML = (strings && strings.close) ? strings.close : "&#160;";
  5369. Event.on(oClose, "click", this._doClose, this, true);
  5370. this.close = oClose;
  5371. } else {
  5372. oClose.style.display = "block";
  5373. }
  5374. } else {
  5375. if (oClose) {
  5376. oClose.style.display = "none";
  5377. }
  5378. }
  5379. },
  5380. /**
  5381. * Event handler for the close icon
  5382. *
  5383. * @method _doClose
  5384. * @protected
  5385. *
  5386. * @param {DOMEvent} e
  5387. */
  5388. _doClose : function (e) {
  5389. Event.preventDefault(e);
  5390. this.hide();
  5391. },
  5392. /**
  5393. * The default event handler fired when the "draggable" property
  5394. * is changed.
  5395. * @method configDraggable
  5396. * @param {String} type The CustomEvent type (usually the property name)
  5397. * @param {Object[]} args The CustomEvent arguments. For configuration
  5398. * handlers, args[0] will equal the newly applied value for the property.
  5399. * @param {Object} obj The scope object. For configuration handlers,
  5400. * this will usually equal the owner.
  5401. */
  5402. configDraggable: function (type, args, obj) {
  5403. var val = args[0];
  5404. if (val) {
  5405. if (!Util.DD) {
  5406. YAHOO.log("DD dependency not met.", "error");
  5407. this.cfg.setProperty("draggable", false);
  5408. return;
  5409. }
  5410. if (this.header) {
  5411. Dom.setStyle(this.header, "cursor", "move");
  5412. this.registerDragDrop();
  5413. }
  5414. this.subscribe("beforeShow", setWidthToOffsetWidth);
  5415. } else {
  5416. if (this.dd) {
  5417. this.dd.unreg();
  5418. }
  5419. if (this.header) {
  5420. Dom.setStyle(this.header,"cursor","auto");
  5421. }
  5422. this.unsubscribe("beforeShow", setWidthToOffsetWidth);
  5423. }
  5424. },
  5425. /**
  5426. * The default event handler fired when the "underlay" property
  5427. * is changed.
  5428. * @method configUnderlay
  5429. * @param {String} type The CustomEvent type (usually the property name)
  5430. * @param {Object[]} args The CustomEvent arguments. For configuration
  5431. * handlers, args[0] will equal the newly applied value for the property.
  5432. * @param {Object} obj The scope object. For configuration handlers,
  5433. * this will usually equal the owner.
  5434. */
  5435. configUnderlay: function (type, args, obj) {
  5436. var bMacGecko = (this.platform == "mac" && UA.gecko),
  5437. sUnderlay = args[0].toLowerCase(),
  5438. oUnderlay = this.underlay,
  5439. oElement = this.element;
  5440. function createUnderlay() {
  5441. var bNew = false;
  5442. if (!oUnderlay) { // create if not already in DOM
  5443. if (!m_oUnderlayTemplate) {
  5444. m_oUnderlayTemplate = document.createElement("div");
  5445. m_oUnderlayTemplate.className = "underlay";
  5446. }
  5447. oUnderlay = m_oUnderlayTemplate.cloneNode(false);
  5448. this.element.appendChild(oUnderlay);
  5449. this.underlay = oUnderlay;
  5450. if (bIEQuirks) {
  5451. this.sizeUnderlay();
  5452. this.cfg.subscribeToConfigEvent("width", this.sizeUnderlay);
  5453. this.cfg.subscribeToConfigEvent("height", this.sizeUnderlay);
  5454. this.changeContentEvent.subscribe(this.sizeUnderlay);
  5455. YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay, this, true);
  5456. }
  5457. if (UA.webkit && UA.webkit < 420) {
  5458. this.changeContentEvent.subscribe(this.forceUnderlayRedraw);
  5459. }
  5460. bNew = true;
  5461. }
  5462. }
  5463. function onBeforeShow() {
  5464. var bNew = createUnderlay.call(this);
  5465. if (!bNew && bIEQuirks) {
  5466. this.sizeUnderlay();
  5467. }
  5468. this._underlayDeferred = false;
  5469. this.beforeShowEvent.unsubscribe(onBeforeShow);
  5470. }
  5471. function destroyUnderlay() {
  5472. if (this._underlayDeferred) {
  5473. this.beforeShowEvent.unsubscribe(onBeforeShow);
  5474. this._underlayDeferred = false;
  5475. }
  5476. if (oUnderlay) {
  5477. this.cfg.unsubscribeFromConfigEvent("width", this.sizeUnderlay);
  5478. this.cfg.unsubscribeFromConfigEvent("height",this.sizeUnderlay);
  5479. this.changeContentEvent.unsubscribe(this.sizeUnderlay);
  5480. this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);
  5481. YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay, this, true);
  5482. this.element.removeChild(oUnderlay);
  5483. this.underlay = null;
  5484. }
  5485. }
  5486. switch (sUnderlay) {
  5487. case "shadow":
  5488. Dom.removeClass(oElement, "matte");
  5489. Dom.addClass(oElement, "shadow");
  5490. break;
  5491. case "matte":
  5492. if (!bMacGecko) {
  5493. destroyUnderlay.call(this);
  5494. }
  5495. Dom.removeClass(oElement, "shadow");
  5496. Dom.addClass(oElement, "matte");
  5497. break;
  5498. default:
  5499. if (!bMacGecko) {
  5500. destroyUnderlay.call(this);
  5501. }
  5502. Dom.removeClass(oElement, "shadow");
  5503. Dom.removeClass(oElement, "matte");
  5504. break;
  5505. }
  5506. if ((sUnderlay == "shadow") || (bMacGecko && !oUnderlay)) {
  5507. if (this.cfg.getProperty("visible")) {
  5508. var bNew = createUnderlay.call(this);
  5509. if (!bNew && bIEQuirks) {
  5510. this.sizeUnderlay();
  5511. }
  5512. } else {
  5513. if (!this._underlayDeferred) {
  5514. this.beforeShowEvent.subscribe(onBeforeShow);
  5515. this._underlayDeferred = true;
  5516. }
  5517. }
  5518. }
  5519. },
  5520. /**
  5521. * The default event handler fired when the "modal" property is
  5522. * changed. This handler subscribes or unsubscribes to the show and hide
  5523. * events to handle the display or hide of the modality mask.
  5524. * @method configModal
  5525. * @param {String} type The CustomEvent type (usually the property name)
  5526. * @param {Object[]} args The CustomEvent arguments. For configuration
  5527. * handlers, args[0] will equal the newly applied value for the property.
  5528. * @param {Object} obj The scope object. For configuration handlers,
  5529. * this will usually equal the owner.
  5530. */
  5531. configModal: function (type, args, obj) {
  5532. var modal = args[0];
  5533. if (modal) {
  5534. if (!this._hasModalityEventListeners) {
  5535. this.subscribe("beforeShow", this.buildMask);
  5536. this.subscribe("beforeShow", this.bringToTop);
  5537. this.subscribe("beforeShow", this.showMask);
  5538. this.subscribe("hide", this.hideMask);
  5539. Overlay.windowResizeEvent.subscribe(this.sizeMask,
  5540. this, true);
  5541. this._hasModalityEventListeners = true;
  5542. }
  5543. } else {
  5544. if (this._hasModalityEventListeners) {
  5545. if (this.cfg.getProperty("visible")) {
  5546. this.hideMask();
  5547. this.removeMask();
  5548. }
  5549. this.unsubscribe("beforeShow", this.buildMask);
  5550. this.unsubscribe("beforeShow", this.bringToTop);
  5551. this.unsubscribe("beforeShow", this.showMask);
  5552. this.unsubscribe("hide", this.hideMask);
  5553. Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
  5554. this._hasModalityEventListeners = false;
  5555. }
  5556. }
  5557. },
  5558. /**
  5559. * Removes the modality mask.
  5560. * @method removeMask
  5561. */
  5562. removeMask: function () {
  5563. var oMask = this.mask,
  5564. oParentNode;
  5565. if (oMask) {
  5566. /*
  5567. Hide the mask before destroying it to ensure that DOM
  5568. event handlers on focusable elements get removed.
  5569. */
  5570. this.hideMask();
  5571. oParentNode = oMask.parentNode;
  5572. if (oParentNode) {
  5573. oParentNode.removeChild(oMask);
  5574. }
  5575. this.mask = null;
  5576. }
  5577. },
  5578. /**
  5579. * The default event handler fired when the "keylisteners" property
  5580. * is changed.
  5581. * @method configKeyListeners
  5582. * @param {String} type The CustomEvent type (usually the property name)
  5583. * @param {Object[]} args The CustomEvent arguments. For configuration
  5584. * handlers, args[0] will equal the newly applied value for the property.
  5585. * @param {Object} obj The scope object. For configuration handlers,
  5586. * this will usually equal the owner.
  5587. */
  5588. configKeyListeners: function (type, args, obj) {
  5589. var listeners = args[0],
  5590. listener,
  5591. nListeners,
  5592. i;
  5593. if (listeners) {
  5594. if (listeners instanceof Array) {
  5595. nListeners = listeners.length;
  5596. for (i = 0; i < nListeners; i++) {
  5597. listener = listeners[i];
  5598. if (!Config.alreadySubscribed(this.showEvent,
  5599. listener.enable, listener)) {
  5600. this.showEvent.subscribe(listener.enable,
  5601. listener, true);
  5602. }
  5603. if (!Config.alreadySubscribed(this.hideEvent,
  5604. listener.disable, listener)) {
  5605. this.hideEvent.subscribe(listener.disable,
  5606. listener, true);
  5607. this.destroyEvent.subscribe(listener.disable,
  5608. listener, true);
  5609. }
  5610. }
  5611. } else {
  5612. if (!Config.alreadySubscribed(this.showEvent,
  5613. listeners.enable, listeners)) {
  5614. this.showEvent.subscribe(listeners.enable,
  5615. listeners, true);
  5616. }
  5617. if (!Config.alreadySubscribed(this.hideEvent,
  5618. listeners.disable, listeners)) {
  5619. this.hideEvent.subscribe(listeners.disable,
  5620. listeners, true);
  5621. this.destroyEvent.subscribe(listeners.disable,
  5622. listeners, true);
  5623. }
  5624. }
  5625. }
  5626. },
  5627. /**
  5628. * The default handler for the "strings" property
  5629. * @method configStrings
  5630. */
  5631. configStrings : function(type, args, obj) {
  5632. var val = Lang.merge(DEFAULT_CONFIG.STRINGS.value, args[0]);
  5633. this.cfg.setProperty(DEFAULT_CONFIG.STRINGS.key, val, true);
  5634. },
  5635. /**
  5636. * The default event handler fired when the "height" property is changed.
  5637. * @method configHeight
  5638. * @param {String} type The CustomEvent type (usually the property name)
  5639. * @param {Object[]} args The CustomEvent arguments. For configuration
  5640. * handlers, args[0] will equal the newly applied value for the property.
  5641. * @param {Object} obj The scope object. For configuration handlers,
  5642. * this will usually equal the owner.
  5643. */
  5644. configHeight: function (type, args, obj) {
  5645. var height = args[0],
  5646. el = this.innerElement;
  5647. Dom.setStyle(el, "height", height);
  5648. this.cfg.refireEvent("iframe");
  5649. },
  5650. /**
  5651. * The default custom event handler executed when the Panel's height is changed,
  5652. * if the autofillheight property has been set.
  5653. *
  5654. * @method _autoFillOnHeightChange
  5655. * @protected
  5656. * @param {String} type The event type
  5657. * @param {Array} args The array of arguments passed to event subscribers
  5658. * @param {HTMLElement} el The header, body or footer element which is to be resized to fill
  5659. * out the containers height
  5660. */
  5661. _autoFillOnHeightChange : function(type, args, el) {
  5662. Panel.superclass._autoFillOnHeightChange.apply(this, arguments);
  5663. if (bIEQuirks) {
  5664. var panel = this;
  5665. setTimeout(function() {
  5666. panel.sizeUnderlay();
  5667. },0);
  5668. }
  5669. },
  5670. /**
  5671. * The default event handler fired when the "width" property is changed.
  5672. * @method configWidth
  5673. * @param {String} type The CustomEvent type (usually the property name)
  5674. * @param {Object[]} args The CustomEvent arguments. For configuration
  5675. * handlers, args[0] will equal the newly applied value for the property.
  5676. * @param {Object} obj The scope object. For configuration handlers,
  5677. * this will usually equal the owner.
  5678. */
  5679. configWidth: function (type, args, obj) {
  5680. var width = args[0],
  5681. el = this.innerElement;
  5682. Dom.setStyle(el, "width", width);
  5683. this.cfg.refireEvent("iframe");
  5684. },
  5685. /**
  5686. * The default event handler fired when the "zIndex" property is changed.
  5687. * @method configzIndex
  5688. * @param {String} type The CustomEvent type (usually the property name)
  5689. * @param {Object[]} args The CustomEvent arguments. For configuration
  5690. * handlers, args[0] will equal the newly applied value for the property.
  5691. * @param {Object} obj The scope object. For configuration handlers,
  5692. * this will usually equal the owner.
  5693. */
  5694. configzIndex: function (type, args, obj) {
  5695. Panel.superclass.configzIndex.call(this, type, args, obj);
  5696. if (this.mask || this.cfg.getProperty("modal") === true) {
  5697. var panelZ = Dom.getStyle(this.element, "zIndex");
  5698. if (!panelZ || isNaN(panelZ)) {
  5699. panelZ = 0;
  5700. }
  5701. if (panelZ === 0) {
  5702. // Recursive call to configzindex (which should be stopped
  5703. // from going further because panelZ should no longer === 0)
  5704. this.cfg.setProperty("zIndex", 1);
  5705. } else {
  5706. this.stackMask();
  5707. }
  5708. }
  5709. },
  5710. // END BUILT-IN PROPERTY EVENT HANDLERS //
  5711. /**
  5712. * Builds the wrapping container around the Panel that is used for
  5713. * positioning the shadow and matte underlays. The container element is
  5714. * assigned to a local instance variable called container, and the
  5715. * element is reinserted inside of it.
  5716. * @method buildWrapper
  5717. */
  5718. buildWrapper: function () {
  5719. var elementParent = this.element.parentNode,
  5720. originalElement = this.element,
  5721. wrapper = document.createElement("div");
  5722. wrapper.className = Panel.CSS_PANEL_CONTAINER;
  5723. wrapper.id = originalElement.id + "_c";
  5724. if (elementParent) {
  5725. elementParent.insertBefore(wrapper, originalElement);
  5726. }
  5727. wrapper.appendChild(originalElement);
  5728. this.element = wrapper;
  5729. this.innerElement = originalElement;
  5730. Dom.setStyle(this.innerElement, "visibility", "inherit");
  5731. },
  5732. /**
  5733. * Adjusts the size of the shadow based on the size of the element.
  5734. * @method sizeUnderlay
  5735. */
  5736. sizeUnderlay: function () {
  5737. var oUnderlay = this.underlay,
  5738. oElement;
  5739. if (oUnderlay) {
  5740. oElement = this.element;
  5741. oUnderlay.style.width = oElement.offsetWidth + "px";
  5742. oUnderlay.style.height = oElement.offsetHeight + "px";
  5743. }
  5744. },
  5745. /**
  5746. * Registers the Panel's header for drag & drop capability.
  5747. * @method registerDragDrop
  5748. */
  5749. registerDragDrop: function () {
  5750. var me = this;
  5751. if (this.header) {
  5752. if (!Util.DD) {
  5753. YAHOO.log("DD dependency not met.", "error");
  5754. return;
  5755. }
  5756. var bDragOnly = (this.cfg.getProperty("dragonly") === true);
  5757. /**
  5758. * The YAHOO.util.DD instance, used to implement the draggable header for the panel if draggable is enabled
  5759. *
  5760. * @property dd
  5761. * @type YAHOO.util.DD
  5762. */
  5763. this.dd = new Util.DD(this.element.id, this.id, {dragOnly: bDragOnly});
  5764. if (!this.header.id) {
  5765. this.header.id = this.id + "_h";
  5766. }
  5767. this.dd.startDrag = function () {
  5768. var offsetHeight,
  5769. offsetWidth,
  5770. viewPortWidth,
  5771. viewPortHeight,
  5772. scrollX,
  5773. scrollY;
  5774. if (YAHOO.env.ua.ie == 6) {
  5775. Dom.addClass(me.element,"drag");
  5776. }
  5777. if (me.cfg.getProperty("constraintoviewport")) {
  5778. var nViewportOffset = Overlay.VIEWPORT_OFFSET;
  5779. offsetHeight = me.element.offsetHeight;
  5780. offsetWidth = me.element.offsetWidth;
  5781. viewPortWidth = Dom.getViewportWidth();
  5782. viewPortHeight = Dom.getViewportHeight();
  5783. scrollX = Dom.getDocumentScrollLeft();
  5784. scrollY = Dom.getDocumentScrollTop();
  5785. if (offsetHeight + nViewportOffset < viewPortHeight) {
  5786. this.minY = scrollY + nViewportOffset;
  5787. this.maxY = scrollY + viewPortHeight - offsetHeight - nViewportOffset;
  5788. } else {
  5789. this.minY = scrollY + nViewportOffset;
  5790. this.maxY = scrollY + nViewportOffset;
  5791. }
  5792. if (offsetWidth + nViewportOffset < viewPortWidth) {
  5793. this.minX = scrollX + nViewportOffset;
  5794. this.maxX = scrollX + viewPortWidth - offsetWidth - nViewportOffset;
  5795. } else {
  5796. this.minX = scrollX + nViewportOffset;
  5797. this.maxX = scrollX + nViewportOffset;
  5798. }
  5799. this.constrainX = true;
  5800. this.constrainY = true;
  5801. } else {
  5802. this.constrainX = false;
  5803. this.constrainY = false;
  5804. }
  5805. me.dragEvent.fire("startDrag", arguments);
  5806. };
  5807. this.dd.onDrag = function () {
  5808. me.syncPosition();
  5809. me.cfg.refireEvent("iframe");
  5810. if (this.platform == "mac" && YAHOO.env.ua.gecko) {
  5811. this.showMacGeckoScrollbars();
  5812. }
  5813. me.dragEvent.fire("onDrag", arguments);
  5814. };
  5815. this.dd.endDrag = function () {
  5816. if (YAHOO.env.ua.ie == 6) {
  5817. Dom.removeClass(me.element,"drag");
  5818. }
  5819. me.dragEvent.fire("endDrag", arguments);
  5820. me.moveEvent.fire(me.cfg.getProperty("xy"));
  5821. };
  5822. this.dd.setHandleElId(this.header.id);
  5823. this.dd.addInvalidHandleType("INPUT");
  5824. this.dd.addInvalidHandleType("SELECT");
  5825. this.dd.addInvalidHandleType("TEXTAREA");
  5826. }
  5827. },
  5828. /**
  5829. * Builds the mask that is laid over the document when the Panel is
  5830. * configured to be modal.
  5831. * @method buildMask
  5832. */
  5833. buildMask: function () {
  5834. var oMask = this.mask;
  5835. if (!oMask) {
  5836. if (!m_oMaskTemplate) {
  5837. m_oMaskTemplate = document.createElement("div");
  5838. m_oMaskTemplate.className = "mask";
  5839. m_oMaskTemplate.innerHTML = "&#160;";
  5840. }
  5841. oMask = m_oMaskTemplate.cloneNode(true);
  5842. oMask.id = this.id + "_mask";
  5843. document.body.insertBefore(oMask, document.body.firstChild);
  5844. this.mask = oMask;
  5845. if (YAHOO.env.ua.gecko && this.platform == "mac") {
  5846. Dom.addClass(this.mask, "block-scrollbars");
  5847. }
  5848. // Stack mask based on the element zindex
  5849. this.stackMask();
  5850. }
  5851. },
  5852. /**
  5853. * Hides the modality mask.
  5854. * @method hideMask
  5855. */
  5856. hideMask: function () {
  5857. if (this.cfg.getProperty("modal") && this.mask) {
  5858. this.mask.style.display = "none";
  5859. Dom.removeClass(document.body, "masked");
  5860. this.hideMaskEvent.fire();
  5861. }
  5862. },
  5863. /**
  5864. * Shows the modality mask.
  5865. * @method showMask
  5866. */
  5867. showMask: function () {
  5868. if (this.cfg.getProperty("modal") && this.mask) {
  5869. Dom.addClass(document.body, "masked");
  5870. this.sizeMask();
  5871. this.mask.style.display = "block";
  5872. this.showMaskEvent.fire();
  5873. }
  5874. },
  5875. /**
  5876. * Sets the size of the modality mask to cover the entire scrollable
  5877. * area of the document
  5878. * @method sizeMask
  5879. */
  5880. sizeMask: function () {
  5881. if (this.mask) {
  5882. // Shrink mask first, so it doesn't affect the document size.
  5883. var mask = this.mask,
  5884. viewWidth = Dom.getViewportWidth(),
  5885. viewHeight = Dom.getViewportHeight();
  5886. if (mask.offsetHeight > viewHeight) {
  5887. mask.style.height = viewHeight + "px";
  5888. }
  5889. if (mask.offsetWidth > viewWidth) {
  5890. mask.style.width = viewWidth + "px";
  5891. }
  5892. // Then size it to the document
  5893. mask.style.height = Dom.getDocumentHeight() + "px";
  5894. mask.style.width = Dom.getDocumentWidth() + "px";
  5895. }
  5896. },
  5897. /**
  5898. * Sets the zindex of the mask, if it exists, based on the zindex of
  5899. * the Panel element. The zindex of the mask is set to be one less
  5900. * than the Panel element's zindex.
  5901. *
  5902. * <p>NOTE: This method will not bump up the zindex of the Panel
  5903. * to ensure that the mask has a non-negative zindex. If you require the
  5904. * mask zindex to be 0 or higher, the zindex of the Panel
  5905. * should be set to a value higher than 0, before this method is called.
  5906. * </p>
  5907. * @method stackMask
  5908. */
  5909. stackMask: function() {
  5910. if (this.mask) {
  5911. var panelZ = Dom.getStyle(this.element, "zIndex");
  5912. if (!YAHOO.lang.isUndefined(panelZ) && !isNaN(panelZ)) {
  5913. Dom.setStyle(this.mask, "zIndex", panelZ - 1);
  5914. }
  5915. }
  5916. },
  5917. /**
  5918. * Renders the Panel by inserting the elements that are not already in
  5919. * the main Panel into their correct places. Optionally appends the
  5920. * Panel to the specified node prior to the render's execution. NOTE:
  5921. * For Panels without existing markup, the appendToNode argument is
  5922. * REQUIRED. If this argument is ommitted and the current element is
  5923. * not present in the document, the function will return false,
  5924. * indicating that the render was a failure.
  5925. * @method render
  5926. * @param {String} appendToNode The element id to which the Module
  5927. * should be appended to prior to rendering <em>OR</em>
  5928. * @param {HTMLElement} appendToNode The element to which the Module
  5929. * should be appended to prior to rendering
  5930. * @return {boolean} Success or failure of the render
  5931. */
  5932. render: function (appendToNode) {
  5933. return Panel.superclass.render.call(this, appendToNode, this.innerElement);
  5934. },
  5935. /**
  5936. * Renders the currently set header into it's proper position under the
  5937. * module element. If the module element is not provided, "this.innerElement"
  5938. * is used.
  5939. *
  5940. * @method _renderHeader
  5941. * @protected
  5942. * @param {HTMLElement} moduleElement Optional. A reference to the module element
  5943. */
  5944. _renderHeader: function(moduleElement){
  5945. moduleElement = moduleElement || this.innerElement;
  5946. Panel.superclass._renderHeader.call(this, moduleElement);
  5947. },
  5948. /**
  5949. * Renders the currently set body into it's proper position under the
  5950. * module element. If the module element is not provided, "this.innerElement"
  5951. * is used.
  5952. *
  5953. * @method _renderBody
  5954. * @protected
  5955. * @param {HTMLElement} moduleElement Optional. A reference to the module element.
  5956. */
  5957. _renderBody: function(moduleElement){
  5958. moduleElement = moduleElement || this.innerElement;
  5959. Panel.superclass._renderBody.call(this, moduleElement);
  5960. },
  5961. /**
  5962. * Renders the currently set footer into it's proper position under the
  5963. * module element. If the module element is not provided, "this.innerElement"
  5964. * is used.
  5965. *
  5966. * @method _renderFooter
  5967. * @protected
  5968. * @param {HTMLElement} moduleElement Optional. A reference to the module element
  5969. */
  5970. _renderFooter: function(moduleElement){
  5971. moduleElement = moduleElement || this.innerElement;
  5972. Panel.superclass._renderFooter.call(this, moduleElement);
  5973. },
  5974. /**
  5975. * Removes the Panel element from the DOM and sets all child elements
  5976. * to null.
  5977. * @method destroy
  5978. */
  5979. destroy: function () {
  5980. Overlay.windowResizeEvent.unsubscribe(this.sizeMask, this);
  5981. this.removeMask();
  5982. if (this.close) {
  5983. Event.purgeElement(this.close);
  5984. }
  5985. Panel.superclass.destroy.call(this);
  5986. },
  5987. /**
  5988. * Forces the underlay element to be repainted through the application/removal
  5989. * of a yui-force-redraw class to the underlay element.
  5990. *
  5991. * @method forceUnderlayRedraw
  5992. */
  5993. forceUnderlayRedraw : function () {
  5994. var u = this.underlay;
  5995. Dom.addClass(u, "yui-force-redraw");
  5996. setTimeout(function(){Dom.removeClass(u, "yui-force-redraw");}, 0);
  5997. },
  5998. /**
  5999. * Returns a String representation of the object.
  6000. * @method toString
  6001. * @return {String} The string representation of the Panel.
  6002. */
  6003. toString: function () {
  6004. return "Panel " + this.id;
  6005. }
  6006. });
  6007. }());
  6008. (function () {
  6009. /**
  6010. * <p>
  6011. * Dialog is an implementation of Panel that can be used to submit form
  6012. * data.
  6013. * </p>
  6014. * <p>
  6015. * Built-in functionality for buttons with event handlers is included.
  6016. * If the optional YUI Button dependancy is included on the page, the buttons
  6017. * created will be instances of YAHOO.widget.Button, otherwise regular HTML buttons
  6018. * will be created.
  6019. * </p>
  6020. * <p>
  6021. * Forms can be processed in 3 ways -- via an asynchronous Connection utility call,
  6022. * a simple form POST or GET, or manually. The YUI Connection utility should be
  6023. * included if you're using the default "async" postmethod, but is not required if
  6024. * you're using any of the other postmethod values.
  6025. * </p>
  6026. * @namespace YAHOO.widget
  6027. * @class Dialog
  6028. * @extends YAHOO.widget.Panel
  6029. * @constructor
  6030. * @param {String} el The element ID representing the Dialog <em>OR</em>
  6031. * @param {HTMLElement} el The element representing the Dialog
  6032. * @param {Object} userConfig The configuration object literal containing
  6033. * the configuration that should be set for this Dialog. See configuration
  6034. * documentation for more details.
  6035. */
  6036. YAHOO.widget.Dialog = function (el, userConfig) {
  6037. YAHOO.widget.Dialog.superclass.constructor.call(this, el, userConfig);
  6038. };
  6039. var Event = YAHOO.util.Event,
  6040. CustomEvent = YAHOO.util.CustomEvent,
  6041. Dom = YAHOO.util.Dom,
  6042. Dialog = YAHOO.widget.Dialog,
  6043. Lang = YAHOO.lang,
  6044. /**
  6045. * Constant representing the name of the Dialog's events
  6046. * @property EVENT_TYPES
  6047. * @private
  6048. * @final
  6049. * @type Object
  6050. */
  6051. EVENT_TYPES = {
  6052. "BEFORE_SUBMIT": "beforeSubmit",
  6053. "SUBMIT": "submit",
  6054. "MANUAL_SUBMIT": "manualSubmit",
  6055. "ASYNC_SUBMIT": "asyncSubmit",
  6056. "FORM_SUBMIT": "formSubmit",
  6057. "CANCEL": "cancel"
  6058. },
  6059. /**
  6060. * Constant representing the Dialog's configuration properties
  6061. * @property DEFAULT_CONFIG
  6062. * @private
  6063. * @final
  6064. * @type Object
  6065. */
  6066. DEFAULT_CONFIG = {
  6067. "POST_METHOD": {
  6068. key: "postmethod",
  6069. value: "async"
  6070. },
  6071. "POST_DATA" : {
  6072. key: "postdata",
  6073. value: null
  6074. },
  6075. "BUTTONS": {
  6076. key: "buttons",
  6077. value: "none",
  6078. supercedes: ["visible"]
  6079. },
  6080. "HIDEAFTERSUBMIT" : {
  6081. key: "hideaftersubmit",
  6082. value: true
  6083. }
  6084. };
  6085. /**
  6086. * Constant representing the default CSS class used for a Dialog
  6087. * @property YAHOO.widget.Dialog.CSS_DIALOG
  6088. * @static
  6089. * @final
  6090. * @type String
  6091. */
  6092. Dialog.CSS_DIALOG = "yui-dialog";
  6093. function removeButtonEventHandlers() {
  6094. var aButtons = this._aButtons,
  6095. nButtons,
  6096. oButton,
  6097. i;
  6098. if (Lang.isArray(aButtons)) {
  6099. nButtons = aButtons.length;
  6100. if (nButtons > 0) {
  6101. i = nButtons - 1;
  6102. do {
  6103. oButton = aButtons[i];
  6104. if (YAHOO.widget.Button && oButton instanceof YAHOO.widget.Button) {
  6105. oButton.destroy();
  6106. }
  6107. else if (oButton.tagName.toUpperCase() == "BUTTON") {
  6108. Event.purgeElement(oButton);
  6109. Event.purgeElement(oButton, false);
  6110. }
  6111. }
  6112. while (i--);
  6113. }
  6114. }
  6115. }
  6116. YAHOO.extend(Dialog, YAHOO.widget.Panel, {
  6117. /**
  6118. * @property form
  6119. * @description Object reference to the Dialog's
  6120. * <code>&#60;form&#62;</code> element.
  6121. * @default null
  6122. * @type <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/
  6123. * level-one-html.html#ID-40002357">HTMLFormElement</a>
  6124. */
  6125. form: null,
  6126. /**
  6127. * Initializes the class's configurable properties which can be changed
  6128. * using the Dialog's Config object (cfg).
  6129. * @method initDefaultConfig
  6130. */
  6131. initDefaultConfig: function () {
  6132. Dialog.superclass.initDefaultConfig.call(this);
  6133. /**
  6134. * The internally maintained callback object for use with the
  6135. * Connection utility. The format of the callback object is
  6136. * similar to Connection Manager's callback object and is
  6137. * simply passed through to Connection Manager when the async
  6138. * request is made.
  6139. * @property callback
  6140. * @type Object
  6141. */
  6142. this.callback = {
  6143. /**
  6144. * The function to execute upon success of the
  6145. * Connection submission (when the form does not
  6146. * contain a file input element).
  6147. *
  6148. * @property callback.success
  6149. * @type Function
  6150. */
  6151. success: null,
  6152. /**
  6153. * The function to execute upon failure of the
  6154. * Connection submission
  6155. * @property callback.failure
  6156. * @type Function
  6157. */
  6158. failure: null,
  6159. /**
  6160. *<p>
  6161. * The function to execute upon success of the
  6162. * Connection submission, when the form contains
  6163. * a file input element.
  6164. * </p>
  6165. * <p>
  6166. * <em>NOTE:</em> Connection manager will not
  6167. * invoke the success or failure handlers for the file
  6168. * upload use case. This will be the only callback
  6169. * handler invoked.
  6170. * </p>
  6171. * <p>
  6172. * For more information, see the <a href="http://developer.yahoo.com/yui/connection/#file">
  6173. * Connection Manager documenation on file uploads</a>.
  6174. * </p>
  6175. * @property callback.upload
  6176. * @type Function
  6177. */
  6178. /**
  6179. * The arbitraty argument or arguments to pass to the Connection
  6180. * callback functions
  6181. * @property callback.argument
  6182. * @type Object
  6183. */
  6184. argument: null
  6185. };
  6186. // Add form dialog config properties //
  6187. /**
  6188. * The method to use for posting the Dialog's form. Possible values
  6189. * are "async", "form", and "manual".
  6190. * @config postmethod
  6191. * @type String
  6192. * @default async
  6193. */
  6194. this.cfg.addProperty(DEFAULT_CONFIG.POST_METHOD.key, {
  6195. handler: this.configPostMethod,
  6196. value: DEFAULT_CONFIG.POST_METHOD.value,
  6197. validator: function (val) {
  6198. if (val != "form" && val != "async" && val != "none" &&
  6199. val != "manual") {
  6200. return false;
  6201. } else {
  6202. return true;
  6203. }
  6204. }
  6205. });
  6206. /**
  6207. * Any additional post data which needs to be sent when using the
  6208. * <a href="#config_postmethod">async</a> postmethod for dialog POST submissions.
  6209. * The format for the post data string is defined by Connection Manager's
  6210. * <a href="YAHOO.util.Connect.html#method_asyncRequest">asyncRequest</a>
  6211. * method.
  6212. * @config postdata
  6213. * @type String
  6214. * @default null
  6215. */
  6216. this.cfg.addProperty(DEFAULT_CONFIG.POST_DATA.key, {
  6217. value: DEFAULT_CONFIG.POST_DATA.value
  6218. });
  6219. /**
  6220. * This property is used to configure whether or not the
  6221. * dialog should be automatically hidden after submit.
  6222. *
  6223. * @config hideaftersubmit
  6224. * @type Boolean
  6225. * @default true
  6226. */
  6227. this.cfg.addProperty(DEFAULT_CONFIG.HIDEAFTERSUBMIT.key, {
  6228. value: DEFAULT_CONFIG.HIDEAFTERSUBMIT.value
  6229. });
  6230. /**
  6231. * Array of object literals, each containing a set of properties
  6232. * defining a button to be appended into the Dialog's footer.
  6233. *
  6234. * <p>Each button object in the buttons array can have three properties:</p>
  6235. * <dl>
  6236. * <dt>text:</dt>
  6237. * <dd>
  6238. * The text that will display on the face of the button. The text can
  6239. * include HTML, as long as it is compliant with HTML Button specifications.
  6240. * </dd>
  6241. * <dt>handler:</dt>
  6242. * <dd>Can be either:
  6243. * <ol>
  6244. * <li>A reference to a function that should fire when the
  6245. * button is clicked. (In this case scope of this function is
  6246. * always its Dialog instance.)</li>
  6247. *
  6248. * <li>An object literal representing the code to be
  6249. * executed when the button is clicked.
  6250. *
  6251. * <p>Format:</p>
  6252. *
  6253. * <p>
  6254. * <code>{
  6255. * <br>
  6256. * <strong>fn:</strong> Function, &#47;&#47;
  6257. * The handler to call when the event fires.
  6258. * <br>
  6259. * <strong>obj:</strong> Object, &#47;&#47;
  6260. * An object to pass back to the handler.
  6261. * <br>
  6262. * <strong>scope:</strong> Object &#47;&#47;
  6263. * The object to use for the scope of the handler.
  6264. * <br>
  6265. * }</code>
  6266. * </p>
  6267. * </li>
  6268. * </ol>
  6269. * </dd>
  6270. * <dt>isDefault:</dt>
  6271. * <dd>
  6272. * An optional boolean value that specifies that a button
  6273. * should be highlighted and focused by default.
  6274. * </dd>
  6275. * </dl>
  6276. *
  6277. * <em>NOTE:</em>If the YUI Button Widget is included on the page,
  6278. * the buttons created will be instances of YAHOO.widget.Button.
  6279. * Otherwise, HTML Buttons (<code>&#60;BUTTON&#62;</code>) will be
  6280. * created.
  6281. *
  6282. * @config buttons
  6283. * @type {Array|String}
  6284. * @default "none"
  6285. */
  6286. this.cfg.addProperty(DEFAULT_CONFIG.BUTTONS.key, {
  6287. handler: this.configButtons,
  6288. value: DEFAULT_CONFIG.BUTTONS.value,
  6289. supercedes : DEFAULT_CONFIG.BUTTONS.supercedes
  6290. });
  6291. },
  6292. /**
  6293. * Initializes the custom events for Dialog which are fired
  6294. * automatically at appropriate times by the Dialog class.
  6295. * @method initEvents
  6296. */
  6297. initEvents: function () {
  6298. Dialog.superclass.initEvents.call(this);
  6299. var SIGNATURE = CustomEvent.LIST;
  6300. /**
  6301. * CustomEvent fired prior to submission
  6302. * @event beforeSubmitEvent
  6303. */
  6304. this.beforeSubmitEvent =
  6305. this.createEvent(EVENT_TYPES.BEFORE_SUBMIT);
  6306. this.beforeSubmitEvent.signature = SIGNATURE;
  6307. /**
  6308. * CustomEvent fired after submission
  6309. * @event submitEvent
  6310. */
  6311. this.submitEvent = this.createEvent(EVENT_TYPES.SUBMIT);
  6312. this.submitEvent.signature = SIGNATURE;
  6313. /**
  6314. * CustomEvent fired for manual submission, before the generic submit event is fired
  6315. * @event manualSubmitEvent
  6316. */
  6317. this.manualSubmitEvent =
  6318. this.createEvent(EVENT_TYPES.MANUAL_SUBMIT);
  6319. this.manualSubmitEvent.signature = SIGNATURE;
  6320. /**
  6321. * CustomEvent fired after asynchronous submission, before the generic submit event is fired
  6322. *
  6323. * @event asyncSubmitEvent
  6324. * @param {Object} conn The connection object, returned by YAHOO.util.Connect.asyncRequest
  6325. */
  6326. this.asyncSubmitEvent = this.createEvent(EVENT_TYPES.ASYNC_SUBMIT);
  6327. this.asyncSubmitEvent.signature = SIGNATURE;
  6328. /**
  6329. * CustomEvent fired after form-based submission, before the generic submit event is fired
  6330. * @event formSubmitEvent
  6331. */
  6332. this.formSubmitEvent = this.createEvent(EVENT_TYPES.FORM_SUBMIT);
  6333. this.formSubmitEvent.signature = SIGNATURE;
  6334. /**
  6335. * CustomEvent fired after cancel
  6336. * @event cancelEvent
  6337. */
  6338. this.cancelEvent = this.createEvent(EVENT_TYPES.CANCEL);
  6339. this.cancelEvent.signature = SIGNATURE;
  6340. },
  6341. /**
  6342. * The Dialog initialization method, which is executed for Dialog and
  6343. * all of its subclasses. This method is automatically called by the
  6344. * constructor, and sets up all DOM references for pre-existing markup,
  6345. * and creates required markup if it is not already present.
  6346. *
  6347. * @method init
  6348. * @param {String} el The element ID representing the Dialog <em>OR</em>
  6349. * @param {HTMLElement} el The element representing the Dialog
  6350. * @param {Object} userConfig The configuration object literal
  6351. * containing the configuration that should be set for this Dialog.
  6352. * See configuration documentation for more details.
  6353. */
  6354. init: function (el, userConfig) {
  6355. /*
  6356. Note that we don't pass the user config in here yet because
  6357. we only want it executed once, at the lowest subclass level
  6358. */
  6359. Dialog.superclass.init.call(this, el/*, userConfig*/);
  6360. this.beforeInitEvent.fire(Dialog);
  6361. Dom.addClass(this.element, Dialog.CSS_DIALOG);
  6362. this.cfg.setProperty("visible", false);
  6363. if (userConfig) {
  6364. this.cfg.applyConfig(userConfig, true);
  6365. }
  6366. this.showEvent.subscribe(this.focusFirst, this, true);
  6367. this.beforeHideEvent.subscribe(this.blurButtons, this, true);
  6368. this.subscribe("changeBody", this.registerForm);
  6369. this.initEvent.fire(Dialog);
  6370. },
  6371. /**
  6372. * Submits the Dialog's form depending on the value of the
  6373. * "postmethod" configuration property. <strong>Please note:
  6374. * </strong> As of version 2.3 this method will automatically handle
  6375. * asyncronous file uploads should the Dialog instance's form contain
  6376. * <code>&#60;input type="file"&#62;</code> elements. If a Dialog
  6377. * instance will be handling asyncronous file uploads, its
  6378. * <code>callback</code> property will need to be setup with a
  6379. * <code>upload</code> handler rather than the standard
  6380. * <code>success</code> and, or <code>failure</code> handlers. For more
  6381. * information, see the <a href="http://developer.yahoo.com/yui/
  6382. * connection/#file">Connection Manager documenation on file uploads</a>.
  6383. * @method doSubmit
  6384. */
  6385. doSubmit: function () {
  6386. var Connect = YAHOO.util.Connect,
  6387. oForm = this.form,
  6388. bUseFileUpload = false,
  6389. bUseSecureFileUpload = false,
  6390. aElements,
  6391. nElements,
  6392. i,
  6393. formAttrs;
  6394. switch (this.cfg.getProperty("postmethod")) {
  6395. case "async":
  6396. aElements = oForm.elements;
  6397. nElements = aElements.length;
  6398. if (nElements > 0) {
  6399. i = nElements - 1;
  6400. do {
  6401. if (aElements[i].type == "file") {
  6402. bUseFileUpload = true;
  6403. break;
  6404. }
  6405. }
  6406. while(i--);
  6407. }
  6408. if (bUseFileUpload && YAHOO.env.ua.ie && this.isSecure) {
  6409. bUseSecureFileUpload = true;
  6410. }
  6411. formAttrs = this._getFormAttributes(oForm);
  6412. Connect.setForm(oForm, bUseFileUpload, bUseSecureFileUpload);
  6413. var postData = this.cfg.getProperty("postdata");
  6414. var c = Connect.asyncRequest(formAttrs.method, formAttrs.action, this.callback, postData);
  6415. this.asyncSubmitEvent.fire(c);
  6416. break;
  6417. case "form":
  6418. oForm.submit();
  6419. this.formSubmitEvent.fire();
  6420. break;
  6421. case "none":
  6422. case "manual":
  6423. this.manualSubmitEvent.fire();
  6424. break;
  6425. }
  6426. },
  6427. /**
  6428. * Retrieves important attributes (currently method and action) from
  6429. * the form element, accounting for any elements which may have the same name
  6430. * as the attributes. Defaults to "POST" and "" for method and action respectively
  6431. * if the attribute cannot be retrieved.
  6432. *
  6433. * @method _getFormAttributes
  6434. * @protected
  6435. * @param {HTMLFormElement} oForm The HTML Form element from which to retrieve the attributes
  6436. * @return {Object} Object literal, with method and action String properties.
  6437. */
  6438. _getFormAttributes : function(oForm){
  6439. var attrs = {
  6440. method : null,
  6441. action : null
  6442. };
  6443. if (oForm) {
  6444. if (oForm.getAttributeNode) {
  6445. var action = oForm.getAttributeNode("action");
  6446. var method = oForm.getAttributeNode("method");
  6447. if (action) {
  6448. attrs.action = action.value;
  6449. }
  6450. if (method) {
  6451. attrs.method = method.value;
  6452. }
  6453. } else {
  6454. attrs.action = oForm.getAttribute("action");
  6455. attrs.method = oForm.getAttribute("method");
  6456. }
  6457. }
  6458. attrs.method = (Lang.isString(attrs.method) ? attrs.method : "POST").toUpperCase();
  6459. attrs.action = Lang.isString(attrs.action) ? attrs.action : "";
  6460. return attrs;
  6461. },
  6462. /**
  6463. * Prepares the Dialog's internal FORM object, creating one if one is
  6464. * not currently present.
  6465. * @method registerForm
  6466. */
  6467. registerForm: function() {
  6468. var form = this.element.getElementsByTagName("form")[0];
  6469. if (this.form) {
  6470. if (this.form == form && Dom.isAncestor(this.element, this.form)) {
  6471. return;
  6472. } else {
  6473. Event.purgeElement(this.form);
  6474. this.form = null;
  6475. }
  6476. }
  6477. if (!form) {
  6478. form = document.createElement("form");
  6479. form.name = "frm_" + this.id;
  6480. this.body.appendChild(form);
  6481. }
  6482. if (form) {
  6483. this.form = form;
  6484. Event.on(form, "submit", this._submitHandler, this, true);
  6485. }
  6486. },
  6487. /**
  6488. * Internal handler for the form submit event
  6489. *
  6490. * @method _submitHandler
  6491. * @protected
  6492. * @param {DOMEvent} e The DOM Event object
  6493. */
  6494. _submitHandler : function(e) {
  6495. Event.stopEvent(e);
  6496. this.submit();
  6497. this.form.blur();
  6498. },
  6499. /**
  6500. * Sets up a tab, shift-tab loop between the first and last elements
  6501. * provided. NOTE: Sets up the preventBackTab and preventTabOut KeyListener
  6502. * instance properties, which are reset everytime this method is invoked.
  6503. *
  6504. * @method setTabLoop
  6505. * @param {HTMLElement} firstElement
  6506. * @param {HTMLElement} lastElement
  6507. *
  6508. */
  6509. setTabLoop : function(firstElement, lastElement) {
  6510. firstElement = firstElement || this.firstButton;
  6511. lastElement = this.lastButton || lastElement;
  6512. Dialog.superclass.setTabLoop.call(this, firstElement, lastElement);
  6513. },
  6514. /**
  6515. * Configures instance properties, pointing to the
  6516. * first and last focusable elements in the Dialog's form.
  6517. *
  6518. * @method setFirstLastFocusable
  6519. */
  6520. setFirstLastFocusable : function() {
  6521. Dialog.superclass.setFirstLastFocusable.call(this);
  6522. var i, l, el, elements = this.focusableElements;
  6523. this.firstFormElement = null;
  6524. this.lastFormElement = null;
  6525. if (this.form && elements && elements.length > 0) {
  6526. l = elements.length;
  6527. for (i = 0; i < l; ++i) {
  6528. el = elements[i];
  6529. if (this.form === el.form) {
  6530. this.firstFormElement = el;
  6531. break;
  6532. }
  6533. }
  6534. for (i = l-1; i >= 0; --i) {
  6535. el = elements[i];
  6536. if (this.form === el.form) {
  6537. this.lastFormElement = el;
  6538. break;
  6539. }
  6540. }
  6541. }
  6542. },
  6543. // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
  6544. /**
  6545. * The default event handler fired when the "close" property is
  6546. * changed. The method controls the appending or hiding of the close
  6547. * icon at the top right of the Dialog.
  6548. * @method configClose
  6549. * @param {String} type The CustomEvent type (usually the property name)
  6550. * @param {Object[]} args The CustomEvent arguments. For
  6551. * configuration handlers, args[0] will equal the newly applied value
  6552. * for the property.
  6553. * @param {Object} obj The scope object. For configuration handlers,
  6554. * this will usually equal the owner.
  6555. */
  6556. configClose: function (type, args, obj) {
  6557. Dialog.superclass.configClose.apply(this, arguments);
  6558. },
  6559. /**
  6560. * Event handler for the close icon
  6561. *
  6562. * @method _doClose
  6563. * @protected
  6564. *
  6565. * @param {DOMEvent} e
  6566. */
  6567. _doClose : function(e) {
  6568. Event.preventDefault(e);
  6569. this.cancel();
  6570. },
  6571. /**
  6572. * The default event handler for the "buttons" configuration property
  6573. * @method configButtons
  6574. * @param {String} type The CustomEvent type (usually the property name)
  6575. * @param {Object[]} args The CustomEvent arguments. For configuration
  6576. * handlers, args[0] will equal the newly applied value for the property.
  6577. * @param {Object} obj The scope object. For configuration handlers,
  6578. * this will usually equal the owner.
  6579. */
  6580. configButtons: function (type, args, obj) {
  6581. var Button = YAHOO.widget.Button,
  6582. aButtons = args[0],
  6583. oInnerElement = this.innerElement,
  6584. oButton,
  6585. oButtonEl,
  6586. oYUIButton,
  6587. nButtons,
  6588. oSpan,
  6589. oFooter,
  6590. i;
  6591. removeButtonEventHandlers.call(this);
  6592. this._aButtons = null;
  6593. if (Lang.isArray(aButtons)) {
  6594. oSpan = document.createElement("span");
  6595. oSpan.className = "button-group";
  6596. nButtons = aButtons.length;
  6597. this._aButtons = [];
  6598. this.defaultHtmlButton = null;
  6599. for (i = 0; i < nButtons; i++) {
  6600. oButton = aButtons[i];
  6601. if (Button) {
  6602. oYUIButton = new Button({ label: oButton.text});
  6603. oYUIButton.appendTo(oSpan);
  6604. oButtonEl = oYUIButton.get("element");
  6605. if (oButton.isDefault) {
  6606. oYUIButton.addClass("default");
  6607. this.defaultHtmlButton = oButtonEl;
  6608. }
  6609. if (Lang.isFunction(oButton.handler)) {
  6610. oYUIButton.set("onclick", {
  6611. fn: oButton.handler,
  6612. obj: this,
  6613. scope: this
  6614. });
  6615. } else if (Lang.isObject(oButton.handler) && Lang.isFunction(oButton.handler.fn)) {
  6616. oYUIButton.set("onclick", {
  6617. fn: oButton.handler.fn,
  6618. obj: ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
  6619. scope: (oButton.handler.scope || this)
  6620. });
  6621. }
  6622. this._aButtons[this._aButtons.length] = oYUIButton;
  6623. } else {
  6624. oButtonEl = document.createElement("button");
  6625. oButtonEl.setAttribute("type", "button");
  6626. if (oButton.isDefault) {
  6627. oButtonEl.className = "default";
  6628. this.defaultHtmlButton = oButtonEl;
  6629. }
  6630. oButtonEl.innerHTML = oButton.text;
  6631. if (Lang.isFunction(oButton.handler)) {
  6632. Event.on(oButtonEl, "click", oButton.handler, this, true);
  6633. } else if (Lang.isObject(oButton.handler) &&
  6634. Lang.isFunction(oButton.handler.fn)) {
  6635. Event.on(oButtonEl, "click",
  6636. oButton.handler.fn,
  6637. ((!Lang.isUndefined(oButton.handler.obj)) ? oButton.handler.obj : this),
  6638. (oButton.handler.scope || this));
  6639. }
  6640. oSpan.appendChild(oButtonEl);
  6641. this._aButtons[this._aButtons.length] = oButtonEl;
  6642. }
  6643. oButton.htmlButton = oButtonEl;
  6644. if (i === 0) {
  6645. this.firstButton = oButtonEl;
  6646. }
  6647. if (i == (nButtons - 1)) {
  6648. this.lastButton = oButtonEl;
  6649. }
  6650. }
  6651. this.setFooter(oSpan);
  6652. oFooter = this.footer;
  6653. if (Dom.inDocument(this.element) && !Dom.isAncestor(oInnerElement, oFooter)) {
  6654. oInnerElement.appendChild(oFooter);
  6655. }
  6656. this.buttonSpan = oSpan;
  6657. } else { // Do cleanup
  6658. oSpan = this.buttonSpan;
  6659. oFooter = this.footer;
  6660. if (oSpan && oFooter) {
  6661. oFooter.removeChild(oSpan);
  6662. this.buttonSpan = null;
  6663. this.firstButton = null;
  6664. this.lastButton = null;
  6665. this.defaultHtmlButton = null;
  6666. }
  6667. }
  6668. this.changeContentEvent.fire();
  6669. },
  6670. /**
  6671. * @method getButtons
  6672. * @description Returns an array containing each of the Dialog's
  6673. * buttons, by default an array of HTML <code>&#60;BUTTON&#62;</code>
  6674. * elements. If the Dialog's buttons were created using the
  6675. * YAHOO.widget.Button class (via the inclusion of the optional Button
  6676. * dependancy on the page), an array of YAHOO.widget.Button instances
  6677. * is returned.
  6678. * @return {Array}
  6679. */
  6680. getButtons: function () {
  6681. return this._aButtons || null;
  6682. },
  6683. /**
  6684. * <p>
  6685. * Sets focus to the first focusable element in the Dialog's form if found,
  6686. * else, the default button if found, else the first button defined via the
  6687. * "buttons" configuration property.
  6688. * </p>
  6689. * <p>
  6690. * This method is invoked when the Dialog is made visible.
  6691. * </p>
  6692. * @method focusFirst
  6693. */
  6694. focusFirst: function (type, args, obj) {
  6695. var el = this.firstFormElement;
  6696. if (args && args[1]) {
  6697. Event.stopEvent(args[1]);
  6698. }
  6699. if (el) {
  6700. try {
  6701. el.focus();
  6702. } catch(oException) {
  6703. // Ignore
  6704. }
  6705. } else {
  6706. if (this.defaultHtmlButton) {
  6707. this.focusDefaultButton();
  6708. } else {
  6709. this.focusFirstButton();
  6710. }
  6711. }
  6712. },
  6713. /**
  6714. * Sets focus to the last element in the Dialog's form or the last
  6715. * button defined via the "buttons" configuration property.
  6716. * @method focusLast
  6717. */
  6718. focusLast: function (type, args, obj) {
  6719. var aButtons = this.cfg.getProperty("buttons"),
  6720. el = this.lastFormElement;
  6721. if (args && args[1]) {
  6722. Event.stopEvent(args[1]);
  6723. }
  6724. if (aButtons && Lang.isArray(aButtons)) {
  6725. this.focusLastButton();
  6726. } else {
  6727. if (el) {
  6728. try {
  6729. el.focus();
  6730. } catch(oException) {
  6731. // Ignore
  6732. }
  6733. }
  6734. }
  6735. },
  6736. /**
  6737. * Helper method to normalize button references. It either returns the
  6738. * YUI Button instance for the given element if found,
  6739. * or the passes back the HTMLElement reference if a corresponding YUI Button
  6740. * reference is not found or YAHOO.widget.Button does not exist on the page.
  6741. *
  6742. * @method _getButton
  6743. * @private
  6744. * @param {HTMLElement} button
  6745. * @return {YAHOO.widget.Button|HTMLElement}
  6746. */
  6747. _getButton : function(button) {
  6748. var Button = YAHOO.widget.Button;
  6749. // If we have an HTML button and YUI Button is on the page,
  6750. // get the YUI Button reference if available.
  6751. if (Button && button && button.nodeName && button.id) {
  6752. button = Button.getButton(button.id) || button;
  6753. }
  6754. return button;
  6755. },
  6756. /**
  6757. * Sets the focus to the button that is designated as the default via
  6758. * the "buttons" configuration property. By default, this method is
  6759. * called when the Dialog is made visible.
  6760. * @method focusDefaultButton
  6761. */
  6762. focusDefaultButton: function () {
  6763. var button = this._getButton(this.defaultHtmlButton);
  6764. if (button) {
  6765. /*
  6766. Place the call to the "focus" method inside a try/catch
  6767. block to prevent IE from throwing JavaScript errors if
  6768. the element is disabled or hidden.
  6769. */
  6770. try {
  6771. button.focus();
  6772. } catch(oException) {
  6773. }
  6774. }
  6775. },
  6776. /**
  6777. * Blurs all the buttons defined via the "buttons"
  6778. * configuration property.
  6779. * @method blurButtons
  6780. */
  6781. blurButtons: function () {
  6782. var aButtons = this.cfg.getProperty("buttons"),
  6783. nButtons,
  6784. oButton,
  6785. oElement,
  6786. i;
  6787. if (aButtons && Lang.isArray(aButtons)) {
  6788. nButtons = aButtons.length;
  6789. if (nButtons > 0) {
  6790. i = (nButtons - 1);
  6791. do {
  6792. oButton = aButtons[i];
  6793. if (oButton) {
  6794. oElement = this._getButton(oButton.htmlButton);
  6795. if (oElement) {
  6796. /*
  6797. Place the call to the "blur" method inside
  6798. a try/catch block to prevent IE from
  6799. throwing JavaScript errors if the element
  6800. is disabled or hidden.
  6801. */
  6802. try {
  6803. oElement.blur();
  6804. } catch(oException) {
  6805. // ignore
  6806. }
  6807. }
  6808. }
  6809. } while(i--);
  6810. }
  6811. }
  6812. },
  6813. /**
  6814. * Sets the focus to the first button created via the "buttons"
  6815. * configuration property.
  6816. * @method focusFirstButton
  6817. */
  6818. focusFirstButton: function () {
  6819. var aButtons = this.cfg.getProperty("buttons"),
  6820. oButton,
  6821. oElement;
  6822. if (aButtons && Lang.isArray(aButtons)) {
  6823. oButton = aButtons[0];
  6824. if (oButton) {
  6825. oElement = this._getButton(oButton.htmlButton);
  6826. if (oElement) {
  6827. /*
  6828. Place the call to the "focus" method inside a
  6829. try/catch block to prevent IE from throwing
  6830. JavaScript errors if the element is disabled
  6831. or hidden.
  6832. */
  6833. try {
  6834. oElement.focus();
  6835. } catch(oException) {
  6836. // ignore
  6837. }
  6838. }
  6839. }
  6840. }
  6841. },
  6842. /**
  6843. * Sets the focus to the last button created via the "buttons"
  6844. * configuration property.
  6845. * @method focusLastButton
  6846. */
  6847. focusLastButton: function () {
  6848. var aButtons = this.cfg.getProperty("buttons"),
  6849. nButtons,
  6850. oButton,
  6851. oElement;
  6852. if (aButtons && Lang.isArray(aButtons)) {
  6853. nButtons = aButtons.length;
  6854. if (nButtons > 0) {
  6855. oButton = aButtons[(nButtons - 1)];
  6856. if (oButton) {
  6857. oElement = this._getButton(oButton.htmlButton);
  6858. if (oElement) {
  6859. /*
  6860. Place the call to the "focus" method inside a
  6861. try/catch block to prevent IE from throwing
  6862. JavaScript errors if the element is disabled
  6863. or hidden.
  6864. */
  6865. try {
  6866. oElement.focus();
  6867. } catch(oException) {
  6868. // Ignore
  6869. }
  6870. }
  6871. }
  6872. }
  6873. }
  6874. },
  6875. /**
  6876. * The default event handler for the "postmethod" configuration property
  6877. * @method configPostMethod
  6878. * @param {String} type The CustomEvent type (usually the property name)
  6879. * @param {Object[]} args The CustomEvent arguments. For
  6880. * configuration handlers, args[0] will equal the newly applied value
  6881. * for the property.
  6882. * @param {Object} obj The scope object. For configuration handlers,
  6883. * this will usually equal the owner.
  6884. */
  6885. configPostMethod: function (type, args, obj) {
  6886. this.registerForm();
  6887. },
  6888. // END BUILT-IN PROPERTY EVENT HANDLERS //
  6889. /**
  6890. * Built-in function hook for writing a validation function that will
  6891. * be checked for a "true" value prior to a submit. This function, as
  6892. * implemented by default, always returns true, so it should be
  6893. * overridden if validation is necessary.
  6894. * @method validate
  6895. */
  6896. validate: function () {
  6897. return true;
  6898. },
  6899. /**
  6900. * Executes a submit of the Dialog if validation
  6901. * is successful. By default the Dialog is hidden
  6902. * after submission, but you can set the "hideaftersubmit"
  6903. * configuration property to false, to prevent the Dialog
  6904. * from being hidden.
  6905. *
  6906. * @method submit
  6907. */
  6908. submit: function () {
  6909. if (this.validate()) {
  6910. if (this.beforeSubmitEvent.fire()) {
  6911. this.doSubmit();
  6912. this.submitEvent.fire();
  6913. if (this.cfg.getProperty("hideaftersubmit")) {
  6914. this.hide();
  6915. }
  6916. return true;
  6917. } else {
  6918. return false;
  6919. }
  6920. } else {
  6921. return false;
  6922. }
  6923. },
  6924. /**
  6925. * Executes the cancel of the Dialog followed by a hide.
  6926. * @method cancel
  6927. */
  6928. cancel: function () {
  6929. this.cancelEvent.fire();
  6930. this.hide();
  6931. },
  6932. /**
  6933. * Returns a JSON-compatible data structure representing the data
  6934. * currently contained in the form.
  6935. * @method getData
  6936. * @return {Object} A JSON object reprsenting the data of the
  6937. * current form.
  6938. */
  6939. getData: function () {
  6940. var oForm = this.form,
  6941. aElements,
  6942. nTotalElements,
  6943. oData,
  6944. sName,
  6945. oElement,
  6946. nElements,
  6947. sType,
  6948. sTagName,
  6949. aOptions,
  6950. nOptions,
  6951. aValues,
  6952. oOption,
  6953. oRadio,
  6954. oCheckbox,
  6955. valueAttr,
  6956. i,
  6957. n;
  6958. function isFormElement(p_oElement) {
  6959. var sTag = p_oElement.tagName.toUpperCase();
  6960. return ((sTag == "INPUT" || sTag == "TEXTAREA" ||
  6961. sTag == "SELECT") && p_oElement.name == sName);
  6962. }
  6963. if (oForm) {
  6964. aElements = oForm.elements;
  6965. nTotalElements = aElements.length;
  6966. oData = {};
  6967. for (i = 0; i < nTotalElements; i++) {
  6968. sName = aElements[i].name;
  6969. /*
  6970. Using "Dom.getElementsBy" to safeguard user from JS
  6971. errors that result from giving a form field (or set of
  6972. fields) the same name as a native method of a form
  6973. (like "submit") or a DOM collection (such as the "item"
  6974. method). Originally tried accessing fields via the
  6975. "namedItem" method of the "element" collection, but
  6976. discovered that it won't return a collection of fields
  6977. in Gecko.
  6978. */
  6979. oElement = Dom.getElementsBy(isFormElement, "*", oForm);
  6980. nElements = oElement.length;
  6981. if (nElements > 0) {
  6982. if (nElements == 1) {
  6983. oElement = oElement[0];
  6984. sType = oElement.type;
  6985. sTagName = oElement.tagName.toUpperCase();
  6986. switch (sTagName) {
  6987. case "INPUT":
  6988. if (sType == "checkbox") {
  6989. oData[sName] = oElement.checked;
  6990. } else if (sType != "radio") {
  6991. oData[sName] = oElement.value;
  6992. }
  6993. break;
  6994. case "TEXTAREA":
  6995. oData[sName] = oElement.value;
  6996. break;
  6997. case "SELECT":
  6998. aOptions = oElement.options;
  6999. nOptions = aOptions.length;
  7000. aValues = [];
  7001. for (n = 0; n < nOptions; n++) {
  7002. oOption = aOptions[n];
  7003. if (oOption.selected) {
  7004. valueAttr = oOption.attributes.value;
  7005. aValues[aValues.length] = (valueAttr && valueAttr.specified) ? oOption.value : oOption.text;
  7006. }
  7007. }
  7008. oData[sName] = aValues;
  7009. break;
  7010. }
  7011. } else {
  7012. sType = oElement[0].type;
  7013. switch (sType) {
  7014. case "radio":
  7015. for (n = 0; n < nElements; n++) {
  7016. oRadio = oElement[n];
  7017. if (oRadio.checked) {
  7018. oData[sName] = oRadio.value;
  7019. break;
  7020. }
  7021. }
  7022. break;
  7023. case "checkbox":
  7024. aValues = [];
  7025. for (n = 0; n < nElements; n++) {
  7026. oCheckbox = oElement[n];
  7027. if (oCheckbox.checked) {
  7028. aValues[aValues.length] = oCheckbox.value;
  7029. }
  7030. }
  7031. oData[sName] = aValues;
  7032. break;
  7033. }
  7034. }
  7035. }
  7036. }
  7037. }
  7038. return oData;
  7039. },
  7040. /**
  7041. * Removes the Panel element from the DOM and sets all child elements
  7042. * to null.
  7043. * @method destroy
  7044. */
  7045. destroy: function () {
  7046. removeButtonEventHandlers.call(this);
  7047. this._aButtons = null;
  7048. var aForms = this.element.getElementsByTagName("form"),
  7049. oForm;
  7050. if (aForms.length > 0) {
  7051. oForm = aForms[0];
  7052. if (oForm) {
  7053. Event.purgeElement(oForm);
  7054. if (oForm.parentNode) {
  7055. oForm.parentNode.removeChild(oForm);
  7056. }
  7057. this.form = null;
  7058. }
  7059. }
  7060. Dialog.superclass.destroy.call(this);
  7061. },
  7062. /**
  7063. * Returns a string representation of the object.
  7064. * @method toString
  7065. * @return {String} The string representation of the Dialog
  7066. */
  7067. toString: function () {
  7068. return "Dialog " + this.id;
  7069. }
  7070. });
  7071. }());
  7072. (function () {
  7073. /**
  7074. * SimpleDialog is a simple implementation of Dialog that can be used to
  7075. * submit a single value. Forms can be processed in 3 ways -- via an
  7076. * asynchronous Connection utility call, a simple form POST or GET,
  7077. * or manually.
  7078. * @namespace YAHOO.widget
  7079. * @class SimpleDialog
  7080. * @extends YAHOO.widget.Dialog
  7081. * @constructor
  7082. * @param {String} el The element ID representing the SimpleDialog
  7083. * <em>OR</em>
  7084. * @param {HTMLElement} el The element representing the SimpleDialog
  7085. * @param {Object} userConfig The configuration object literal containing
  7086. * the configuration that should be set for this SimpleDialog. See
  7087. * configuration documentation for more details.
  7088. */
  7089. YAHOO.widget.SimpleDialog = function (el, userConfig) {
  7090. YAHOO.widget.SimpleDialog.superclass.constructor.call(this,
  7091. el, userConfig);
  7092. };
  7093. var Dom = YAHOO.util.Dom,
  7094. SimpleDialog = YAHOO.widget.SimpleDialog,
  7095. /**
  7096. * Constant representing the SimpleDialog's configuration properties
  7097. * @property DEFAULT_CONFIG
  7098. * @private
  7099. * @final
  7100. * @type Object
  7101. */
  7102. DEFAULT_CONFIG = {
  7103. "ICON": {
  7104. key: "icon",
  7105. value: "none",
  7106. suppressEvent: true
  7107. },
  7108. "TEXT": {
  7109. key: "text",
  7110. value: "",
  7111. suppressEvent: true,
  7112. supercedes: ["icon"]
  7113. }
  7114. };
  7115. /**
  7116. * Constant for the standard network icon for a blocking action
  7117. * @property YAHOO.widget.SimpleDialog.ICON_BLOCK
  7118. * @static
  7119. * @final
  7120. * @type String
  7121. */
  7122. SimpleDialog.ICON_BLOCK = "blckicon";
  7123. /**
  7124. * Constant for the standard network icon for alarm
  7125. * @property YAHOO.widget.SimpleDialog.ICON_ALARM
  7126. * @static
  7127. * @final
  7128. * @type String
  7129. */
  7130. SimpleDialog.ICON_ALARM = "alrticon";
  7131. /**
  7132. * Constant for the standard network icon for help
  7133. * @property YAHOO.widget.SimpleDialog.ICON_HELP
  7134. * @static
  7135. * @final
  7136. * @type String
  7137. */
  7138. SimpleDialog.ICON_HELP = "hlpicon";
  7139. /**
  7140. * Constant for the standard network icon for info
  7141. * @property YAHOO.widget.SimpleDialog.ICON_INFO
  7142. * @static
  7143. * @final
  7144. * @type String
  7145. */
  7146. SimpleDialog.ICON_INFO = "infoicon";
  7147. /**
  7148. * Constant for the standard network icon for warn
  7149. * @property YAHOO.widget.SimpleDialog.ICON_WARN
  7150. * @static
  7151. * @final
  7152. * @type String
  7153. */
  7154. SimpleDialog.ICON_WARN = "warnicon";
  7155. /**
  7156. * Constant for the standard network icon for a tip
  7157. * @property YAHOO.widget.SimpleDialog.ICON_TIP
  7158. * @static
  7159. * @final
  7160. * @type String
  7161. */
  7162. SimpleDialog.ICON_TIP = "tipicon";
  7163. /**
  7164. * Constant representing the name of the CSS class applied to the element
  7165. * created by the "icon" configuration property.
  7166. * @property YAHOO.widget.SimpleDialog.ICON_CSS_CLASSNAME
  7167. * @static
  7168. * @final
  7169. * @type String
  7170. */
  7171. SimpleDialog.ICON_CSS_CLASSNAME = "yui-icon";
  7172. /**
  7173. * Constant representing the default CSS class used for a SimpleDialog
  7174. * @property YAHOO.widget.SimpleDialog.CSS_SIMPLEDIALOG
  7175. * @static
  7176. * @final
  7177. * @type String
  7178. */
  7179. SimpleDialog.CSS_SIMPLEDIALOG = "yui-simple-dialog";
  7180. YAHOO.extend(SimpleDialog, YAHOO.widget.Dialog, {
  7181. /**
  7182. * Initializes the class's configurable properties which can be changed
  7183. * using the SimpleDialog's Config object (cfg).
  7184. * @method initDefaultConfig
  7185. */
  7186. initDefaultConfig: function () {
  7187. SimpleDialog.superclass.initDefaultConfig.call(this);
  7188. // Add dialog config properties //
  7189. /**
  7190. * Sets the informational icon for the SimpleDialog
  7191. * @config icon
  7192. * @type String
  7193. * @default "none"
  7194. */
  7195. this.cfg.addProperty(DEFAULT_CONFIG.ICON.key, {
  7196. handler: this.configIcon,
  7197. value: DEFAULT_CONFIG.ICON.value,
  7198. suppressEvent: DEFAULT_CONFIG.ICON.suppressEvent
  7199. });
  7200. /**
  7201. * Sets the text for the SimpleDialog
  7202. * @config text
  7203. * @type String
  7204. * @default ""
  7205. */
  7206. this.cfg.addProperty(DEFAULT_CONFIG.TEXT.key, {
  7207. handler: this.configText,
  7208. value: DEFAULT_CONFIG.TEXT.value,
  7209. suppressEvent: DEFAULT_CONFIG.TEXT.suppressEvent,
  7210. supercedes: DEFAULT_CONFIG.TEXT.supercedes
  7211. });
  7212. },
  7213. /**
  7214. * The SimpleDialog initialization method, which is executed for
  7215. * SimpleDialog and all of its subclasses. This method is automatically
  7216. * called by the constructor, and sets up all DOM references for
  7217. * pre-existing markup, and creates required markup if it is not
  7218. * already present.
  7219. * @method init
  7220. * @param {String} el The element ID representing the SimpleDialog
  7221. * <em>OR</em>
  7222. * @param {HTMLElement} el The element representing the SimpleDialog
  7223. * @param {Object} userConfig The configuration object literal
  7224. * containing the configuration that should be set for this
  7225. * SimpleDialog. See configuration documentation for more details.
  7226. */
  7227. init: function (el, userConfig) {
  7228. /*
  7229. Note that we don't pass the user config in here yet because we
  7230. only want it executed once, at the lowest subclass level
  7231. */
  7232. SimpleDialog.superclass.init.call(this, el/*, userConfig*/);
  7233. this.beforeInitEvent.fire(SimpleDialog);
  7234. Dom.addClass(this.element, SimpleDialog.CSS_SIMPLEDIALOG);
  7235. this.cfg.queueProperty("postmethod", "manual");
  7236. if (userConfig) {
  7237. this.cfg.applyConfig(userConfig, true);
  7238. }
  7239. this.beforeRenderEvent.subscribe(function () {
  7240. if (! this.body) {
  7241. this.setBody("");
  7242. }
  7243. }, this, true);
  7244. this.initEvent.fire(SimpleDialog);
  7245. },
  7246. /**
  7247. * Prepares the SimpleDialog's internal FORM object, creating one if one
  7248. * is not currently present, and adding the value hidden field.
  7249. * @method registerForm
  7250. */
  7251. registerForm: function () {
  7252. SimpleDialog.superclass.registerForm.call(this);
  7253. this.form.innerHTML += "<input type=\"hidden\" name=\"" +
  7254. this.id + "\" value=\"\"/>";
  7255. },
  7256. // BEGIN BUILT-IN PROPERTY EVENT HANDLERS //
  7257. /**
  7258. * Fired when the "icon" property is set.
  7259. * @method configIcon
  7260. * @param {String} type The CustomEvent type (usually the property name)
  7261. * @param {Object[]} args The CustomEvent arguments. For configuration
  7262. * handlers, args[0] will equal the newly applied value for the property.
  7263. * @param {Object} obj The scope object. For configuration handlers,
  7264. * this will usually equal the owner.
  7265. */
  7266. configIcon: function (type,args,obj) {
  7267. var sIcon = args[0],
  7268. oBody = this.body,
  7269. sCSSClass = SimpleDialog.ICON_CSS_CLASSNAME,
  7270. aElements,
  7271. oIcon,
  7272. oIconParent;
  7273. if (sIcon && sIcon != "none") {
  7274. aElements = Dom.getElementsByClassName(sCSSClass, "*" , oBody);
  7275. if (aElements.length === 1) {
  7276. oIcon = aElements[0];
  7277. oIconParent = oIcon.parentNode;
  7278. if (oIconParent) {
  7279. oIconParent.removeChild(oIcon);
  7280. oIcon = null;
  7281. }
  7282. }
  7283. if (sIcon.indexOf(".") == -1) {
  7284. oIcon = document.createElement("span");
  7285. oIcon.className = (sCSSClass + " " + sIcon);
  7286. oIcon.innerHTML = "&#160;";
  7287. } else {
  7288. oIcon = document.createElement("img");
  7289. oIcon.src = (this.imageRoot + sIcon);
  7290. oIcon.className = sCSSClass;
  7291. }
  7292. if (oIcon) {
  7293. oBody.insertBefore(oIcon, oBody.firstChild);
  7294. }
  7295. }
  7296. },
  7297. /**
  7298. * Fired when the "text" property is set.
  7299. * @method configText
  7300. * @param {String} type The CustomEvent type (usually the property name)
  7301. * @param {Object[]} args The CustomEvent arguments. For configuration
  7302. * handlers, args[0] will equal the newly applied value for the property.
  7303. * @param {Object} obj The scope object. For configuration handlers,
  7304. * this will usually equal the owner.
  7305. */
  7306. configText: function (type,args,obj) {
  7307. var text = args[0];
  7308. if (text) {
  7309. this.setBody(text);
  7310. this.cfg.refireEvent("icon");
  7311. }
  7312. },
  7313. // END BUILT-IN PROPERTY EVENT HANDLERS //
  7314. /**
  7315. * Returns a string representation of the object.
  7316. * @method toString
  7317. * @return {String} The string representation of the SimpleDialog
  7318. */
  7319. toString: function () {
  7320. return "SimpleDialog " + this.id;
  7321. }
  7322. /**
  7323. * <p>
  7324. * Sets the SimpleDialog's body content to the HTML specified.
  7325. * If no body is present, one will be automatically created.
  7326. * An empty string can be passed to the method to clear the contents of the body.
  7327. * </p>
  7328. * <p><strong>NOTE:</strong> SimpleDialog provides the <a href="#config_text">text</a>
  7329. * and <a href="#config_icon">icon</a> configuration properties to set the contents
  7330. * of it's body element in accordance with the UI design for a SimpleDialog (an
  7331. * icon and message text). Calling setBody on the SimpleDialog will not enforce this
  7332. * UI design constraint and will replace the entire contents of the SimpleDialog body.
  7333. * It should only be used if you wish the replace the default icon/text body structure
  7334. * of a SimpleDialog with your own custom markup.</p>
  7335. *
  7336. * @method setBody
  7337. * @param {String} bodyContent The HTML used to set the body.
  7338. * As a convenience, non HTMLElement objects can also be passed into
  7339. * the method, and will be treated as strings, with the body innerHTML
  7340. * set to their default toString implementations.
  7341. * <em>OR</em>
  7342. * @param {HTMLElement} bodyContent The HTMLElement to add as the first and only child of the body element.
  7343. * <em>OR</em>
  7344. * @param {DocumentFragment} bodyContent The document fragment
  7345. * containing elements which are to be added to the body
  7346. */
  7347. });
  7348. }());
  7349. (function () {
  7350. /**
  7351. * ContainerEffect encapsulates animation transitions that are executed when
  7352. * an Overlay is shown or hidden.
  7353. * @namespace YAHOO.widget
  7354. * @class ContainerEffect
  7355. * @constructor
  7356. * @param {YAHOO.widget.Overlay} overlay The Overlay that the animation
  7357. * should be associated with
  7358. * @param {Object} attrIn The object literal representing the animation
  7359. * arguments to be used for the animate-in transition. The arguments for
  7360. * this literal are: attributes(object, see YAHOO.util.Anim for description),
  7361. * duration(Number), and method(i.e. Easing.easeIn).
  7362. * @param {Object} attrOut The object literal representing the animation
  7363. * arguments to be used for the animate-out transition. The arguments for
  7364. * this literal are: attributes(object, see YAHOO.util.Anim for description),
  7365. * duration(Number), and method(i.e. Easing.easeIn).
  7366. * @param {HTMLElement} targetElement Optional. The target element that
  7367. * should be animated during the transition. Defaults to overlay.element.
  7368. * @param {class} Optional. The animation class to instantiate. Defaults to
  7369. * YAHOO.util.Anim. Other options include YAHOO.util.Motion.
  7370. */
  7371. YAHOO.widget.ContainerEffect = function (overlay, attrIn, attrOut, targetElement, animClass) {
  7372. if (!animClass) {
  7373. animClass = YAHOO.util.Anim;
  7374. }
  7375. /**
  7376. * The overlay to animate
  7377. * @property overlay
  7378. * @type YAHOO.widget.Overlay
  7379. */
  7380. this.overlay = overlay;
  7381. /**
  7382. * The animation attributes to use when transitioning into view
  7383. * @property attrIn
  7384. * @type Object
  7385. */
  7386. this.attrIn = attrIn;
  7387. /**
  7388. * The animation attributes to use when transitioning out of view
  7389. * @property attrOut
  7390. * @type Object
  7391. */
  7392. this.attrOut = attrOut;
  7393. /**
  7394. * The target element to be animated
  7395. * @property targetElement
  7396. * @type HTMLElement
  7397. */
  7398. this.targetElement = targetElement || overlay.element;
  7399. /**
  7400. * The animation class to use for animating the overlay
  7401. * @property animClass
  7402. * @type class
  7403. */
  7404. this.animClass = animClass;
  7405. };
  7406. var Dom = YAHOO.util.Dom,
  7407. CustomEvent = YAHOO.util.CustomEvent,
  7408. ContainerEffect = YAHOO.widget.ContainerEffect;
  7409. /**
  7410. * A pre-configured ContainerEffect instance that can be used for fading
  7411. * an overlay in and out.
  7412. * @method FADE
  7413. * @static
  7414. * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
  7415. * @param {Number} dur The duration of the animation
  7416. * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
  7417. */
  7418. ContainerEffect.FADE = function (overlay, dur) {
  7419. var Easing = YAHOO.util.Easing,
  7420. fin = {
  7421. attributes: {opacity:{from:0, to:1}},
  7422. duration: dur,
  7423. method: Easing.easeIn
  7424. },
  7425. fout = {
  7426. attributes: {opacity:{to:0}},
  7427. duration: dur,
  7428. method: Easing.easeOut
  7429. },
  7430. fade = new ContainerEffect(overlay, fin, fout, overlay.element);
  7431. fade.handleUnderlayStart = function() {
  7432. var underlay = this.overlay.underlay;
  7433. if (underlay && YAHOO.env.ua.ie) {
  7434. var hasFilters = (underlay.filters && underlay.filters.length > 0);
  7435. if(hasFilters) {
  7436. Dom.addClass(overlay.element, "yui-effect-fade");
  7437. }
  7438. }
  7439. };
  7440. fade.handleUnderlayComplete = function() {
  7441. var underlay = this.overlay.underlay;
  7442. if (underlay && YAHOO.env.ua.ie) {
  7443. Dom.removeClass(overlay.element, "yui-effect-fade");
  7444. }
  7445. };
  7446. fade.handleStartAnimateIn = function (type, args, obj) {
  7447. Dom.addClass(obj.overlay.element, "hide-select");
  7448. if (!obj.overlay.underlay) {
  7449. obj.overlay.cfg.refireEvent("underlay");
  7450. }
  7451. obj.handleUnderlayStart();
  7452. obj.overlay._setDomVisibility(true);
  7453. Dom.setStyle(obj.overlay.element, "opacity", 0);
  7454. };
  7455. fade.handleCompleteAnimateIn = function (type,args,obj) {
  7456. Dom.removeClass(obj.overlay.element, "hide-select");
  7457. if (obj.overlay.element.style.filter) {
  7458. obj.overlay.element.style.filter = null;
  7459. }
  7460. obj.handleUnderlayComplete();
  7461. obj.overlay.cfg.refireEvent("iframe");
  7462. obj.animateInCompleteEvent.fire();
  7463. };
  7464. fade.handleStartAnimateOut = function (type, args, obj) {
  7465. Dom.addClass(obj.overlay.element, "hide-select");
  7466. obj.handleUnderlayStart();
  7467. };
  7468. fade.handleCompleteAnimateOut = function (type, args, obj) {
  7469. Dom.removeClass(obj.overlay.element, "hide-select");
  7470. if (obj.overlay.element.style.filter) {
  7471. obj.overlay.element.style.filter = null;
  7472. }
  7473. obj.overlay._setDomVisibility(false);
  7474. Dom.setStyle(obj.overlay.element, "opacity", 1);
  7475. obj.handleUnderlayComplete();
  7476. obj.overlay.cfg.refireEvent("iframe");
  7477. obj.animateOutCompleteEvent.fire();
  7478. };
  7479. fade.init();
  7480. return fade;
  7481. };
  7482. /**
  7483. * A pre-configured ContainerEffect instance that can be used for sliding an
  7484. * overlay in and out.
  7485. * @method SLIDE
  7486. * @static
  7487. * @param {YAHOO.widget.Overlay} overlay The Overlay object to animate
  7488. * @param {Number} dur The duration of the animation
  7489. * @return {YAHOO.widget.ContainerEffect} The configured ContainerEffect object
  7490. */
  7491. ContainerEffect.SLIDE = function (overlay, dur) {
  7492. var Easing = YAHOO.util.Easing,
  7493. x = overlay.cfg.getProperty("x") || Dom.getX(overlay.element),
  7494. y = overlay.cfg.getProperty("y") || Dom.getY(overlay.element),
  7495. clientWidth = Dom.getClientWidth(),
  7496. offsetWidth = overlay.element.offsetWidth,
  7497. sin = {
  7498. attributes: { points: { to: [x, y] } },
  7499. duration: dur,
  7500. method: Easing.easeIn
  7501. },
  7502. sout = {
  7503. attributes: { points: { to: [(clientWidth + 25), y] } },
  7504. duration: dur,
  7505. method: Easing.easeOut
  7506. },
  7507. slide = new ContainerEffect(overlay, sin, sout, overlay.element, YAHOO.util.Motion);
  7508. slide.handleStartAnimateIn = function (type,args,obj) {
  7509. obj.overlay.element.style.left = ((-25) - offsetWidth) + "px";
  7510. obj.overlay.element.style.top = y + "px";
  7511. };
  7512. slide.handleTweenAnimateIn = function (type, args, obj) {
  7513. var pos = Dom.getXY(obj.overlay.element),
  7514. currentX = pos[0],
  7515. currentY = pos[1];
  7516. if (Dom.getStyle(obj.overlay.element, "visibility") ==
  7517. "hidden" && currentX < x) {
  7518. obj.overlay._setDomVisibility(true);
  7519. }
  7520. obj.overlay.cfg.setProperty("xy", [currentX, currentY], true);
  7521. obj.overlay.cfg.refireEvent("iframe");
  7522. };
  7523. slide.handleCompleteAnimateIn = function (type, args, obj) {
  7524. obj.overlay.cfg.setProperty("xy", [x, y], true);
  7525. obj.startX = x;
  7526. obj.startY = y;
  7527. obj.overlay.cfg.refireEvent("iframe");
  7528. obj.animateInCompleteEvent.fire();
  7529. };
  7530. slide.handleStartAnimateOut = function (type, args, obj) {
  7531. var vw = Dom.getViewportWidth(),
  7532. pos = Dom.getXY(obj.overlay.element),
  7533. yso = pos[1];
  7534. obj.animOut.attributes.points.to = [(vw + 25), yso];
  7535. };
  7536. slide.handleTweenAnimateOut = function (type, args, obj) {
  7537. var pos = Dom.getXY(obj.overlay.element),
  7538. xto = pos[0],
  7539. yto = pos[1];
  7540. obj.overlay.cfg.setProperty("xy", [xto, yto], true);
  7541. obj.overlay.cfg.refireEvent("iframe");
  7542. };
  7543. slide.handleCompleteAnimateOut = function (type, args, obj) {
  7544. obj.overlay._setDomVisibility(false);
  7545. obj.overlay.cfg.setProperty("xy", [x, y]);
  7546. obj.animateOutCompleteEvent.fire();
  7547. };
  7548. slide.init();
  7549. return slide;
  7550. };
  7551. ContainerEffect.prototype = {
  7552. /**
  7553. * Initializes the animation classes and events.
  7554. * @method init
  7555. */
  7556. init: function () {
  7557. this.beforeAnimateInEvent = this.createEvent("beforeAnimateIn");
  7558. this.beforeAnimateInEvent.signature = CustomEvent.LIST;
  7559. this.beforeAnimateOutEvent = this.createEvent("beforeAnimateOut");
  7560. this.beforeAnimateOutEvent.signature = CustomEvent.LIST;
  7561. this.animateInCompleteEvent = this.createEvent("animateInComplete");
  7562. this.animateInCompleteEvent.signature = CustomEvent.LIST;
  7563. this.animateOutCompleteEvent =
  7564. this.createEvent("animateOutComplete");
  7565. this.animateOutCompleteEvent.signature = CustomEvent.LIST;
  7566. this.animIn = new this.animClass(this.targetElement,
  7567. this.attrIn.attributes, this.attrIn.duration,
  7568. this.attrIn.method);
  7569. this.animIn.onStart.subscribe(this.handleStartAnimateIn, this);
  7570. this.animIn.onTween.subscribe(this.handleTweenAnimateIn, this);
  7571. this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,
  7572. this);
  7573. this.animOut = new this.animClass(this.targetElement,
  7574. this.attrOut.attributes, this.attrOut.duration,
  7575. this.attrOut.method);
  7576. this.animOut.onStart.subscribe(this.handleStartAnimateOut, this);
  7577. this.animOut.onTween.subscribe(this.handleTweenAnimateOut, this);
  7578. this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,
  7579. this);
  7580. },
  7581. /**
  7582. * Triggers the in-animation.
  7583. * @method animateIn
  7584. */
  7585. animateIn: function () {
  7586. this.beforeAnimateInEvent.fire();
  7587. this.animIn.animate();
  7588. },
  7589. /**
  7590. * Triggers the out-animation.
  7591. * @method animateOut
  7592. */
  7593. animateOut: function () {
  7594. this.beforeAnimateOutEvent.fire();
  7595. this.animOut.animate();
  7596. },
  7597. /**
  7598. * The default onStart handler for the in-animation.
  7599. * @method handleStartAnimateIn
  7600. * @param {String} type The CustomEvent type
  7601. * @param {Object[]} args The CustomEvent arguments
  7602. * @param {Object} obj The scope object
  7603. */
  7604. handleStartAnimateIn: function (type, args, obj) { },
  7605. /**
  7606. * The default onTween handler for the in-animation.
  7607. * @method handleTweenAnimateIn
  7608. * @param {String} type The CustomEvent type
  7609. * @param {Object[]} args The CustomEvent arguments
  7610. * @param {Object} obj The scope object
  7611. */
  7612. handleTweenAnimateIn: function (type, args, obj) { },
  7613. /**
  7614. * The default onComplete handler for the in-animation.
  7615. * @method handleCompleteAnimateIn
  7616. * @param {String} type The CustomEvent type
  7617. * @param {Object[]} args The CustomEvent arguments
  7618. * @param {Object} obj The scope object
  7619. */
  7620. handleCompleteAnimateIn: function (type, args, obj) { },
  7621. /**
  7622. * The default onStart handler for the out-animation.
  7623. * @method handleStartAnimateOut
  7624. * @param {String} type The CustomEvent type
  7625. * @param {Object[]} args The CustomEvent arguments
  7626. * @param {Object} obj The scope object
  7627. */
  7628. handleStartAnimateOut: function (type, args, obj) { },
  7629. /**
  7630. * The default onTween handler for the out-animation.
  7631. * @method handleTweenAnimateOut
  7632. * @param {String} type The CustomEvent type
  7633. * @param {Object[]} args The CustomEvent arguments
  7634. * @param {Object} obj The scope object
  7635. */
  7636. handleTweenAnimateOut: function (type, args, obj) { },
  7637. /**
  7638. * The default onComplete handler for the out-animation.
  7639. * @method handleCompleteAnimateOut
  7640. * @param {String} type The CustomEvent type
  7641. * @param {Object[]} args The CustomEvent arguments
  7642. * @param {Object} obj The scope object
  7643. */
  7644. handleCompleteAnimateOut: function (type, args, obj) { },
  7645. /**
  7646. * Returns a string representation of the object.
  7647. * @method toString
  7648. * @return {String} The string representation of the ContainerEffect
  7649. */
  7650. toString: function () {
  7651. var output = "ContainerEffect";
  7652. if (this.overlay) {
  7653. output += " [" + this.overlay.toString() + "]";
  7654. }
  7655. return output;
  7656. }
  7657. };
  7658. YAHOO.lang.augmentProto(ContainerEffect, YAHOO.util.EventProvider);
  7659. })();
  7660. YAHOO.register("container", YAHOO.widget.Module, {version: "2.8.0r4", build: "2449"});