container.js 315 KB

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