firebug-lite-beta.js 913 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775977697779778977997809781978297839784978597869787978897899790979197929793979497959796979797989799980098019802980398049805980698079808980998109811981298139814981598169817981898199820982198229823982498259826982798289829983098319832983398349835983698379838983998409841984298439844984598469847984898499850985198529853985498559856985798589859986098619862986398649865986698679868986998709871987298739874987598769877987898799880988198829883988498859886988798889889989098919892989398949895989698979898989999009901990299039904990599069907990899099910991199129913991499159916991799189919992099219922992399249925992699279928992999309931993299339934993599369937993899399940994199429943994499459946994799489949995099519952995399549955995699579958995999609961996299639964996599669967996899699970997199729973997499759976997799789979998099819982998399849985998699879988998999909991999299939994999599969997999899991000010001100021000310004100051000610007100081000910010100111001210013100141001510016100171001810019100201002110022100231002410025100261002710028100291003010031100321003310034100351003610037100381003910040100411004210043100441004510046100471004810049100501005110052100531005410055100561005710058100591006010061100621006310064100651006610067100681006910070100711007210073100741007510076100771007810079100801008110082100831008410085100861008710088100891009010091100921009310094100951009610097100981009910100101011010210103101041010510106101071010810109101101011110112101131011410115101161011710118101191012010121101221012310124101251012610127101281012910130101311013210133101341013510136101371013810139101401014110142101431014410145101461014710148101491015010151101521015310154101551015610157101581015910160101611016210163101641016510166101671016810169101701017110172101731017410175101761017710178101791018010181101821018310184101851018610187101881018910190101911019210193101941019510196101971019810199102001020110202102031020410205102061020710208102091021010211102121021310214102151021610217102181021910220102211022210223102241022510226102271022810229102301023110232102331023410235102361023710238102391024010241102421024310244102451024610247102481024910250102511025210253102541025510256102571025810259102601026110262102631026410265102661026710268102691027010271102721027310274102751027610277102781027910280102811028210283102841028510286102871028810289102901029110292102931029410295102961029710298102991030010301103021030310304103051030610307103081030910310103111031210313103141031510316103171031810319103201032110322103231032410325103261032710328103291033010331103321033310334103351033610337103381033910340103411034210343103441034510346103471034810349103501035110352103531035410355103561035710358103591036010361103621036310364103651036610367103681036910370103711037210373103741037510376103771037810379103801038110382103831038410385103861038710388103891039010391103921039310394103951039610397103981039910400104011040210403104041040510406104071040810409104101041110412104131041410415104161041710418104191042010421104221042310424104251042610427104281042910430104311043210433104341043510436104371043810439104401044110442104431044410445104461044710448104491045010451104521045310454104551045610457104581045910460104611046210463104641046510466104671046810469104701047110472104731047410475104761047710478104791048010481104821048310484104851048610487104881048910490104911049210493104941049510496104971049810499105001050110502105031050410505105061050710508105091051010511105121051310514105151051610517105181051910520105211052210523105241052510526105271052810529105301053110532105331053410535105361053710538105391054010541105421054310544105451054610547105481054910550105511055210553105541055510556105571055810559105601056110562105631056410565105661056710568105691057010571105721057310574105751057610577105781057910580105811058210583105841058510586105871058810589105901059110592105931059410595105961059710598105991060010601106021060310604106051060610607106081060910610106111061210613106141061510616106171061810619106201062110622106231062410625106261062710628106291063010631106321063310634106351063610637106381063910640106411064210643106441064510646106471064810649106501065110652106531065410655106561065710658106591066010661106621066310664106651066610667106681066910670106711067210673106741067510676106771067810679106801068110682106831068410685106861068710688106891069010691106921069310694106951069610697106981069910700107011070210703107041070510706107071070810709107101071110712107131071410715107161071710718107191072010721107221072310724107251072610727107281072910730107311073210733107341073510736107371073810739107401074110742107431074410745107461074710748107491075010751107521075310754107551075610757107581075910760107611076210763107641076510766107671076810769107701077110772107731077410775107761077710778107791078010781107821078310784107851078610787107881078910790107911079210793107941079510796107971079810799108001080110802108031080410805108061080710808108091081010811108121081310814108151081610817108181081910820108211082210823108241082510826108271082810829108301083110832108331083410835108361083710838108391084010841108421084310844108451084610847108481084910850108511085210853108541085510856108571085810859108601086110862108631086410865108661086710868108691087010871108721087310874108751087610877108781087910880108811088210883108841088510886108871088810889108901089110892108931089410895108961089710898108991090010901109021090310904109051090610907109081090910910109111091210913109141091510916109171091810919109201092110922109231092410925109261092710928109291093010931109321093310934109351093610937109381093910940109411094210943109441094510946109471094810949109501095110952109531095410955109561095710958109591096010961109621096310964109651096610967109681096910970109711097210973109741097510976109771097810979109801098110982109831098410985109861098710988109891099010991109921099310994109951099610997109981099911000110011100211003110041100511006110071100811009110101101111012110131101411015110161101711018110191102011021110221102311024110251102611027110281102911030110311103211033110341103511036110371103811039110401104111042110431104411045110461104711048110491105011051110521105311054110551105611057110581105911060110611106211063110641106511066110671106811069110701107111072110731107411075110761107711078110791108011081110821108311084110851108611087110881108911090110911109211093110941109511096110971109811099111001110111102111031110411105111061110711108111091111011111111121111311114111151111611117111181111911120111211112211123111241112511126111271112811129111301113111132111331113411135111361113711138111391114011141111421114311144111451114611147111481114911150111511115211153111541115511156111571115811159111601116111162111631116411165111661116711168111691117011171111721117311174111751117611177111781117911180111811118211183111841118511186111871118811189111901119111192111931119411195111961119711198111991120011201112021120311204112051120611207112081120911210112111121211213112141121511216112171121811219112201122111222112231122411225112261122711228112291123011231112321123311234112351123611237112381123911240112411124211243112441124511246112471124811249112501125111252112531125411255112561125711258112591126011261112621126311264112651126611267112681126911270112711127211273112741127511276112771127811279112801128111282112831128411285112861128711288112891129011291112921129311294112951129611297112981129911300113011130211303113041130511306113071130811309113101131111312113131131411315113161131711318113191132011321113221132311324113251132611327113281132911330113311133211333113341133511336113371133811339113401134111342113431134411345113461134711348113491135011351113521135311354113551135611357113581135911360113611136211363113641136511366113671136811369113701137111372113731137411375113761137711378113791138011381113821138311384113851138611387113881138911390113911139211393113941139511396113971139811399114001140111402114031140411405114061140711408114091141011411114121141311414114151141611417114181141911420114211142211423114241142511426114271142811429114301143111432114331143411435114361143711438114391144011441114421144311444114451144611447114481144911450114511145211453114541145511456114571145811459114601146111462114631146411465114661146711468114691147011471114721147311474114751147611477114781147911480114811148211483114841148511486114871148811489114901149111492114931149411495114961149711498114991150011501115021150311504115051150611507115081150911510115111151211513115141151511516115171151811519115201152111522115231152411525115261152711528115291153011531115321153311534115351153611537115381153911540115411154211543115441154511546115471154811549115501155111552115531155411555115561155711558115591156011561115621156311564115651156611567115681156911570115711157211573115741157511576115771157811579115801158111582115831158411585115861158711588115891159011591115921159311594115951159611597115981159911600116011160211603116041160511606116071160811609116101161111612116131161411615116161161711618116191162011621116221162311624116251162611627116281162911630116311163211633116341163511636116371163811639116401164111642116431164411645116461164711648116491165011651116521165311654116551165611657116581165911660116611166211663116641166511666116671166811669116701167111672116731167411675116761167711678116791168011681116821168311684116851168611687116881168911690116911169211693116941169511696116971169811699117001170111702117031170411705117061170711708117091171011711117121171311714117151171611717117181171911720117211172211723117241172511726117271172811729117301173111732117331173411735117361173711738117391174011741117421174311744117451174611747117481174911750117511175211753117541175511756117571175811759117601176111762117631176411765117661176711768117691177011771117721177311774117751177611777117781177911780117811178211783117841178511786117871178811789117901179111792117931179411795117961179711798117991180011801118021180311804118051180611807118081180911810118111181211813118141181511816118171181811819118201182111822118231182411825118261182711828118291183011831118321183311834118351183611837118381183911840118411184211843118441184511846118471184811849118501185111852118531185411855118561185711858118591186011861118621186311864118651186611867118681186911870118711187211873118741187511876118771187811879118801188111882118831188411885118861188711888118891189011891118921189311894118951189611897118981189911900119011190211903119041190511906119071190811909119101191111912119131191411915119161191711918119191192011921119221192311924119251192611927119281192911930119311193211933119341193511936119371193811939119401194111942119431194411945119461194711948119491195011951119521195311954119551195611957119581195911960119611196211963119641196511966119671196811969119701197111972119731197411975119761197711978119791198011981119821198311984119851198611987119881198911990119911199211993119941199511996119971199811999120001200112002120031200412005120061200712008120091201012011120121201312014120151201612017120181201912020120211202212023120241202512026120271202812029120301203112032120331203412035120361203712038120391204012041120421204312044120451204612047120481204912050120511205212053120541205512056120571205812059120601206112062120631206412065120661206712068120691207012071120721207312074120751207612077120781207912080120811208212083120841208512086120871208812089120901209112092120931209412095120961209712098120991210012101121021210312104121051210612107121081210912110121111211212113121141211512116121171211812119121201212112122121231212412125121261212712128121291213012131121321213312134121351213612137121381213912140121411214212143121441214512146121471214812149121501215112152121531215412155121561215712158121591216012161121621216312164121651216612167121681216912170121711217212173121741217512176121771217812179121801218112182121831218412185121861218712188121891219012191121921219312194121951219612197121981219912200122011220212203122041220512206122071220812209122101221112212122131221412215122161221712218122191222012221122221222312224122251222612227122281222912230122311223212233122341223512236122371223812239122401224112242122431224412245122461224712248122491225012251122521225312254122551225612257122581225912260122611226212263122641226512266122671226812269122701227112272122731227412275122761227712278122791228012281122821228312284122851228612287122881228912290122911229212293122941229512296122971229812299123001230112302123031230412305123061230712308123091231012311123121231312314123151231612317123181231912320123211232212323123241232512326123271232812329123301233112332123331233412335123361233712338123391234012341123421234312344123451234612347123481234912350123511235212353123541235512356123571235812359123601236112362123631236412365123661236712368123691237012371123721237312374123751237612377123781237912380123811238212383123841238512386123871238812389123901239112392123931239412395123961239712398123991240012401124021240312404124051240612407124081240912410124111241212413124141241512416124171241812419124201242112422124231242412425124261242712428124291243012431124321243312434124351243612437124381243912440124411244212443124441244512446124471244812449124501245112452124531245412455124561245712458124591246012461124621246312464124651246612467124681246912470124711247212473124741247512476124771247812479124801248112482124831248412485124861248712488124891249012491124921249312494124951249612497124981249912500125011250212503125041250512506125071250812509125101251112512125131251412515125161251712518125191252012521125221252312524125251252612527125281252912530125311253212533125341253512536125371253812539125401254112542125431254412545125461254712548125491255012551125521255312554125551255612557125581255912560125611256212563125641256512566125671256812569125701257112572125731257412575125761257712578125791258012581125821258312584125851258612587125881258912590125911259212593125941259512596125971259812599126001260112602126031260412605126061260712608126091261012611126121261312614126151261612617126181261912620126211262212623126241262512626126271262812629126301263112632126331263412635126361263712638126391264012641126421264312644126451264612647126481264912650126511265212653126541265512656126571265812659126601266112662126631266412665126661266712668126691267012671126721267312674126751267612677126781267912680126811268212683126841268512686126871268812689126901269112692126931269412695126961269712698126991270012701127021270312704127051270612707127081270912710127111271212713127141271512716127171271812719127201272112722127231272412725127261272712728127291273012731127321273312734127351273612737127381273912740127411274212743127441274512746127471274812749127501275112752127531275412755127561275712758127591276012761127621276312764127651276612767127681276912770127711277212773127741277512776127771277812779127801278112782127831278412785127861278712788127891279012791127921279312794127951279612797127981279912800128011280212803128041280512806128071280812809128101281112812128131281412815128161281712818128191282012821128221282312824128251282612827128281282912830128311283212833128341283512836128371283812839128401284112842128431284412845128461284712848128491285012851128521285312854128551285612857128581285912860128611286212863128641286512866128671286812869128701287112872128731287412875128761287712878128791288012881128821288312884128851288612887128881288912890128911289212893128941289512896128971289812899129001290112902129031290412905129061290712908129091291012911129121291312914129151291612917129181291912920129211292212923129241292512926129271292812929129301293112932129331293412935129361293712938129391294012941129421294312944129451294612947129481294912950129511295212953129541295512956129571295812959129601296112962129631296412965129661296712968129691297012971129721297312974129751297612977129781297912980129811298212983129841298512986129871298812989129901299112992129931299412995129961299712998129991300013001130021300313004130051300613007130081300913010130111301213013130141301513016130171301813019130201302113022130231302413025130261302713028130291303013031130321303313034130351303613037130381303913040130411304213043130441304513046130471304813049130501305113052130531305413055130561305713058130591306013061130621306313064130651306613067130681306913070130711307213073130741307513076130771307813079130801308113082130831308413085130861308713088130891309013091130921309313094130951309613097130981309913100131011310213103131041310513106131071310813109131101311113112131131311413115131161311713118131191312013121131221312313124131251312613127131281312913130131311313213133131341313513136131371313813139131401314113142131431314413145131461314713148131491315013151131521315313154131551315613157131581315913160131611316213163131641316513166131671316813169131701317113172131731317413175131761317713178131791318013181131821318313184131851318613187131881318913190131911319213193131941319513196131971319813199132001320113202132031320413205132061320713208132091321013211132121321313214132151321613217132181321913220132211322213223132241322513226132271322813229132301323113232132331323413235132361323713238132391324013241132421324313244132451324613247132481324913250132511325213253132541325513256132571325813259132601326113262132631326413265132661326713268132691327013271132721327313274132751327613277132781327913280132811328213283132841328513286132871328813289132901329113292132931329413295132961329713298132991330013301133021330313304133051330613307133081330913310133111331213313133141331513316133171331813319133201332113322133231332413325133261332713328133291333013331133321333313334133351333613337133381333913340133411334213343133441334513346133471334813349133501335113352133531335413355133561335713358133591336013361133621336313364133651336613367133681336913370133711337213373133741337513376133771337813379133801338113382133831338413385133861338713388133891339013391133921339313394133951339613397133981339913400134011340213403134041340513406134071340813409134101341113412134131341413415134161341713418134191342013421134221342313424134251342613427134281342913430134311343213433134341343513436134371343813439134401344113442134431344413445134461344713448134491345013451134521345313454134551345613457134581345913460134611346213463134641346513466134671346813469134701347113472134731347413475134761347713478134791348013481134821348313484134851348613487134881348913490134911349213493134941349513496134971349813499135001350113502135031350413505135061350713508135091351013511135121351313514135151351613517135181351913520135211352213523135241352513526135271352813529135301353113532135331353413535135361353713538135391354013541135421354313544135451354613547135481354913550135511355213553135541355513556135571355813559135601356113562135631356413565135661356713568135691357013571135721357313574135751357613577135781357913580135811358213583135841358513586135871358813589135901359113592135931359413595135961359713598135991360013601136021360313604136051360613607136081360913610136111361213613136141361513616136171361813619136201362113622136231362413625136261362713628136291363013631136321363313634136351363613637136381363913640136411364213643136441364513646136471364813649136501365113652136531365413655136561365713658136591366013661136621366313664136651366613667136681366913670136711367213673136741367513676136771367813679136801368113682136831368413685136861368713688136891369013691136921369313694136951369613697136981369913700137011370213703137041370513706137071370813709137101371113712137131371413715137161371713718137191372013721137221372313724137251372613727137281372913730137311373213733137341373513736137371373813739137401374113742137431374413745137461374713748137491375013751137521375313754137551375613757137581375913760137611376213763137641376513766137671376813769137701377113772137731377413775137761377713778137791378013781137821378313784137851378613787137881378913790137911379213793137941379513796137971379813799138001380113802138031380413805138061380713808138091381013811138121381313814138151381613817138181381913820138211382213823138241382513826138271382813829138301383113832138331383413835138361383713838138391384013841138421384313844138451384613847138481384913850138511385213853138541385513856138571385813859138601386113862138631386413865138661386713868138691387013871138721387313874138751387613877138781387913880138811388213883138841388513886138871388813889138901389113892138931389413895138961389713898138991390013901139021390313904139051390613907139081390913910139111391213913139141391513916139171391813919139201392113922139231392413925139261392713928139291393013931139321393313934139351393613937139381393913940139411394213943139441394513946139471394813949139501395113952139531395413955139561395713958139591396013961139621396313964139651396613967139681396913970139711397213973139741397513976139771397813979139801398113982139831398413985139861398713988139891399013991139921399313994139951399613997139981399914000140011400214003140041400514006140071400814009140101401114012140131401414015140161401714018140191402014021140221402314024140251402614027140281402914030140311403214033140341403514036140371403814039140401404114042140431404414045140461404714048140491405014051140521405314054140551405614057140581405914060140611406214063140641406514066140671406814069140701407114072140731407414075140761407714078140791408014081140821408314084140851408614087140881408914090140911409214093140941409514096140971409814099141001410114102141031410414105141061410714108141091411014111141121411314114141151411614117141181411914120141211412214123141241412514126141271412814129141301413114132141331413414135141361413714138141391414014141141421414314144141451414614147141481414914150141511415214153141541415514156141571415814159141601416114162141631416414165141661416714168141691417014171141721417314174141751417614177141781417914180141811418214183141841418514186141871418814189141901419114192141931419414195141961419714198141991420014201142021420314204142051420614207142081420914210142111421214213142141421514216142171421814219142201422114222142231422414225142261422714228142291423014231142321423314234142351423614237142381423914240142411424214243142441424514246142471424814249142501425114252142531425414255142561425714258142591426014261142621426314264142651426614267142681426914270142711427214273142741427514276142771427814279142801428114282142831428414285142861428714288142891429014291142921429314294142951429614297142981429914300143011430214303143041430514306143071430814309143101431114312143131431414315143161431714318143191432014321143221432314324143251432614327143281432914330143311433214333143341433514336143371433814339143401434114342143431434414345143461434714348143491435014351143521435314354143551435614357143581435914360143611436214363143641436514366143671436814369143701437114372143731437414375143761437714378143791438014381143821438314384143851438614387143881438914390143911439214393143941439514396143971439814399144001440114402144031440414405144061440714408144091441014411144121441314414144151441614417144181441914420144211442214423144241442514426144271442814429144301443114432144331443414435144361443714438144391444014441144421444314444144451444614447144481444914450144511445214453144541445514456144571445814459144601446114462144631446414465144661446714468144691447014471144721447314474144751447614477144781447914480144811448214483144841448514486144871448814489144901449114492144931449414495144961449714498144991450014501145021450314504145051450614507145081450914510145111451214513145141451514516145171451814519145201452114522145231452414525145261452714528145291453014531145321453314534145351453614537145381453914540145411454214543145441454514546145471454814549145501455114552145531455414555145561455714558145591456014561145621456314564145651456614567145681456914570145711457214573145741457514576145771457814579145801458114582145831458414585145861458714588145891459014591145921459314594145951459614597145981459914600146011460214603146041460514606146071460814609146101461114612146131461414615146161461714618146191462014621146221462314624146251462614627146281462914630146311463214633146341463514636146371463814639146401464114642146431464414645146461464714648146491465014651146521465314654146551465614657146581465914660146611466214663146641466514666146671466814669146701467114672146731467414675146761467714678146791468014681146821468314684146851468614687146881468914690146911469214693146941469514696146971469814699147001470114702147031470414705147061470714708147091471014711147121471314714147151471614717147181471914720147211472214723147241472514726147271472814729147301473114732147331473414735147361473714738147391474014741147421474314744147451474614747147481474914750147511475214753147541475514756147571475814759147601476114762147631476414765147661476714768147691477014771147721477314774147751477614777147781477914780147811478214783147841478514786147871478814789147901479114792147931479414795147961479714798147991480014801148021480314804148051480614807148081480914810148111481214813148141481514816148171481814819148201482114822148231482414825148261482714828148291483014831148321483314834148351483614837148381483914840148411484214843148441484514846148471484814849148501485114852148531485414855148561485714858148591486014861148621486314864148651486614867148681486914870148711487214873148741487514876148771487814879148801488114882148831488414885148861488714888148891489014891148921489314894148951489614897148981489914900149011490214903149041490514906149071490814909149101491114912149131491414915149161491714918149191492014921149221492314924149251492614927149281492914930149311493214933149341493514936149371493814939149401494114942149431494414945149461494714948149491495014951149521495314954149551495614957149581495914960149611496214963149641496514966149671496814969149701497114972149731497414975149761497714978149791498014981149821498314984149851498614987149881498914990149911499214993149941499514996149971499814999150001500115002150031500415005150061500715008150091501015011150121501315014150151501615017150181501915020150211502215023150241502515026150271502815029150301503115032150331503415035150361503715038150391504015041150421504315044150451504615047150481504915050150511505215053150541505515056150571505815059150601506115062150631506415065150661506715068150691507015071150721507315074150751507615077150781507915080150811508215083150841508515086150871508815089150901509115092150931509415095150961509715098150991510015101151021510315104151051510615107151081510915110151111511215113151141511515116151171511815119151201512115122151231512415125151261512715128151291513015131151321513315134151351513615137151381513915140151411514215143151441514515146151471514815149151501515115152151531515415155151561515715158151591516015161151621516315164151651516615167151681516915170151711517215173151741517515176151771517815179151801518115182151831518415185151861518715188151891519015191151921519315194151951519615197151981519915200152011520215203152041520515206152071520815209152101521115212152131521415215152161521715218152191522015221152221522315224152251522615227152281522915230152311523215233152341523515236152371523815239152401524115242152431524415245152461524715248152491525015251152521525315254152551525615257152581525915260152611526215263152641526515266152671526815269152701527115272152731527415275152761527715278152791528015281152821528315284152851528615287152881528915290152911529215293152941529515296152971529815299153001530115302153031530415305153061530715308153091531015311153121531315314153151531615317153181531915320153211532215323153241532515326153271532815329153301533115332153331533415335153361533715338153391534015341153421534315344153451534615347153481534915350153511535215353153541535515356153571535815359153601536115362153631536415365153661536715368153691537015371153721537315374153751537615377153781537915380153811538215383153841538515386153871538815389153901539115392153931539415395153961539715398153991540015401154021540315404154051540615407154081540915410154111541215413154141541515416154171541815419154201542115422154231542415425154261542715428154291543015431154321543315434154351543615437154381543915440154411544215443154441544515446154471544815449154501545115452154531545415455154561545715458154591546015461154621546315464154651546615467154681546915470154711547215473154741547515476154771547815479154801548115482154831548415485154861548715488154891549015491154921549315494154951549615497154981549915500155011550215503155041550515506155071550815509155101551115512155131551415515155161551715518155191552015521155221552315524155251552615527155281552915530155311553215533155341553515536155371553815539155401554115542155431554415545155461554715548155491555015551155521555315554155551555615557155581555915560155611556215563155641556515566155671556815569155701557115572155731557415575155761557715578155791558015581155821558315584155851558615587155881558915590155911559215593155941559515596155971559815599156001560115602156031560415605156061560715608156091561015611156121561315614156151561615617156181561915620156211562215623156241562515626156271562815629156301563115632156331563415635156361563715638156391564015641156421564315644156451564615647156481564915650156511565215653156541565515656156571565815659156601566115662156631566415665156661566715668156691567015671156721567315674156751567615677156781567915680156811568215683156841568515686156871568815689156901569115692156931569415695156961569715698156991570015701157021570315704157051570615707157081570915710157111571215713157141571515716157171571815719157201572115722157231572415725157261572715728157291573015731157321573315734157351573615737157381573915740157411574215743157441574515746157471574815749157501575115752157531575415755157561575715758157591576015761157621576315764157651576615767157681576915770157711577215773157741577515776157771577815779157801578115782157831578415785157861578715788157891579015791157921579315794157951579615797157981579915800158011580215803158041580515806158071580815809158101581115812158131581415815158161581715818158191582015821158221582315824158251582615827158281582915830158311583215833158341583515836158371583815839158401584115842158431584415845158461584715848158491585015851158521585315854158551585615857158581585915860158611586215863158641586515866158671586815869158701587115872158731587415875158761587715878158791588015881158821588315884158851588615887158881588915890158911589215893158941589515896158971589815899159001590115902159031590415905159061590715908159091591015911159121591315914159151591615917159181591915920159211592215923159241592515926159271592815929159301593115932159331593415935159361593715938159391594015941159421594315944159451594615947159481594915950159511595215953159541595515956159571595815959159601596115962159631596415965159661596715968159691597015971159721597315974159751597615977159781597915980159811598215983159841598515986159871598815989159901599115992159931599415995159961599715998159991600016001160021600316004160051600616007160081600916010160111601216013160141601516016160171601816019160201602116022160231602416025160261602716028160291603016031160321603316034160351603616037160381603916040160411604216043160441604516046160471604816049160501605116052160531605416055160561605716058160591606016061160621606316064160651606616067160681606916070160711607216073160741607516076160771607816079160801608116082160831608416085160861608716088160891609016091160921609316094160951609616097160981609916100161011610216103161041610516106161071610816109161101611116112161131611416115161161611716118161191612016121161221612316124161251612616127161281612916130161311613216133161341613516136161371613816139161401614116142161431614416145161461614716148161491615016151161521615316154161551615616157161581615916160161611616216163161641616516166161671616816169161701617116172161731617416175161761617716178161791618016181161821618316184161851618616187161881618916190161911619216193161941619516196161971619816199162001620116202162031620416205162061620716208162091621016211162121621316214162151621616217162181621916220162211622216223162241622516226162271622816229162301623116232162331623416235162361623716238162391624016241162421624316244162451624616247162481624916250162511625216253162541625516256162571625816259162601626116262162631626416265162661626716268162691627016271162721627316274162751627616277162781627916280162811628216283162841628516286162871628816289162901629116292162931629416295162961629716298162991630016301163021630316304163051630616307163081630916310163111631216313163141631516316163171631816319163201632116322163231632416325163261632716328163291633016331163321633316334163351633616337163381633916340163411634216343163441634516346163471634816349163501635116352163531635416355163561635716358163591636016361163621636316364163651636616367163681636916370163711637216373163741637516376163771637816379163801638116382163831638416385163861638716388163891639016391163921639316394163951639616397163981639916400164011640216403164041640516406164071640816409164101641116412164131641416415164161641716418164191642016421164221642316424164251642616427164281642916430164311643216433164341643516436164371643816439164401644116442164431644416445164461644716448164491645016451164521645316454164551645616457164581645916460164611646216463164641646516466164671646816469164701647116472164731647416475164761647716478164791648016481164821648316484164851648616487164881648916490164911649216493164941649516496164971649816499165001650116502165031650416505165061650716508165091651016511165121651316514165151651616517165181651916520165211652216523165241652516526165271652816529165301653116532165331653416535165361653716538165391654016541165421654316544165451654616547165481654916550165511655216553165541655516556165571655816559165601656116562165631656416565165661656716568165691657016571165721657316574165751657616577165781657916580165811658216583165841658516586165871658816589165901659116592165931659416595165961659716598165991660016601166021660316604166051660616607166081660916610166111661216613166141661516616166171661816619166201662116622166231662416625166261662716628166291663016631166321663316634166351663616637166381663916640166411664216643166441664516646166471664816649166501665116652166531665416655166561665716658166591666016661166621666316664166651666616667166681666916670166711667216673166741667516676166771667816679166801668116682166831668416685166861668716688166891669016691166921669316694166951669616697166981669916700167011670216703167041670516706167071670816709167101671116712167131671416715167161671716718167191672016721167221672316724167251672616727167281672916730167311673216733167341673516736167371673816739167401674116742167431674416745167461674716748167491675016751167521675316754167551675616757167581675916760167611676216763167641676516766167671676816769167701677116772167731677416775167761677716778167791678016781167821678316784167851678616787167881678916790167911679216793167941679516796167971679816799168001680116802168031680416805168061680716808168091681016811168121681316814168151681616817168181681916820168211682216823168241682516826168271682816829168301683116832168331683416835168361683716838168391684016841168421684316844168451684616847168481684916850168511685216853168541685516856168571685816859168601686116862168631686416865168661686716868168691687016871168721687316874168751687616877168781687916880168811688216883168841688516886168871688816889168901689116892168931689416895168961689716898168991690016901169021690316904169051690616907169081690916910169111691216913169141691516916169171691816919169201692116922169231692416925169261692716928169291693016931169321693316934169351693616937169381693916940169411694216943169441694516946169471694816949169501695116952169531695416955169561695716958169591696016961169621696316964169651696616967169681696916970169711697216973169741697516976169771697816979169801698116982169831698416985169861698716988169891699016991169921699316994169951699616997169981699917000170011700217003170041700517006170071700817009170101701117012170131701417015170161701717018170191702017021170221702317024170251702617027170281702917030170311703217033170341703517036170371703817039170401704117042170431704417045170461704717048170491705017051170521705317054170551705617057170581705917060170611706217063170641706517066170671706817069170701707117072170731707417075170761707717078170791708017081170821708317084170851708617087170881708917090170911709217093170941709517096170971709817099171001710117102171031710417105171061710717108171091711017111171121711317114171151711617117171181711917120171211712217123171241712517126171271712817129171301713117132171331713417135171361713717138171391714017141171421714317144171451714617147171481714917150171511715217153171541715517156171571715817159171601716117162171631716417165171661716717168171691717017171171721717317174171751717617177171781717917180171811718217183171841718517186171871718817189171901719117192171931719417195171961719717198171991720017201172021720317204172051720617207172081720917210172111721217213172141721517216172171721817219172201722117222172231722417225172261722717228172291723017231172321723317234172351723617237172381723917240172411724217243172441724517246172471724817249172501725117252172531725417255172561725717258172591726017261172621726317264172651726617267172681726917270172711727217273172741727517276172771727817279172801728117282172831728417285172861728717288172891729017291172921729317294172951729617297172981729917300173011730217303173041730517306173071730817309173101731117312173131731417315173161731717318173191732017321173221732317324173251732617327173281732917330173311733217333173341733517336173371733817339173401734117342173431734417345173461734717348173491735017351173521735317354173551735617357173581735917360173611736217363173641736517366173671736817369173701737117372173731737417375173761737717378173791738017381173821738317384173851738617387173881738917390173911739217393173941739517396173971739817399174001740117402174031740417405174061740717408174091741017411174121741317414174151741617417174181741917420174211742217423174241742517426174271742817429174301743117432174331743417435174361743717438174391744017441174421744317444174451744617447174481744917450174511745217453174541745517456174571745817459174601746117462174631746417465174661746717468174691747017471174721747317474174751747617477174781747917480174811748217483174841748517486174871748817489174901749117492174931749417495174961749717498174991750017501175021750317504175051750617507175081750917510175111751217513175141751517516175171751817519175201752117522175231752417525175261752717528175291753017531175321753317534175351753617537175381753917540175411754217543175441754517546175471754817549175501755117552175531755417555175561755717558175591756017561175621756317564175651756617567175681756917570175711757217573175741757517576175771757817579175801758117582175831758417585175861758717588175891759017591175921759317594175951759617597175981759917600176011760217603176041760517606176071760817609176101761117612176131761417615176161761717618176191762017621176221762317624176251762617627176281762917630176311763217633176341763517636176371763817639176401764117642176431764417645176461764717648176491765017651176521765317654176551765617657176581765917660176611766217663176641766517666176671766817669176701767117672176731767417675176761767717678176791768017681176821768317684176851768617687176881768917690176911769217693176941769517696176971769817699177001770117702177031770417705177061770717708177091771017711177121771317714177151771617717177181771917720177211772217723177241772517726177271772817729177301773117732177331773417735177361773717738177391774017741177421774317744177451774617747177481774917750177511775217753177541775517756177571775817759177601776117762177631776417765177661776717768177691777017771177721777317774177751777617777177781777917780177811778217783177841778517786177871778817789177901779117792177931779417795177961779717798177991780017801178021780317804178051780617807178081780917810178111781217813178141781517816178171781817819178201782117822178231782417825178261782717828178291783017831178321783317834178351783617837178381783917840178411784217843178441784517846178471784817849178501785117852178531785417855178561785717858178591786017861178621786317864178651786617867178681786917870178711787217873178741787517876178771787817879178801788117882178831788417885178861788717888178891789017891178921789317894178951789617897178981789917900179011790217903179041790517906179071790817909179101791117912179131791417915179161791717918179191792017921179221792317924179251792617927179281792917930179311793217933179341793517936179371793817939179401794117942179431794417945179461794717948179491795017951179521795317954179551795617957179581795917960179611796217963179641796517966179671796817969179701797117972179731797417975179761797717978179791798017981179821798317984179851798617987179881798917990179911799217993179941799517996179971799817999180001800118002180031800418005180061800718008180091801018011180121801318014180151801618017180181801918020180211802218023180241802518026180271802818029180301803118032180331803418035180361803718038180391804018041180421804318044180451804618047180481804918050180511805218053180541805518056180571805818059180601806118062180631806418065180661806718068180691807018071180721807318074180751807618077180781807918080180811808218083180841808518086180871808818089180901809118092180931809418095180961809718098180991810018101181021810318104181051810618107181081810918110181111811218113181141811518116181171811818119181201812118122181231812418125181261812718128181291813018131181321813318134181351813618137181381813918140181411814218143181441814518146181471814818149181501815118152181531815418155181561815718158181591816018161181621816318164181651816618167181681816918170181711817218173181741817518176181771817818179181801818118182181831818418185181861818718188181891819018191181921819318194181951819618197181981819918200182011820218203182041820518206182071820818209182101821118212182131821418215182161821718218182191822018221182221822318224182251822618227182281822918230182311823218233182341823518236182371823818239182401824118242182431824418245182461824718248182491825018251182521825318254182551825618257182581825918260182611826218263182641826518266182671826818269182701827118272182731827418275182761827718278182791828018281182821828318284182851828618287182881828918290182911829218293182941829518296182971829818299183001830118302183031830418305183061830718308183091831018311183121831318314183151831618317183181831918320183211832218323183241832518326183271832818329183301833118332183331833418335183361833718338183391834018341183421834318344183451834618347183481834918350183511835218353183541835518356183571835818359183601836118362183631836418365183661836718368183691837018371183721837318374183751837618377183781837918380183811838218383183841838518386183871838818389183901839118392183931839418395183961839718398183991840018401184021840318404184051840618407184081840918410184111841218413184141841518416184171841818419184201842118422184231842418425184261842718428184291843018431184321843318434184351843618437184381843918440184411844218443184441844518446184471844818449184501845118452184531845418455184561845718458184591846018461184621846318464184651846618467184681846918470184711847218473184741847518476184771847818479184801848118482184831848418485184861848718488184891849018491184921849318494184951849618497184981849918500185011850218503185041850518506185071850818509185101851118512185131851418515185161851718518185191852018521185221852318524185251852618527185281852918530185311853218533185341853518536185371853818539185401854118542185431854418545185461854718548185491855018551185521855318554185551855618557185581855918560185611856218563185641856518566185671856818569185701857118572185731857418575185761857718578185791858018581185821858318584185851858618587185881858918590185911859218593185941859518596185971859818599186001860118602186031860418605186061860718608186091861018611186121861318614186151861618617186181861918620186211862218623186241862518626186271862818629186301863118632186331863418635186361863718638186391864018641186421864318644186451864618647186481864918650186511865218653186541865518656186571865818659186601866118662186631866418665186661866718668186691867018671186721867318674186751867618677186781867918680186811868218683186841868518686186871868818689186901869118692186931869418695186961869718698186991870018701187021870318704187051870618707187081870918710187111871218713187141871518716187171871818719187201872118722187231872418725187261872718728187291873018731187321873318734187351873618737187381873918740187411874218743187441874518746187471874818749187501875118752187531875418755187561875718758187591876018761187621876318764187651876618767187681876918770187711877218773187741877518776187771877818779187801878118782187831878418785187861878718788187891879018791187921879318794187951879618797187981879918800188011880218803188041880518806188071880818809188101881118812188131881418815188161881718818188191882018821188221882318824188251882618827188281882918830188311883218833188341883518836188371883818839188401884118842188431884418845188461884718848188491885018851188521885318854188551885618857188581885918860188611886218863188641886518866188671886818869188701887118872188731887418875188761887718878188791888018881188821888318884188851888618887188881888918890188911889218893188941889518896188971889818899189001890118902189031890418905189061890718908189091891018911189121891318914189151891618917189181891918920189211892218923189241892518926189271892818929189301893118932189331893418935189361893718938189391894018941189421894318944189451894618947189481894918950189511895218953189541895518956189571895818959189601896118962189631896418965189661896718968189691897018971189721897318974189751897618977189781897918980189811898218983189841898518986189871898818989189901899118992189931899418995189961899718998189991900019001190021900319004190051900619007190081900919010190111901219013190141901519016190171901819019190201902119022190231902419025190261902719028190291903019031190321903319034190351903619037190381903919040190411904219043190441904519046190471904819049190501905119052190531905419055190561905719058190591906019061190621906319064190651906619067190681906919070190711907219073190741907519076190771907819079190801908119082190831908419085190861908719088190891909019091190921909319094190951909619097190981909919100191011910219103191041910519106191071910819109191101911119112191131911419115191161911719118191191912019121191221912319124191251912619127191281912919130191311913219133191341913519136191371913819139191401914119142191431914419145191461914719148191491915019151191521915319154191551915619157191581915919160191611916219163191641916519166191671916819169191701917119172191731917419175191761917719178191791918019181191821918319184191851918619187191881918919190191911919219193191941919519196191971919819199192001920119202192031920419205192061920719208192091921019211192121921319214192151921619217192181921919220192211922219223192241922519226192271922819229192301923119232192331923419235192361923719238192391924019241192421924319244192451924619247192481924919250192511925219253192541925519256192571925819259192601926119262192631926419265192661926719268192691927019271192721927319274192751927619277192781927919280192811928219283192841928519286192871928819289192901929119292192931929419295192961929719298192991930019301193021930319304193051930619307193081930919310193111931219313193141931519316193171931819319193201932119322193231932419325193261932719328193291933019331193321933319334193351933619337193381933919340193411934219343193441934519346193471934819349193501935119352193531935419355193561935719358193591936019361193621936319364193651936619367193681936919370193711937219373193741937519376193771937819379193801938119382193831938419385193861938719388193891939019391193921939319394193951939619397193981939919400194011940219403194041940519406194071940819409194101941119412194131941419415194161941719418194191942019421194221942319424194251942619427194281942919430194311943219433194341943519436194371943819439194401944119442194431944419445194461944719448194491945019451194521945319454194551945619457194581945919460194611946219463194641946519466194671946819469194701947119472194731947419475194761947719478194791948019481194821948319484194851948619487194881948919490194911949219493194941949519496194971949819499195001950119502195031950419505195061950719508195091951019511195121951319514195151951619517195181951919520195211952219523195241952519526195271952819529195301953119532195331953419535195361953719538195391954019541195421954319544195451954619547195481954919550195511955219553195541955519556195571955819559195601956119562195631956419565195661956719568195691957019571195721957319574195751957619577195781957919580195811958219583195841958519586195871958819589195901959119592195931959419595195961959719598195991960019601196021960319604196051960619607196081960919610196111961219613196141961519616196171961819619196201962119622196231962419625196261962719628196291963019631196321963319634196351963619637196381963919640196411964219643196441964519646196471964819649196501965119652196531965419655196561965719658196591966019661196621966319664196651966619667196681966919670196711967219673196741967519676196771967819679196801968119682196831968419685196861968719688196891969019691196921969319694196951969619697196981969919700197011970219703197041970519706197071970819709197101971119712197131971419715197161971719718197191972019721197221972319724197251972619727197281972919730197311973219733197341973519736197371973819739197401974119742197431974419745197461974719748197491975019751197521975319754197551975619757197581975919760197611976219763197641976519766197671976819769197701977119772197731977419775197761977719778197791978019781197821978319784197851978619787197881978919790197911979219793197941979519796197971979819799198001980119802198031980419805198061980719808198091981019811198121981319814198151981619817198181981919820198211982219823198241982519826198271982819829198301983119832198331983419835198361983719838198391984019841198421984319844198451984619847198481984919850198511985219853198541985519856198571985819859198601986119862198631986419865198661986719868198691987019871198721987319874198751987619877198781987919880198811988219883198841988519886198871988819889198901989119892198931989419895198961989719898198991990019901199021990319904199051990619907199081990919910199111991219913199141991519916199171991819919199201992119922199231992419925199261992719928199291993019931199321993319934199351993619937199381993919940199411994219943199441994519946199471994819949199501995119952199531995419955199561995719958199591996019961199621996319964199651996619967199681996919970199711997219973199741997519976199771997819979199801998119982199831998419985199861998719988199891999019991199921999319994199951999619997199981999920000200012000220003200042000520006200072000820009200102001120012200132001420015200162001720018200192002020021200222002320024200252002620027200282002920030200312003220033200342003520036200372003820039200402004120042200432004420045200462004720048200492005020051200522005320054200552005620057200582005920060200612006220063200642006520066200672006820069200702007120072200732007420075200762007720078200792008020081200822008320084200852008620087200882008920090200912009220093200942009520096200972009820099201002010120102201032010420105201062010720108201092011020111201122011320114201152011620117201182011920120201212012220123201242012520126201272012820129201302013120132201332013420135201362013720138201392014020141201422014320144201452014620147201482014920150201512015220153201542015520156201572015820159201602016120162201632016420165201662016720168201692017020171201722017320174201752017620177201782017920180201812018220183201842018520186201872018820189201902019120192201932019420195201962019720198201992020020201202022020320204202052020620207202082020920210202112021220213202142021520216202172021820219202202022120222202232022420225202262022720228202292023020231202322023320234202352023620237202382023920240202412024220243202442024520246202472024820249202502025120252202532025420255202562025720258202592026020261202622026320264202652026620267202682026920270202712027220273202742027520276202772027820279202802028120282202832028420285202862028720288202892029020291202922029320294202952029620297202982029920300203012030220303203042030520306203072030820309203102031120312203132031420315203162031720318203192032020321203222032320324203252032620327203282032920330203312033220333203342033520336203372033820339203402034120342203432034420345203462034720348203492035020351203522035320354203552035620357203582035920360203612036220363203642036520366203672036820369203702037120372203732037420375203762037720378203792038020381203822038320384203852038620387203882038920390203912039220393203942039520396203972039820399204002040120402204032040420405204062040720408204092041020411204122041320414204152041620417204182041920420204212042220423204242042520426204272042820429204302043120432204332043420435204362043720438204392044020441204422044320444204452044620447204482044920450204512045220453204542045520456204572045820459204602046120462204632046420465204662046720468204692047020471204722047320474204752047620477204782047920480204812048220483204842048520486204872048820489204902049120492204932049420495204962049720498204992050020501205022050320504205052050620507205082050920510205112051220513205142051520516205172051820519205202052120522205232052420525205262052720528205292053020531205322053320534205352053620537205382053920540205412054220543205442054520546205472054820549205502055120552205532055420555205562055720558205592056020561205622056320564205652056620567205682056920570205712057220573205742057520576205772057820579205802058120582205832058420585205862058720588205892059020591205922059320594205952059620597205982059920600206012060220603206042060520606206072060820609206102061120612206132061420615206162061720618206192062020621206222062320624206252062620627206282062920630206312063220633206342063520636206372063820639206402064120642206432064420645206462064720648206492065020651206522065320654206552065620657206582065920660206612066220663206642066520666206672066820669206702067120672206732067420675206762067720678206792068020681206822068320684206852068620687206882068920690206912069220693206942069520696206972069820699207002070120702207032070420705207062070720708207092071020711207122071320714207152071620717207182071920720207212072220723207242072520726207272072820729207302073120732207332073420735207362073720738207392074020741207422074320744207452074620747207482074920750207512075220753207542075520756207572075820759207602076120762207632076420765207662076720768207692077020771207722077320774207752077620777207782077920780207812078220783207842078520786207872078820789207902079120792207932079420795207962079720798207992080020801208022080320804208052080620807208082080920810208112081220813208142081520816208172081820819208202082120822208232082420825208262082720828208292083020831208322083320834208352083620837208382083920840208412084220843208442084520846208472084820849208502085120852208532085420855208562085720858208592086020861208622086320864208652086620867208682086920870208712087220873208742087520876208772087820879208802088120882208832088420885208862088720888208892089020891208922089320894208952089620897208982089920900209012090220903209042090520906209072090820909209102091120912209132091420915209162091720918209192092020921209222092320924209252092620927209282092920930209312093220933209342093520936209372093820939209402094120942209432094420945209462094720948209492095020951209522095320954209552095620957209582095920960209612096220963209642096520966209672096820969209702097120972209732097420975209762097720978209792098020981209822098320984209852098620987209882098920990209912099220993209942099520996209972099820999210002100121002210032100421005210062100721008210092101021011210122101321014210152101621017210182101921020210212102221023210242102521026210272102821029210302103121032210332103421035210362103721038210392104021041210422104321044210452104621047210482104921050210512105221053210542105521056210572105821059210602106121062210632106421065210662106721068210692107021071210722107321074210752107621077210782107921080210812108221083210842108521086210872108821089210902109121092210932109421095210962109721098210992110021101211022110321104211052110621107211082110921110211112111221113211142111521116211172111821119211202112121122211232112421125211262112721128211292113021131211322113321134211352113621137211382113921140211412114221143211442114521146211472114821149211502115121152211532115421155211562115721158211592116021161211622116321164211652116621167211682116921170211712117221173211742117521176211772117821179211802118121182211832118421185211862118721188211892119021191211922119321194211952119621197211982119921200212012120221203212042120521206212072120821209212102121121212212132121421215212162121721218212192122021221212222122321224212252122621227212282122921230212312123221233212342123521236212372123821239212402124121242212432124421245212462124721248212492125021251212522125321254212552125621257212582125921260212612126221263212642126521266212672126821269212702127121272212732127421275212762127721278212792128021281212822128321284212852128621287212882128921290212912129221293212942129521296212972129821299213002130121302213032130421305213062130721308213092131021311213122131321314213152131621317213182131921320213212132221323213242132521326213272132821329213302133121332213332133421335213362133721338213392134021341213422134321344213452134621347213482134921350213512135221353213542135521356213572135821359213602136121362213632136421365213662136721368213692137021371213722137321374213752137621377213782137921380213812138221383213842138521386213872138821389213902139121392213932139421395213962139721398213992140021401214022140321404214052140621407214082140921410214112141221413214142141521416214172141821419214202142121422214232142421425214262142721428214292143021431214322143321434214352143621437214382143921440214412144221443214442144521446214472144821449214502145121452214532145421455214562145721458214592146021461214622146321464214652146621467214682146921470214712147221473214742147521476214772147821479214802148121482214832148421485214862148721488214892149021491214922149321494214952149621497214982149921500215012150221503215042150521506215072150821509215102151121512215132151421515215162151721518215192152021521215222152321524215252152621527215282152921530215312153221533215342153521536215372153821539215402154121542215432154421545215462154721548215492155021551215522155321554215552155621557215582155921560215612156221563215642156521566215672156821569215702157121572215732157421575215762157721578215792158021581215822158321584215852158621587215882158921590215912159221593215942159521596215972159821599216002160121602216032160421605216062160721608216092161021611216122161321614216152161621617216182161921620216212162221623216242162521626216272162821629216302163121632216332163421635216362163721638216392164021641216422164321644216452164621647216482164921650216512165221653216542165521656216572165821659216602166121662216632166421665216662166721668216692167021671216722167321674216752167621677216782167921680216812168221683216842168521686216872168821689216902169121692216932169421695216962169721698216992170021701217022170321704217052170621707217082170921710217112171221713217142171521716217172171821719217202172121722217232172421725217262172721728217292173021731217322173321734217352173621737217382173921740217412174221743217442174521746217472174821749217502175121752217532175421755217562175721758217592176021761217622176321764217652176621767217682176921770217712177221773217742177521776217772177821779217802178121782217832178421785217862178721788217892179021791217922179321794217952179621797217982179921800218012180221803218042180521806218072180821809218102181121812218132181421815218162181721818218192182021821218222182321824218252182621827218282182921830218312183221833218342183521836218372183821839218402184121842218432184421845218462184721848218492185021851218522185321854218552185621857218582185921860218612186221863218642186521866218672186821869218702187121872218732187421875218762187721878218792188021881218822188321884218852188621887218882188921890218912189221893218942189521896218972189821899219002190121902219032190421905219062190721908219092191021911219122191321914219152191621917219182191921920219212192221923219242192521926219272192821929219302193121932219332193421935219362193721938219392194021941219422194321944219452194621947219482194921950219512195221953219542195521956219572195821959219602196121962219632196421965219662196721968219692197021971219722197321974219752197621977219782197921980219812198221983219842198521986219872198821989219902199121992219932199421995219962199721998219992200022001220022200322004220052200622007220082200922010220112201222013220142201522016220172201822019220202202122022220232202422025220262202722028220292203022031220322203322034220352203622037220382203922040220412204222043220442204522046220472204822049220502205122052220532205422055220562205722058220592206022061220622206322064220652206622067220682206922070220712207222073220742207522076220772207822079220802208122082220832208422085220862208722088220892209022091220922209322094220952209622097220982209922100221012210222103221042210522106221072210822109221102211122112221132211422115221162211722118221192212022121221222212322124221252212622127221282212922130221312213222133221342213522136221372213822139221402214122142221432214422145221462214722148221492215022151221522215322154221552215622157221582215922160221612216222163221642216522166221672216822169221702217122172221732217422175221762217722178221792218022181221822218322184221852218622187221882218922190221912219222193221942219522196221972219822199222002220122202222032220422205222062220722208222092221022211222122221322214222152221622217222182221922220222212222222223222242222522226222272222822229222302223122232222332223422235222362223722238222392224022241222422224322244222452224622247222482224922250222512225222253222542225522256222572225822259222602226122262222632226422265222662226722268222692227022271222722227322274222752227622277222782227922280222812228222283222842228522286222872228822289222902229122292222932229422295222962229722298222992230022301223022230322304223052230622307223082230922310223112231222313223142231522316223172231822319223202232122322223232232422325223262232722328223292233022331223322233322334223352233622337223382233922340223412234222343223442234522346223472234822349223502235122352223532235422355223562235722358223592236022361223622236322364223652236622367223682236922370223712237222373223742237522376223772237822379223802238122382223832238422385223862238722388223892239022391223922239322394223952239622397223982239922400224012240222403224042240522406224072240822409224102241122412224132241422415224162241722418224192242022421224222242322424224252242622427224282242922430224312243222433224342243522436224372243822439224402244122442224432244422445224462244722448224492245022451224522245322454224552245622457224582245922460224612246222463224642246522466224672246822469224702247122472224732247422475224762247722478224792248022481224822248322484224852248622487224882248922490224912249222493224942249522496224972249822499225002250122502225032250422505225062250722508225092251022511225122251322514225152251622517225182251922520225212252222523225242252522526225272252822529225302253122532225332253422535225362253722538225392254022541225422254322544225452254622547225482254922550225512255222553225542255522556225572255822559225602256122562225632256422565225662256722568225692257022571225722257322574225752257622577225782257922580225812258222583225842258522586225872258822589225902259122592225932259422595225962259722598225992260022601226022260322604226052260622607226082260922610226112261222613226142261522616226172261822619226202262122622226232262422625226262262722628226292263022631226322263322634226352263622637226382263922640226412264222643226442264522646226472264822649226502265122652226532265422655226562265722658226592266022661226622266322664226652266622667226682266922670226712267222673226742267522676226772267822679226802268122682226832268422685226862268722688226892269022691226922269322694226952269622697226982269922700227012270222703227042270522706227072270822709227102271122712227132271422715227162271722718227192272022721227222272322724227252272622727227282272922730227312273222733227342273522736227372273822739227402274122742227432274422745227462274722748227492275022751227522275322754227552275622757227582275922760227612276222763227642276522766227672276822769227702277122772227732277422775227762277722778227792278022781227822278322784227852278622787227882278922790227912279222793227942279522796227972279822799228002280122802228032280422805228062280722808228092281022811228122281322814228152281622817228182281922820228212282222823228242282522826228272282822829228302283122832228332283422835228362283722838228392284022841228422284322844228452284622847228482284922850228512285222853228542285522856228572285822859228602286122862228632286422865228662286722868228692287022871228722287322874228752287622877228782287922880228812288222883228842288522886228872288822889228902289122892228932289422895228962289722898228992290022901229022290322904229052290622907229082290922910229112291222913229142291522916229172291822919229202292122922229232292422925229262292722928229292293022931229322293322934229352293622937229382293922940229412294222943229442294522946229472294822949229502295122952229532295422955229562295722958229592296022961229622296322964229652296622967229682296922970229712297222973229742297522976229772297822979229802298122982229832298422985229862298722988229892299022991229922299322994229952299622997229982299923000230012300223003230042300523006230072300823009230102301123012230132301423015230162301723018230192302023021230222302323024230252302623027230282302923030230312303223033230342303523036230372303823039230402304123042230432304423045230462304723048230492305023051230522305323054230552305623057230582305923060230612306223063230642306523066230672306823069230702307123072230732307423075230762307723078230792308023081230822308323084230852308623087230882308923090230912309223093230942309523096230972309823099231002310123102231032310423105231062310723108231092311023111231122311323114231152311623117231182311923120231212312223123231242312523126231272312823129231302313123132231332313423135231362313723138231392314023141231422314323144231452314623147231482314923150231512315223153231542315523156231572315823159231602316123162231632316423165231662316723168231692317023171231722317323174231752317623177231782317923180231812318223183231842318523186231872318823189231902319123192231932319423195231962319723198231992320023201232022320323204232052320623207232082320923210232112321223213232142321523216232172321823219232202322123222232232322423225232262322723228232292323023231232322323323234232352323623237232382323923240232412324223243232442324523246232472324823249232502325123252232532325423255232562325723258232592326023261232622326323264232652326623267232682326923270232712327223273232742327523276232772327823279232802328123282232832328423285232862328723288232892329023291232922329323294232952329623297232982329923300233012330223303233042330523306233072330823309233102331123312233132331423315233162331723318233192332023321233222332323324233252332623327233282332923330233312333223333233342333523336233372333823339233402334123342233432334423345233462334723348233492335023351233522335323354233552335623357233582335923360233612336223363233642336523366233672336823369233702337123372233732337423375233762337723378233792338023381233822338323384233852338623387233882338923390233912339223393233942339523396233972339823399234002340123402234032340423405234062340723408234092341023411234122341323414234152341623417234182341923420234212342223423234242342523426234272342823429234302343123432234332343423435234362343723438234392344023441234422344323444234452344623447234482344923450234512345223453234542345523456234572345823459234602346123462234632346423465234662346723468234692347023471234722347323474234752347623477234782347923480234812348223483234842348523486234872348823489234902349123492234932349423495234962349723498234992350023501235022350323504235052350623507235082350923510235112351223513235142351523516235172351823519235202352123522235232352423525235262352723528235292353023531235322353323534235352353623537235382353923540235412354223543235442354523546235472354823549235502355123552235532355423555235562355723558235592356023561235622356323564235652356623567235682356923570235712357223573235742357523576235772357823579235802358123582235832358423585235862358723588235892359023591235922359323594235952359623597235982359923600236012360223603236042360523606236072360823609236102361123612236132361423615236162361723618236192362023621236222362323624236252362623627236282362923630236312363223633236342363523636236372363823639236402364123642236432364423645236462364723648236492365023651236522365323654236552365623657236582365923660236612366223663236642366523666236672366823669236702367123672236732367423675236762367723678236792368023681236822368323684236852368623687236882368923690236912369223693236942369523696236972369823699237002370123702237032370423705237062370723708237092371023711237122371323714237152371623717237182371923720237212372223723237242372523726237272372823729237302373123732237332373423735237362373723738237392374023741237422374323744237452374623747237482374923750237512375223753237542375523756237572375823759237602376123762237632376423765237662376723768237692377023771237722377323774237752377623777237782377923780237812378223783237842378523786237872378823789237902379123792237932379423795237962379723798237992380023801238022380323804238052380623807238082380923810238112381223813238142381523816238172381823819238202382123822238232382423825238262382723828238292383023831238322383323834238352383623837238382383923840238412384223843238442384523846238472384823849238502385123852238532385423855238562385723858238592386023861238622386323864238652386623867238682386923870238712387223873238742387523876238772387823879238802388123882238832388423885238862388723888238892389023891238922389323894238952389623897238982389923900239012390223903239042390523906239072390823909239102391123912239132391423915239162391723918239192392023921239222392323924239252392623927239282392923930239312393223933239342393523936239372393823939239402394123942239432394423945239462394723948239492395023951239522395323954239552395623957239582395923960239612396223963239642396523966239672396823969239702397123972239732397423975239762397723978239792398023981239822398323984239852398623987239882398923990239912399223993239942399523996239972399823999240002400124002240032400424005240062400724008240092401024011240122401324014240152401624017240182401924020240212402224023240242402524026240272402824029240302403124032240332403424035240362403724038240392404024041240422404324044240452404624047240482404924050240512405224053240542405524056240572405824059240602406124062240632406424065240662406724068240692407024071240722407324074240752407624077240782407924080240812408224083240842408524086240872408824089240902409124092240932409424095240962409724098240992410024101241022410324104241052410624107241082410924110241112411224113241142411524116241172411824119241202412124122241232412424125241262412724128241292413024131241322413324134241352413624137241382413924140241412414224143241442414524146241472414824149241502415124152241532415424155241562415724158241592416024161241622416324164241652416624167241682416924170241712417224173241742417524176241772417824179241802418124182241832418424185241862418724188241892419024191241922419324194241952419624197241982419924200242012420224203242042420524206242072420824209242102421124212242132421424215242162421724218242192422024221242222422324224242252422624227242282422924230242312423224233242342423524236242372423824239242402424124242242432424424245242462424724248242492425024251242522425324254242552425624257242582425924260242612426224263242642426524266242672426824269242702427124272242732427424275242762427724278242792428024281242822428324284242852428624287242882428924290242912429224293242942429524296242972429824299243002430124302243032430424305243062430724308243092431024311243122431324314243152431624317243182431924320243212432224323243242432524326243272432824329243302433124332243332433424335243362433724338243392434024341243422434324344243452434624347243482434924350243512435224353243542435524356243572435824359243602436124362243632436424365243662436724368243692437024371243722437324374243752437624377243782437924380243812438224383243842438524386243872438824389243902439124392243932439424395243962439724398243992440024401244022440324404244052440624407244082440924410244112441224413244142441524416244172441824419244202442124422244232442424425244262442724428244292443024431244322443324434244352443624437244382443924440244412444224443244442444524446244472444824449244502445124452244532445424455244562445724458244592446024461244622446324464244652446624467244682446924470244712447224473244742447524476244772447824479244802448124482244832448424485244862448724488244892449024491244922449324494244952449624497244982449924500245012450224503245042450524506245072450824509245102451124512245132451424515245162451724518245192452024521245222452324524245252452624527245282452924530245312453224533245342453524536245372453824539245402454124542245432454424545245462454724548245492455024551245522455324554245552455624557245582455924560245612456224563245642456524566245672456824569245702457124572245732457424575245762457724578245792458024581245822458324584245852458624587245882458924590245912459224593245942459524596245972459824599246002460124602246032460424605246062460724608246092461024611246122461324614246152461624617246182461924620246212462224623246242462524626246272462824629246302463124632246332463424635246362463724638246392464024641246422464324644246452464624647246482464924650246512465224653246542465524656246572465824659246602466124662246632466424665246662466724668246692467024671246722467324674246752467624677246782467924680246812468224683246842468524686246872468824689246902469124692246932469424695246962469724698246992470024701247022470324704247052470624707247082470924710247112471224713247142471524716247172471824719247202472124722247232472424725247262472724728247292473024731247322473324734247352473624737247382473924740247412474224743247442474524746247472474824749247502475124752247532475424755247562475724758247592476024761247622476324764247652476624767247682476924770247712477224773247742477524776247772477824779247802478124782247832478424785247862478724788247892479024791247922479324794247952479624797247982479924800248012480224803248042480524806248072480824809248102481124812248132481424815248162481724818248192482024821248222482324824248252482624827248282482924830248312483224833248342483524836248372483824839248402484124842248432484424845248462484724848248492485024851248522485324854248552485624857248582485924860248612486224863248642486524866248672486824869248702487124872248732487424875248762487724878248792488024881248822488324884248852488624887248882488924890248912489224893248942489524896248972489824899249002490124902249032490424905249062490724908249092491024911249122491324914249152491624917249182491924920249212492224923249242492524926249272492824929249302493124932249332493424935249362493724938249392494024941249422494324944249452494624947249482494924950249512495224953249542495524956249572495824959249602496124962249632496424965249662496724968249692497024971249722497324974249752497624977249782497924980249812498224983249842498524986249872498824989249902499124992249932499424995249962499724998249992500025001250022500325004250052500625007250082500925010250112501225013250142501525016250172501825019250202502125022250232502425025250262502725028250292503025031250322503325034250352503625037250382503925040250412504225043250442504525046250472504825049250502505125052250532505425055250562505725058250592506025061250622506325064250652506625067250682506925070250712507225073250742507525076250772507825079250802508125082250832508425085250862508725088250892509025091250922509325094250952509625097250982509925100251012510225103251042510525106251072510825109251102511125112251132511425115251162511725118251192512025121251222512325124251252512625127251282512925130251312513225133251342513525136251372513825139251402514125142251432514425145251462514725148251492515025151251522515325154251552515625157251582515925160251612516225163251642516525166251672516825169251702517125172251732517425175251762517725178251792518025181251822518325184251852518625187251882518925190251912519225193251942519525196251972519825199252002520125202252032520425205252062520725208252092521025211252122521325214252152521625217252182521925220252212522225223252242522525226252272522825229252302523125232252332523425235252362523725238252392524025241252422524325244252452524625247252482524925250252512525225253252542525525256252572525825259252602526125262252632526425265252662526725268252692527025271252722527325274252752527625277252782527925280252812528225283252842528525286252872528825289252902529125292252932529425295252962529725298252992530025301253022530325304253052530625307253082530925310253112531225313253142531525316253172531825319253202532125322253232532425325253262532725328253292533025331253322533325334253352533625337253382533925340253412534225343253442534525346253472534825349253502535125352253532535425355253562535725358253592536025361253622536325364253652536625367253682536925370253712537225373253742537525376253772537825379253802538125382253832538425385253862538725388253892539025391253922539325394253952539625397253982539925400254012540225403254042540525406254072540825409254102541125412254132541425415254162541725418254192542025421254222542325424254252542625427254282542925430254312543225433254342543525436254372543825439254402544125442254432544425445254462544725448254492545025451254522545325454254552545625457254582545925460254612546225463254642546525466254672546825469254702547125472254732547425475254762547725478254792548025481254822548325484254852548625487254882548925490254912549225493254942549525496254972549825499255002550125502255032550425505255062550725508255092551025511255122551325514255152551625517255182551925520255212552225523255242552525526255272552825529255302553125532255332553425535255362553725538255392554025541255422554325544255452554625547255482554925550255512555225553255542555525556255572555825559255602556125562255632556425565255662556725568255692557025571255722557325574255752557625577255782557925580255812558225583255842558525586255872558825589255902559125592255932559425595255962559725598255992560025601256022560325604256052560625607256082560925610256112561225613256142561525616256172561825619256202562125622256232562425625256262562725628256292563025631256322563325634256352563625637256382563925640256412564225643256442564525646256472564825649256502565125652256532565425655256562565725658256592566025661256622566325664256652566625667256682566925670256712567225673256742567525676256772567825679256802568125682256832568425685256862568725688256892569025691256922569325694256952569625697256982569925700257012570225703257042570525706257072570825709257102571125712257132571425715257162571725718257192572025721257222572325724257252572625727257282572925730257312573225733257342573525736257372573825739257402574125742257432574425745257462574725748257492575025751257522575325754257552575625757257582575925760257612576225763257642576525766257672576825769257702577125772257732577425775257762577725778257792578025781257822578325784257852578625787257882578925790257912579225793257942579525796257972579825799258002580125802258032580425805258062580725808258092581025811258122581325814258152581625817258182581925820258212582225823258242582525826258272582825829258302583125832258332583425835258362583725838258392584025841258422584325844258452584625847258482584925850258512585225853258542585525856258572585825859258602586125862258632586425865258662586725868258692587025871258722587325874258752587625877258782587925880258812588225883258842588525886258872588825889258902589125892258932589425895258962589725898258992590025901259022590325904259052590625907259082590925910259112591225913259142591525916259172591825919259202592125922259232592425925259262592725928259292593025931259322593325934259352593625937259382593925940259412594225943259442594525946259472594825949259502595125952259532595425955259562595725958259592596025961259622596325964259652596625967259682596925970259712597225973259742597525976259772597825979259802598125982259832598425985259862598725988259892599025991259922599325994259952599625997259982599926000260012600226003260042600526006260072600826009260102601126012260132601426015260162601726018260192602026021260222602326024260252602626027260282602926030260312603226033260342603526036260372603826039260402604126042260432604426045260462604726048260492605026051260522605326054260552605626057260582605926060260612606226063260642606526066260672606826069260702607126072260732607426075260762607726078260792608026081260822608326084260852608626087260882608926090260912609226093260942609526096260972609826099261002610126102261032610426105261062610726108261092611026111261122611326114261152611626117261182611926120261212612226123261242612526126261272612826129261302613126132261332613426135261362613726138261392614026141261422614326144261452614626147261482614926150261512615226153261542615526156261572615826159261602616126162261632616426165261662616726168261692617026171261722617326174261752617626177261782617926180261812618226183261842618526186261872618826189261902619126192261932619426195261962619726198261992620026201262022620326204262052620626207262082620926210262112621226213262142621526216262172621826219262202622126222262232622426225262262622726228262292623026231262322623326234262352623626237262382623926240262412624226243262442624526246262472624826249262502625126252262532625426255262562625726258262592626026261262622626326264262652626626267262682626926270262712627226273262742627526276262772627826279262802628126282262832628426285262862628726288262892629026291262922629326294262952629626297262982629926300263012630226303263042630526306263072630826309263102631126312263132631426315263162631726318263192632026321263222632326324263252632626327263282632926330263312633226333263342633526336263372633826339263402634126342263432634426345263462634726348263492635026351263522635326354263552635626357263582635926360263612636226363263642636526366263672636826369263702637126372263732637426375263762637726378263792638026381263822638326384263852638626387263882638926390263912639226393263942639526396263972639826399264002640126402264032640426405264062640726408264092641026411264122641326414264152641626417264182641926420264212642226423264242642526426264272642826429264302643126432264332643426435264362643726438264392644026441264422644326444264452644626447264482644926450264512645226453264542645526456264572645826459264602646126462264632646426465264662646726468264692647026471264722647326474264752647626477264782647926480264812648226483264842648526486264872648826489264902649126492264932649426495264962649726498264992650026501265022650326504265052650626507265082650926510265112651226513265142651526516265172651826519265202652126522265232652426525265262652726528265292653026531265322653326534265352653626537265382653926540265412654226543265442654526546265472654826549265502655126552265532655426555265562655726558265592656026561265622656326564265652656626567265682656926570265712657226573265742657526576265772657826579265802658126582265832658426585265862658726588265892659026591265922659326594265952659626597265982659926600266012660226603266042660526606266072660826609266102661126612266132661426615266162661726618266192662026621266222662326624266252662626627266282662926630266312663226633266342663526636266372663826639266402664126642266432664426645266462664726648266492665026651266522665326654266552665626657266582665926660266612666226663266642666526666266672666826669266702667126672266732667426675266762667726678266792668026681266822668326684266852668626687266882668926690266912669226693266942669526696266972669826699267002670126702267032670426705267062670726708267092671026711267122671326714267152671626717267182671926720267212672226723267242672526726267272672826729267302673126732267332673426735267362673726738267392674026741267422674326744267452674626747267482674926750267512675226753267542675526756267572675826759267602676126762267632676426765267662676726768267692677026771267722677326774267752677626777267782677926780267812678226783267842678526786267872678826789267902679126792267932679426795267962679726798267992680026801268022680326804268052680626807268082680926810268112681226813268142681526816268172681826819268202682126822268232682426825268262682726828268292683026831268322683326834268352683626837268382683926840268412684226843268442684526846268472684826849268502685126852268532685426855268562685726858268592686026861268622686326864268652686626867268682686926870268712687226873268742687526876268772687826879268802688126882268832688426885268862688726888268892689026891268922689326894268952689626897268982689926900269012690226903269042690526906269072690826909269102691126912269132691426915269162691726918269192692026921269222692326924269252692626927269282692926930269312693226933269342693526936269372693826939269402694126942269432694426945269462694726948269492695026951269522695326954269552695626957269582695926960269612696226963269642696526966269672696826969269702697126972269732697426975269762697726978269792698026981269822698326984269852698626987269882698926990269912699226993269942699526996269972699826999270002700127002270032700427005270062700727008270092701027011270122701327014270152701627017270182701927020270212702227023270242702527026270272702827029270302703127032270332703427035270362703727038270392704027041270422704327044270452704627047270482704927050270512705227053270542705527056270572705827059270602706127062270632706427065270662706727068270692707027071270722707327074270752707627077270782707927080270812708227083270842708527086270872708827089270902709127092270932709427095270962709727098270992710027101271022710327104271052710627107271082710927110271112711227113271142711527116271172711827119271202712127122271232712427125271262712727128271292713027131271322713327134271352713627137271382713927140271412714227143271442714527146271472714827149271502715127152271532715427155271562715727158271592716027161271622716327164271652716627167271682716927170271712717227173271742717527176271772717827179271802718127182271832718427185271862718727188271892719027191271922719327194271952719627197271982719927200272012720227203272042720527206272072720827209272102721127212272132721427215272162721727218272192722027221272222722327224272252722627227272282722927230272312723227233272342723527236272372723827239272402724127242272432724427245272462724727248272492725027251272522725327254272552725627257272582725927260272612726227263272642726527266272672726827269272702727127272272732727427275272762727727278272792728027281272822728327284272852728627287272882728927290272912729227293272942729527296272972729827299273002730127302273032730427305273062730727308273092731027311273122731327314273152731627317273182731927320273212732227323273242732527326273272732827329273302733127332273332733427335273362733727338273392734027341273422734327344273452734627347273482734927350273512735227353273542735527356273572735827359273602736127362273632736427365273662736727368273692737027371273722737327374273752737627377273782737927380273812738227383273842738527386273872738827389273902739127392273932739427395273962739727398273992740027401274022740327404274052740627407274082740927410274112741227413274142741527416274172741827419274202742127422274232742427425274262742727428274292743027431274322743327434274352743627437274382743927440274412744227443274442744527446274472744827449274502745127452274532745427455274562745727458274592746027461274622746327464274652746627467274682746927470274712747227473274742747527476274772747827479274802748127482274832748427485274862748727488274892749027491274922749327494274952749627497274982749927500275012750227503275042750527506275072750827509275102751127512275132751427515275162751727518275192752027521275222752327524275252752627527275282752927530275312753227533275342753527536275372753827539275402754127542275432754427545275462754727548275492755027551275522755327554275552755627557275582755927560275612756227563275642756527566275672756827569275702757127572275732757427575275762757727578275792758027581275822758327584275852758627587275882758927590275912759227593275942759527596275972759827599276002760127602276032760427605276062760727608276092761027611276122761327614276152761627617276182761927620276212762227623276242762527626276272762827629276302763127632276332763427635276362763727638276392764027641276422764327644276452764627647276482764927650276512765227653276542765527656276572765827659276602766127662276632766427665276662766727668276692767027671276722767327674276752767627677276782767927680276812768227683276842768527686276872768827689276902769127692276932769427695276962769727698276992770027701277022770327704277052770627707277082770927710277112771227713277142771527716277172771827719277202772127722277232772427725277262772727728277292773027731277322773327734277352773627737277382773927740277412774227743277442774527746277472774827749277502775127752277532775427755277562775727758277592776027761277622776327764277652776627767277682776927770277712777227773277742777527776277772777827779277802778127782277832778427785277862778727788277892779027791277922779327794277952779627797277982779927800278012780227803278042780527806278072780827809278102781127812278132781427815278162781727818278192782027821278222782327824278252782627827278282782927830278312783227833278342783527836278372783827839278402784127842278432784427845278462784727848278492785027851278522785327854278552785627857278582785927860278612786227863278642786527866278672786827869278702787127872278732787427875278762787727878278792788027881278822788327884278852788627887278882788927890278912789227893278942789527896278972789827899279002790127902279032790427905279062790727908279092791027911279122791327914279152791627917279182791927920279212792227923279242792527926279272792827929279302793127932279332793427935279362793727938279392794027941279422794327944279452794627947279482794927950279512795227953279542795527956279572795827959279602796127962279632796427965279662796727968279692797027971279722797327974279752797627977279782797927980279812798227983279842798527986279872798827989279902799127992279932799427995279962799727998279992800028001280022800328004280052800628007280082800928010280112801228013280142801528016280172801828019280202802128022280232802428025280262802728028280292803028031280322803328034280352803628037280382803928040280412804228043280442804528046280472804828049280502805128052280532805428055280562805728058280592806028061280622806328064280652806628067280682806928070280712807228073280742807528076280772807828079280802808128082280832808428085280862808728088280892809028091280922809328094280952809628097280982809928100281012810228103281042810528106281072810828109281102811128112281132811428115281162811728118281192812028121281222812328124281252812628127281282812928130281312813228133281342813528136281372813828139281402814128142281432814428145281462814728148281492815028151281522815328154281552815628157281582815928160281612816228163281642816528166281672816828169281702817128172281732817428175281762817728178281792818028181281822818328184281852818628187281882818928190281912819228193281942819528196281972819828199282002820128202282032820428205282062820728208282092821028211282122821328214282152821628217282182821928220282212822228223282242822528226282272822828229282302823128232282332823428235282362823728238282392824028241282422824328244282452824628247282482824928250282512825228253282542825528256282572825828259282602826128262282632826428265282662826728268282692827028271282722827328274282752827628277282782827928280282812828228283282842828528286282872828828289282902829128292282932829428295282962829728298282992830028301283022830328304283052830628307283082830928310283112831228313283142831528316283172831828319283202832128322283232832428325283262832728328283292833028331283322833328334283352833628337283382833928340283412834228343283442834528346283472834828349283502835128352283532835428355283562835728358283592836028361283622836328364283652836628367283682836928370283712837228373283742837528376283772837828379283802838128382283832838428385283862838728388283892839028391283922839328394283952839628397283982839928400284012840228403284042840528406284072840828409284102841128412284132841428415284162841728418284192842028421284222842328424284252842628427284282842928430284312843228433284342843528436284372843828439284402844128442284432844428445284462844728448284492845028451284522845328454284552845628457284582845928460284612846228463284642846528466284672846828469284702847128472284732847428475284762847728478284792848028481284822848328484284852848628487284882848928490284912849228493284942849528496284972849828499285002850128502285032850428505285062850728508285092851028511285122851328514285152851628517285182851928520285212852228523285242852528526285272852828529285302853128532285332853428535285362853728538285392854028541285422854328544285452854628547285482854928550285512855228553285542855528556285572855828559285602856128562285632856428565285662856728568285692857028571285722857328574285752857628577285782857928580285812858228583285842858528586285872858828589285902859128592285932859428595285962859728598285992860028601286022860328604286052860628607286082860928610286112861228613286142861528616286172861828619286202862128622286232862428625286262862728628286292863028631286322863328634286352863628637286382863928640286412864228643286442864528646286472864828649286502865128652286532865428655286562865728658286592866028661286622866328664286652866628667286682866928670286712867228673286742867528676286772867828679286802868128682286832868428685286862868728688286892869028691286922869328694286952869628697286982869928700287012870228703287042870528706287072870828709287102871128712287132871428715287162871728718287192872028721287222872328724287252872628727287282872928730287312873228733287342873528736287372873828739287402874128742287432874428745287462874728748287492875028751287522875328754287552875628757287582875928760287612876228763287642876528766287672876828769287702877128772287732877428775287762877728778287792878028781287822878328784287852878628787287882878928790287912879228793287942879528796287972879828799288002880128802288032880428805288062880728808288092881028811288122881328814288152881628817288182881928820288212882228823288242882528826288272882828829288302883128832288332883428835288362883728838288392884028841288422884328844288452884628847288482884928850288512885228853288542885528856288572885828859288602886128862288632886428865288662886728868288692887028871288722887328874288752887628877288782887928880288812888228883288842888528886288872888828889288902889128892288932889428895288962889728898288992890028901289022890328904289052890628907289082890928910289112891228913289142891528916289172891828919289202892128922289232892428925289262892728928289292893028931289322893328934289352893628937289382893928940289412894228943289442894528946289472894828949289502895128952289532895428955289562895728958289592896028961289622896328964289652896628967289682896928970289712897228973289742897528976289772897828979289802898128982289832898428985289862898728988289892899028991289922899328994289952899628997289982899929000290012900229003290042900529006290072900829009290102901129012290132901429015290162901729018290192902029021290222902329024290252902629027290282902929030290312903229033290342903529036290372903829039290402904129042290432904429045290462904729048290492905029051290522905329054290552905629057290582905929060290612906229063290642906529066290672906829069290702907129072290732907429075290762907729078290792908029081290822908329084290852908629087290882908929090290912909229093290942909529096290972909829099291002910129102291032910429105291062910729108291092911029111291122911329114291152911629117291182911929120291212912229123291242912529126291272912829129291302913129132291332913429135291362913729138291392914029141291422914329144291452914629147291482914929150291512915229153291542915529156291572915829159291602916129162291632916429165291662916729168291692917029171291722917329174291752917629177291782917929180291812918229183291842918529186291872918829189291902919129192291932919429195291962919729198291992920029201292022920329204292052920629207292082920929210292112921229213292142921529216292172921829219292202922129222292232922429225292262922729228292292923029231292322923329234292352923629237292382923929240292412924229243292442924529246292472924829249292502925129252292532925429255292562925729258292592926029261292622926329264292652926629267292682926929270292712927229273292742927529276292772927829279292802928129282292832928429285292862928729288292892929029291292922929329294292952929629297292982929929300293012930229303293042930529306293072930829309293102931129312293132931429315293162931729318293192932029321293222932329324293252932629327293282932929330293312933229333293342933529336293372933829339293402934129342293432934429345293462934729348293492935029351293522935329354293552935629357293582935929360293612936229363293642936529366293672936829369293702937129372293732937429375293762937729378293792938029381293822938329384293852938629387293882938929390293912939229393293942939529396293972939829399294002940129402294032940429405294062940729408294092941029411294122941329414294152941629417294182941929420294212942229423294242942529426294272942829429294302943129432294332943429435294362943729438294392944029441294422944329444294452944629447294482944929450294512945229453294542945529456294572945829459294602946129462294632946429465294662946729468294692947029471294722947329474294752947629477294782947929480294812948229483294842948529486294872948829489294902949129492294932949429495294962949729498294992950029501295022950329504295052950629507295082950929510295112951229513295142951529516295172951829519295202952129522295232952429525295262952729528295292953029531295322953329534295352953629537295382953929540295412954229543295442954529546295472954829549295502955129552295532955429555295562955729558295592956029561295622956329564295652956629567295682956929570295712957229573295742957529576295772957829579295802958129582295832958429585295862958729588295892959029591295922959329594295952959629597295982959929600296012960229603296042960529606296072960829609296102961129612296132961429615296162961729618296192962029621296222962329624
  1. (function(){
  2. /*!*************************************************************
  3. *
  4. * Firebug Lite 1.3.2
  5. *
  6. * Copyright (c) 2007, Parakey Inc.
  7. * Released under BSD license.
  8. * More information: http://getfirebug.com/firebuglite
  9. *
  10. **************************************************************/
  11. /*!
  12. * CSS selectors powered by:
  13. *
  14. * Sizzle CSS Selector Engine - v1.0
  15. * Copyright 2009, The Dojo Foundation
  16. * Released under the MIT, BSD, and GPL Licenses.
  17. * More information: http://sizzlejs.com/
  18. */
  19. /** @namespace describe lib */
  20. var FBL = {};
  21. /** @name ns @namespace */
  22. ( /** @scope ns-lib @this FBL */ function() {
  23. // ************************************************************************************************
  24. // ************************************************************************************************
  25. // Constants
  26. var productionDir = "http://getfirebug.com/releases/lite/";
  27. var bookmarkletVersion = 4;
  28. // ************************************************************************************************
  29. var reNotWhitespace = /[^\s]/;
  30. var reSplitFile = /:\/{1,3}(.*?)\/([^\/]*?)\/?($|\?.*)/;
  31. // Globals
  32. this.reJavascript = /\s*javascript:\s*(.*)/;
  33. this.reChrome = /chrome:\/\/([^\/]*)\//;
  34. this.reFile = /file:\/\/([^\/]*)\//;
  35. // ************************************************************************************************
  36. // properties
  37. var userAgent = navigator.userAgent.toLowerCase();
  38. this.isFirefox = /firefox/.test(userAgent);
  39. this.isOpera = /opera/.test(userAgent);
  40. this.isSafari = /webkit/.test(userAgent);
  41. this.isIE = /msie/.test(userAgent) && !/opera/.test(userAgent);
  42. this.isIE6 = /msie 6/i.test(navigator.appVersion);
  43. this.browserVersion = (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [0,'0'])[1];
  44. this.isIElt8 = this.isIE && (this.browserVersion-0 < 8);
  45. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  46. this.NS = null;
  47. this.pixelsPerInch = null;
  48. // ************************************************************************************************
  49. // Namespaces
  50. var namespaces = [];
  51. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  52. this.ns = function(fn)
  53. {
  54. var ns = {};
  55. namespaces.push(fn, ns);
  56. return ns;
  57. };
  58. var FBTrace = null;
  59. this.initialize = function()
  60. {
  61. // Firebug Lite is already running in persistent mode so we just quit
  62. if (window.firebug && firebug.firebuglite || window.console && console.firebuglite)
  63. return;
  64. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  65. // initialize environment
  66. // point the FBTrace object to the local variable
  67. if (FBL.FBTrace)
  68. FBTrace = FBL.FBTrace;
  69. else
  70. FBTrace = FBL.FBTrace = {};
  71. FBL.Ajax.initialize();
  72. // check if the actual window is a persisted chrome context
  73. var isChromeContext = window.Firebug && typeof window.Firebug.SharedEnv == "object";
  74. // chrome context of the persistent application
  75. if (isChromeContext)
  76. {
  77. // TODO: xxxpedro persist - make a better synchronization
  78. sharedEnv = window.Firebug.SharedEnv;
  79. delete window.Firebug.SharedEnv;
  80. FBL.Env = sharedEnv;
  81. FBL.Env.isChromeContext = true;
  82. FBTrace.messageQueue = FBL.Env.traceMessageQueue;
  83. }
  84. // non-persistent application
  85. else
  86. {
  87. FBL.NS = document.documentElement.namespaceURI;
  88. FBL.Env.browser = window;
  89. FBL.Env.destroy = destroyEnvironment;
  90. if (document.documentElement.getAttribute("debug") == "true")
  91. FBL.Env.Options.startOpened = true;
  92. // find the URL location of the loaded application
  93. findLocation();
  94. // TODO: get preferences here...
  95. var prefs = eval("(" + FBL.readCookie("FirebugLite") + ")");
  96. if (prefs)
  97. {
  98. FBL.Env.Options.startOpened = prefs.startOpened;
  99. FBL.Env.Options.enableTrace = prefs.enableTrace;
  100. FBL.Env.Options.enablePersistent = prefs.enablePersistent;
  101. FBL.Env.Options.disableXHRListener = prefs.disableXHRListener;
  102. }
  103. if (FBL.isFirefox &&
  104. typeof FBL.Env.browser.console == "object" &&
  105. FBL.Env.browser.console.firebug &&
  106. FBL.Env.Options.disableWhenFirebugActive)
  107. return;
  108. }
  109. // exposes the FBL to the global namespace when in debug mode
  110. if (FBL.Env.isDebugMode)
  111. {
  112. FBL.Env.browser.FBL = FBL;
  113. }
  114. // check browser compatibilities
  115. this.isQuiksMode = FBL.Env.browser.document.compatMode == "BackCompat";
  116. this.isIEQuiksMode = this.isIE && this.isQuiksMode;
  117. this.isIEStantandMode = this.isIE && !this.isQuiksMode;
  118. this.noFixedPosition = this.isIE6 || this.isIEQuiksMode;
  119. // after creating/synchronizing the environment, initialize the FBTrace module
  120. if (FBL.Env.Options.enableTrace) FBTrace.initialize();
  121. if (FBTrace.DBG_INITIALIZE && isChromeContext) FBTrace.sysout("FBL.initialize - persistent application", "initialize chrome context");
  122. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  123. // initialize namespaces
  124. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces BEGIN");
  125. for (var i = 0; i < namespaces.length; i += 2)
  126. {
  127. var fn = namespaces[i];
  128. var ns = namespaces[i+1];
  129. fn.apply(ns);
  130. }
  131. if (FBTrace.DBG_INITIALIZE) {
  132. FBTrace.sysout("FBL.initialize", namespaces.length/2+" namespaces END");
  133. FBTrace.sysout("FBL waitForDocument", "waiting document load");
  134. }
  135. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  136. // finish environment initialization
  137. FBL.Firebug.loadPrefs(prefs);
  138. if (FBL.Env.Options.enablePersistent)
  139. {
  140. // TODO: xxxpedro persist - make a better synchronization
  141. if (isChromeContext)
  142. {
  143. FBL.FirebugChrome.clone(FBL.Env.FirebugChrome);
  144. }
  145. else
  146. {
  147. FBL.Env.FirebugChrome = FBL.FirebugChrome;
  148. FBL.Env.traceMessageQueue = FBTrace.messageQueue;
  149. }
  150. }
  151. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  152. // wait document load
  153. waitForDocument();
  154. };
  155. var waitForDocument = function waitForDocument()
  156. {
  157. // document.body not available in XML+XSL documents in Firefox
  158. var doc = FBL.Env.browser.document;
  159. var body = doc.getElementsByTagName("body")[0];
  160. if (body)
  161. {
  162. calculatePixelsPerInch(doc, body);
  163. onDocumentLoad();
  164. }
  165. else
  166. setTimeout(waitForDocument, 50);
  167. };
  168. var onDocumentLoad = function onDocumentLoad()
  169. {
  170. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FBL onDocumentLoad", "document loaded");
  171. // fix IE6 problem with cache of background images, causing a lot of flickering
  172. if (FBL.isIE6)
  173. fixIE6BackgroundImageCache();
  174. // chrome context of the persistent application
  175. if (FBL.Env.Options.enablePersistent && FBL.Env.isChromeContext)
  176. {
  177. // finally, start the application in the chrome context
  178. FBL.Firebug.initialize();
  179. // if is not development mode, remove the shared environment cache object
  180. // used to synchronize the both persistent contexts
  181. if (!FBL.Env.isDevelopmentMode)
  182. {
  183. sharedEnv.destroy();
  184. sharedEnv = null;
  185. }
  186. }
  187. // non-persistent application
  188. else
  189. {
  190. FBL.FirebugChrome.create();
  191. }
  192. };
  193. // ************************************************************************************************
  194. // Env
  195. var sharedEnv;
  196. this.Env =
  197. {
  198. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  199. // Env Options (will be transported to Firebug options)
  200. Options:
  201. {
  202. saveCookies: false,
  203. saveWindowPosition: false,
  204. saveCommandLineHistory: false,
  205. startOpened: false,
  206. startInNewWindow: false,
  207. showIconWhenHidden: true,
  208. overrideConsole: true,
  209. ignoreFirebugElements: true,
  210. disableWhenFirebugActive: true,
  211. disableXHRListener: false,
  212. enableTrace: false,
  213. enablePersistent: false
  214. },
  215. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  216. // Library location
  217. Location:
  218. {
  219. sourceDir: null,
  220. baseDir: null,
  221. skinDir: null,
  222. skin: null,
  223. app: null
  224. },
  225. skin: "xp",
  226. useLocalSkin: false,
  227. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  228. // Env states
  229. isDevelopmentMode: false,
  230. isDebugMode: false,
  231. isChromeContext: false,
  232. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  233. // Env references
  234. browser: null,
  235. chrome: null
  236. };
  237. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  238. var destroyEnvironment = function destroyEnvironment()
  239. {
  240. setTimeout(function()
  241. {
  242. FBL = null;
  243. }, 100);
  244. };
  245. // ************************************************************************************************
  246. // Library location
  247. var findLocation = function findLocation()
  248. {
  249. var reFirebugFile = /(firebug-lite(?:-\w+)?(?:\.js|\.jgz))(?:#(.+))?$/;
  250. var rePath = /^(.*\/)/;
  251. var reProtocol = /^\w+:\/\//;
  252. var path = null;
  253. var doc = document;
  254. // Firebug Lite 1.3.0 bookmarklet identification
  255. var script = doc.getElementById("FirebugLite");
  256. if (script)
  257. {
  258. file = reFirebugFile.exec(script.src);
  259. var version = script.getAttribute("FirebugLite");
  260. var number = version ? parseInt(version) : 0;
  261. if (!version || !number || number < bookmarkletVersion)
  262. {
  263. FBL.Env.bookmarkletOutdated = true;
  264. }
  265. }
  266. else
  267. {
  268. for(var i=0, s=doc.getElementsByTagName("script"), si; si=s[i]; i++)
  269. {
  270. var file = null;
  271. if ( si.nodeName.toLowerCase() == "script" && (file = reFirebugFile.exec(si.src)) )
  272. {
  273. script = si;
  274. break;
  275. }
  276. }
  277. }
  278. if (script)
  279. script.firebugIgnore = true;
  280. if (file)
  281. {
  282. var fileName = file[1];
  283. var fileOptions = file[2];
  284. // absolute path
  285. if (reProtocol.test(script.src)) {
  286. path = rePath.exec(script.src)[1];
  287. }
  288. // relative path
  289. else
  290. {
  291. var r = rePath.exec(script.src);
  292. var src = r ? r[1] : script.src;
  293. var backDir = /^((?:\.\.\/)+)(.*)/.exec(src);
  294. var reLastDir = /^(.*\/)[^\/]+\/$/;
  295. path = rePath.exec(location.href)[1];
  296. // "../some/path"
  297. if (backDir)
  298. {
  299. var j = backDir[1].length/3;
  300. var p;
  301. while (j-- > 0)
  302. path = reLastDir.exec(path)[1];
  303. path += backDir[2];
  304. }
  305. else if(src.indexOf("/") != -1)
  306. {
  307. // "./some/path"
  308. if(/^\.\/./.test(src))
  309. {
  310. path += src.substring(2);
  311. }
  312. // "/some/path"
  313. else if(/^\/./.test(src))
  314. {
  315. var domain = /^(\w+:\/\/[^\/]+)/.exec(path);
  316. path = domain[1] + src;
  317. }
  318. // "some/path"
  319. else
  320. {
  321. path += src;
  322. }
  323. }
  324. }
  325. }
  326. FBL.Env.isChromeExtension = script && script.getAttribute("extension") == "Chrome";
  327. if (FBL.Env.isChromeExtension)
  328. {
  329. path = productionDir;
  330. FBL.Env.bookmarkletOutdated = false;
  331. script = {innerHTML: "{showIconWhenHidden:false}"};
  332. }
  333. var m = path && path.match(/([^\/]+)\/$/) || null;
  334. if (path && m)
  335. {
  336. var Env = FBL.Env;
  337. // Always use the local skin when running in the same domain
  338. // See Issue 3554: Firebug Lite should use local images when loaded locally
  339. Env.useLocalSkin = path.indexOf(location.protocol + "//" + location.host + "/") == 0;
  340. // detecting development and debug modes via file name
  341. if (fileName == "firebug-lite-dev.js")
  342. {
  343. Env.isDevelopmentMode = true;
  344. Env.isDebugMode = true;
  345. }
  346. else if (fileName == "firebug-lite-debug.js")
  347. {
  348. Env.isDebugMode = true;
  349. }
  350. // process the <html debug="true">
  351. if (Env.browser.document.documentElement.getAttribute("debug") == "true")
  352. {
  353. Env.Options.startOpened = true;
  354. }
  355. // process the Script URL Options
  356. if (fileOptions)
  357. {
  358. var options = fileOptions.split(",");
  359. for (var i = 0, length = options.length; i < length; i++)
  360. {
  361. var option = options[i];
  362. var name, value;
  363. if (option.indexOf("=") != -1)
  364. {
  365. var parts = option.split("=");
  366. name = parts[0];
  367. value = eval(unescape(parts[1]));
  368. }
  369. else
  370. {
  371. name = option;
  372. value = true;
  373. }
  374. if (name == "debug")
  375. {
  376. Env.isDebugMode = !!value;
  377. }
  378. else if (name in Env.Options)
  379. {
  380. Env.Options[name] = value;
  381. }
  382. else
  383. {
  384. Env[name] = value;
  385. }
  386. }
  387. }
  388. // process the Script JSON Options
  389. var innerOptions = FBL.trim(script.innerHTML);
  390. if (innerOptions)
  391. {
  392. var innerOptionsObject = eval("(" + innerOptions + ")");
  393. for (var name in innerOptionsObject)
  394. {
  395. var value = innerOptionsObject[name];
  396. if (name == "debug")
  397. {
  398. Env.isDebugMode = !!value;
  399. }
  400. else if (name in Env.Options)
  401. {
  402. Env.Options[name] = value;
  403. }
  404. else
  405. {
  406. Env[name] = value;
  407. }
  408. }
  409. }
  410. // process the Debug Mode
  411. if (Env.isDebugMode)
  412. {
  413. Env.Options.startOpened = true;
  414. Env.Options.enableTrace = true;
  415. Env.Options.disableWhenFirebugActive = false;
  416. }
  417. var loc = Env.Location;
  418. var isProductionRelease = path.indexOf(productionDir) != -1;
  419. loc.sourceDir = path;
  420. loc.baseDir = path.substr(0, path.length - m[1].length - 1);
  421. loc.skinDir = (isProductionRelease ? path : loc.baseDir) + "skin/" + Env.skin + "/";
  422. loc.skin = loc.skinDir + "firebug.html";
  423. loc.app = path + fileName;
  424. }
  425. else
  426. {
  427. throw new Error("Firebug Error: Library path not found");
  428. }
  429. };
  430. // ************************************************************************************************
  431. // Basics
  432. this.bind = function() // fn, thisObject, args => thisObject.fn(args, arguments);
  433. {
  434. var args = cloneArray(arguments), fn = args.shift(), object = args.shift();
  435. return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); };
  436. };
  437. this.bindFixed = function() // fn, thisObject, args => thisObject.fn(args);
  438. {
  439. var args = cloneArray(arguments), fn = args.shift(), object = args.shift();
  440. return function() { return fn.apply(object, args); };
  441. };
  442. this.extend = function(l, r)
  443. {
  444. var newOb = {};
  445. for (var n in l)
  446. newOb[n] = l[n];
  447. for (var n in r)
  448. newOb[n] = r[n];
  449. return newOb;
  450. };
  451. this.descend = function(prototypeParent, childProperties)
  452. {
  453. function protoSetter() {};
  454. protoSetter.prototype = prototypeParent;
  455. var newOb = new protoSetter();
  456. for (var n in childProperties)
  457. newOb[n] = childProperties[n];
  458. return newOb;
  459. };
  460. this.append = function(l, r)
  461. {
  462. for (var n in r)
  463. l[n] = r[n];
  464. return l;
  465. };
  466. this.keys = function(map) // At least sometimes the keys will be on user-level window objects
  467. {
  468. var keys = [];
  469. try
  470. {
  471. for (var name in map) // enumeration is safe
  472. keys.push(name); // name is string, safe
  473. }
  474. catch (exc)
  475. {
  476. // Sometimes we get exceptions trying to iterate properties
  477. }
  478. return keys; // return is safe
  479. };
  480. this.values = function(map)
  481. {
  482. var values = [];
  483. try
  484. {
  485. for (var name in map)
  486. {
  487. try
  488. {
  489. values.push(map[name]);
  490. }
  491. catch (exc)
  492. {
  493. // Sometimes we get exceptions trying to access properties
  494. if (FBTrace.DBG_ERRORS)
  495. FBTrace.sysout("lib.values FAILED ", exc);
  496. }
  497. }
  498. }
  499. catch (exc)
  500. {
  501. // Sometimes we get exceptions trying to iterate properties
  502. if (FBTrace.DBG_ERRORS)
  503. FBTrace.sysout("lib.values FAILED ", exc);
  504. }
  505. return values;
  506. };
  507. this.remove = function(list, item)
  508. {
  509. for (var i = 0; i < list.length; ++i)
  510. {
  511. if (list[i] == item)
  512. {
  513. list.splice(i, 1);
  514. break;
  515. }
  516. }
  517. };
  518. this.sliceArray = function(array, index)
  519. {
  520. var slice = [];
  521. for (var i = index; i < array.length; ++i)
  522. slice.push(array[i]);
  523. return slice;
  524. };
  525. function cloneArray(array, fn)
  526. {
  527. var newArray = [];
  528. if (fn)
  529. for (var i = 0; i < array.length; ++i)
  530. newArray.push(fn(array[i]));
  531. else
  532. for (var i = 0; i < array.length; ++i)
  533. newArray.push(array[i]);
  534. return newArray;
  535. }
  536. function extendArray(array, array2)
  537. {
  538. var newArray = [];
  539. newArray.push.apply(newArray, array);
  540. newArray.push.apply(newArray, array2);
  541. return newArray;
  542. }
  543. this.extendArray = extendArray;
  544. this.cloneArray = cloneArray;
  545. function arrayInsert(array, index, other)
  546. {
  547. for (var i = 0; i < other.length; ++i)
  548. array.splice(i+index, 0, other[i]);
  549. return array;
  550. }
  551. // ************************************************************************************************
  552. this.createStyleSheet = function(doc, url)
  553. {
  554. //TODO: xxxpedro
  555. //var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
  556. var style = this.createElement("link");
  557. style.setAttribute("charset","utf-8");
  558. style.firebugIgnore = true;
  559. style.setAttribute("rel", "stylesheet");
  560. style.setAttribute("type", "text/css");
  561. style.setAttribute("href", url);
  562. //TODO: xxxpedro
  563. //style.innerHTML = this.getResource(url);
  564. return style;
  565. };
  566. this.addStyleSheet = function(doc, style)
  567. {
  568. var heads = doc.getElementsByTagName("head");
  569. if (heads.length)
  570. heads[0].appendChild(style);
  571. else
  572. doc.documentElement.appendChild(style);
  573. };
  574. this.appendStylesheet = function(doc, uri)
  575. {
  576. // Make sure the stylesheet is not appended twice.
  577. if (this.$(uri, doc))
  578. return;
  579. var styleSheet = this.createStyleSheet(doc, uri);
  580. styleSheet.setAttribute("id", uri);
  581. this.addStyleSheet(doc, styleSheet);
  582. };
  583. this.addScript = function(doc, id, src)
  584. {
  585. var element = doc.createElementNS("http://www.w3.org/1999/xhtml", "html:script");
  586. element.setAttribute("type", "text/javascript");
  587. element.setAttribute("id", id);
  588. if (!FBTrace.DBG_CONSOLE)
  589. FBL.unwrapObject(element).firebugIgnore = true;
  590. element.innerHTML = src;
  591. if (doc.documentElement)
  592. doc.documentElement.appendChild(element);
  593. else
  594. {
  595. // See issue 1079, the svg test case gives this error
  596. if (FBTrace.DBG_ERRORS)
  597. FBTrace.sysout("lib.addScript doc has no documentElement:", doc);
  598. }
  599. return element;
  600. };
  601. // ************************************************************************************************
  602. this.getStyle = this.isIE ?
  603. function(el, name)
  604. {
  605. return el.currentStyle[name] || el.style[name] || undefined;
  606. }
  607. :
  608. function(el, name)
  609. {
  610. return el.ownerDocument.defaultView.getComputedStyle(el,null)[name]
  611. || el.style[name] || undefined;
  612. };
  613. // ************************************************************************************************
  614. // Whitespace and Entity conversions
  615. var entityConversionLists = this.entityConversionLists = {
  616. normal : {
  617. whitespace : {
  618. '\t' : '\u200c\u2192',
  619. '\n' : '\u200c\u00b6',
  620. '\r' : '\u200c\u00ac',
  621. ' ' : '\u200c\u00b7'
  622. }
  623. },
  624. reverse : {
  625. whitespace : {
  626. '&Tab;' : '\t',
  627. '&NewLine;' : '\n',
  628. '\u200c\u2192' : '\t',
  629. '\u200c\u00b6' : '\n',
  630. '\u200c\u00ac' : '\r',
  631. '\u200c\u00b7' : ' '
  632. }
  633. }
  634. };
  635. var normal = entityConversionLists.normal,
  636. reverse = entityConversionLists.reverse;
  637. function addEntityMapToList(ccode, entity)
  638. {
  639. var lists = Array.prototype.slice.call(arguments, 2),
  640. len = lists.length,
  641. ch = String.fromCharCode(ccode);
  642. for (var i = 0; i < len; i++)
  643. {
  644. var list = lists[i];
  645. normal[list]=normal[list] || {};
  646. normal[list][ch] = '&' + entity + ';';
  647. reverse[list]=reverse[list] || {};
  648. reverse[list]['&' + entity + ';'] = ch;
  649. }
  650. };
  651. var e = addEntityMapToList,
  652. white = 'whitespace',
  653. text = 'text',
  654. attr = 'attributes',
  655. css = 'css',
  656. editor = 'editor';
  657. e(0x0022, 'quot', attr, css);
  658. e(0x0026, 'amp', attr, text, css);
  659. e(0x0027, 'apos', css);
  660. e(0x003c, 'lt', attr, text, css);
  661. e(0x003e, 'gt', attr, text, css);
  662. e(0xa9, 'copy', text, editor);
  663. e(0xae, 'reg', text, editor);
  664. e(0x2122, 'trade', text, editor);
  665. // See http://en.wikipedia.org/wiki/Dash
  666. e(0x2012, '#8210', attr, text, editor); // figure dash
  667. e(0x2013, 'ndash', attr, text, editor); // en dash
  668. e(0x2014, 'mdash', attr, text, editor); // em dash
  669. e(0x2015, '#8213', attr, text, editor); // horizontal bar
  670. e(0x00a0, 'nbsp', attr, text, white, editor);
  671. e(0x2002, 'ensp', attr, text, white, editor);
  672. e(0x2003, 'emsp', attr, text, white, editor);
  673. e(0x2009, 'thinsp', attr, text, white, editor);
  674. e(0x200c, 'zwnj', attr, text, white, editor);
  675. e(0x200d, 'zwj', attr, text, white, editor);
  676. e(0x200e, 'lrm', attr, text, white, editor);
  677. e(0x200f, 'rlm', attr, text, white, editor);
  678. e(0x200b, '#8203', attr, text, white, editor); // zero-width space (ZWSP)
  679. //************************************************************************************************
  680. // Entity escaping
  681. var entityConversionRegexes = {
  682. normal : {},
  683. reverse : {}
  684. };
  685. var escapeEntitiesRegEx = {
  686. normal : function(list)
  687. {
  688. var chars = [];
  689. for ( var ch in list)
  690. {
  691. chars.push(ch);
  692. }
  693. return new RegExp('([' + chars.join('') + '])', 'gm');
  694. },
  695. reverse : function(list)
  696. {
  697. var chars = [];
  698. for ( var ch in list)
  699. {
  700. chars.push(ch);
  701. }
  702. return new RegExp('(' + chars.join('|') + ')', 'gm');
  703. }
  704. };
  705. function getEscapeRegexp(direction, lists)
  706. {
  707. var name = '', re;
  708. var groups = [].concat(lists);
  709. for (i = 0; i < groups.length; i++)
  710. {
  711. name += groups[i].group;
  712. }
  713. re = entityConversionRegexes[direction][name];
  714. if (!re)
  715. {
  716. var list = {};
  717. if (groups.length > 1)
  718. {
  719. for ( var i = 0; i < groups.length; i++)
  720. {
  721. var aList = entityConversionLists[direction][groups[i].group];
  722. for ( var item in aList)
  723. list[item] = aList[item];
  724. }
  725. } else if (groups.length==1)
  726. {
  727. list = entityConversionLists[direction][groups[0].group]; // faster for special case
  728. } else {
  729. list = {}; // perhaps should print out an error here?
  730. }
  731. re = entityConversionRegexes[direction][name] = escapeEntitiesRegEx[direction](list);
  732. }
  733. return re;
  734. };
  735. function createSimpleEscape(name, direction)
  736. {
  737. return function(value)
  738. {
  739. var list = entityConversionLists[direction][name];
  740. return String(value).replace(
  741. getEscapeRegexp(direction, {
  742. group : name,
  743. list : list
  744. }),
  745. function(ch)
  746. {
  747. return list[ch];
  748. }
  749. );
  750. };
  751. };
  752. function escapeGroupsForEntities(str, lists)
  753. {
  754. lists = [].concat(lists);
  755. var re = getEscapeRegexp('normal', lists),
  756. split = String(str).split(re),
  757. len = split.length,
  758. results = [],
  759. cur, r, i, ri = 0, l, list, last = '';
  760. if (!len)
  761. return [ {
  762. str : String(str),
  763. group : '',
  764. name : ''
  765. } ];
  766. for (i = 0; i < len; i++)
  767. {
  768. cur = split[i];
  769. if (cur == '')
  770. continue;
  771. for (l = 0; l < lists.length; l++)
  772. {
  773. list = lists[l];
  774. r = entityConversionLists.normal[list.group][cur];
  775. // if (cur == ' ' && list.group == 'whitespace' && last == ' ') // only show for runs of more than one space
  776. // r = ' ';
  777. if (r)
  778. {
  779. results[ri] = {
  780. 'str' : r,
  781. 'class' : list['class'],
  782. 'extra' : list.extra[cur] ? list['class']
  783. + list.extra[cur] : ''
  784. };
  785. break;
  786. }
  787. }
  788. // last=cur;
  789. if (!r)
  790. results[ri] = {
  791. 'str' : cur,
  792. 'class' : '',
  793. 'extra' : ''
  794. };
  795. ri++;
  796. }
  797. return results;
  798. };
  799. this.escapeGroupsForEntities = escapeGroupsForEntities;
  800. function unescapeEntities(str, lists)
  801. {
  802. var re = getEscapeRegexp('reverse', lists),
  803. split = String(str).split(re),
  804. len = split.length,
  805. results = [],
  806. cur, r, i, ri = 0, l, list;
  807. if (!len)
  808. return str;
  809. lists = [].concat(lists);
  810. for (i = 0; i < len; i++)
  811. {
  812. cur = split[i];
  813. if (cur == '')
  814. continue;
  815. for (l = 0; l < lists.length; l++)
  816. {
  817. list = lists[l];
  818. r = entityConversionLists.reverse[list.group][cur];
  819. if (r)
  820. {
  821. results[ri] = r;
  822. break;
  823. }
  824. }
  825. if (!r)
  826. results[ri] = cur;
  827. ri++;
  828. }
  829. return results.join('') || '';
  830. };
  831. // ************************************************************************************************
  832. // String escaping
  833. var escapeForTextNode = this.escapeForTextNode = createSimpleEscape('text', 'normal');
  834. var escapeForHtmlEditor = this.escapeForHtmlEditor = createSimpleEscape('editor', 'normal');
  835. var escapeForElementAttribute = this.escapeForElementAttribute = createSimpleEscape('attributes', 'normal');
  836. var escapeForCss = this.escapeForCss = createSimpleEscape('css', 'normal');
  837. // deprecated compatibility functions
  838. //this.deprecateEscapeHTML = createSimpleEscape('text', 'normal');
  839. //this.deprecatedUnescapeHTML = createSimpleEscape('text', 'reverse');
  840. //this.escapeHTML = deprecated("use appropriate escapeFor... function", this.deprecateEscapeHTML);
  841. //this.unescapeHTML = deprecated("use appropriate unescapeFor... function", this.deprecatedUnescapeHTML);
  842. var escapeForSourceLine = this.escapeForSourceLine = createSimpleEscape('text', 'normal');
  843. var unescapeWhitespace = createSimpleEscape('whitespace', 'reverse');
  844. this.unescapeForTextNode = function(str)
  845. {
  846. if (Firebug.showTextNodesWithWhitespace)
  847. str = unescapeWhitespace(str);
  848. if (!Firebug.showTextNodesWithEntities)
  849. str = escapeForElementAttribute(str);
  850. return str;
  851. };
  852. this.escapeNewLines = function(value)
  853. {
  854. return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n");
  855. };
  856. this.stripNewLines = function(value)
  857. {
  858. return typeof(value) == "string" ? value.replace(/[\r\n]/g, " ") : value;
  859. };
  860. this.escapeJS = function(value)
  861. {
  862. return value.replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace('"', '\\"', "g");
  863. };
  864. function escapeHTMLAttribute(value)
  865. {
  866. function replaceChars(ch)
  867. {
  868. switch (ch)
  869. {
  870. case "&":
  871. return "&amp;";
  872. case "'":
  873. return apos;
  874. case '"':
  875. return quot;
  876. }
  877. return "?";
  878. };
  879. var apos = "&#39;", quot = "&quot;", around = '"';
  880. if( value.indexOf('"') == -1 ) {
  881. quot = '"';
  882. apos = "'";
  883. } else if( value.indexOf("'") == -1 ) {
  884. quot = '"';
  885. around = "'";
  886. }
  887. return around + (String(value).replace(/[&'"]/g, replaceChars)) + around;
  888. }
  889. function escapeHTML(value)
  890. {
  891. function replaceChars(ch)
  892. {
  893. switch (ch)
  894. {
  895. case "<":
  896. return "&lt;";
  897. case ">":
  898. return "&gt;";
  899. case "&":
  900. return "&amp;";
  901. case "'":
  902. return "&#39;";
  903. case '"':
  904. return "&quot;";
  905. }
  906. return "?";
  907. };
  908. return String(value).replace(/[<>&"']/g, replaceChars);
  909. }
  910. this.escapeHTML = escapeHTML;
  911. this.cropString = function(text, limit)
  912. {
  913. text = text + "";
  914. if (!limit)
  915. var halfLimit = 50;
  916. else
  917. var halfLimit = limit / 2;
  918. if (text.length > limit)
  919. return this.escapeNewLines(text.substr(0, halfLimit) + "..." + text.substr(text.length-halfLimit));
  920. else
  921. return this.escapeNewLines(text);
  922. };
  923. this.isWhitespace = function(text)
  924. {
  925. return !reNotWhitespace.exec(text);
  926. };
  927. this.splitLines = function(text)
  928. {
  929. var reSplitLines2 = /.*(:?\r\n|\n|\r)?/mg;
  930. var lines;
  931. if (text.match)
  932. {
  933. lines = text.match(reSplitLines2);
  934. }
  935. else
  936. {
  937. var str = text+"";
  938. lines = str.match(reSplitLines2);
  939. }
  940. lines.pop();
  941. return lines;
  942. };
  943. // ************************************************************************************************
  944. this.safeToString = function(ob)
  945. {
  946. if (this.isIE)
  947. return ob + "";
  948. try
  949. {
  950. if (ob && "toString" in ob && typeof ob.toString == "function")
  951. return ob.toString();
  952. }
  953. catch (exc)
  954. {
  955. // xxxpedro it is not safe to use ob+""?
  956. return ob + "";
  957. ///return "[an object with no toString() function]";
  958. }
  959. };
  960. // ************************************************************************************************
  961. this.hasProperties = function(ob)
  962. {
  963. try
  964. {
  965. for (var name in ob)
  966. return true;
  967. } catch (exc) {}
  968. return false;
  969. };
  970. // ************************************************************************************************
  971. // String Util
  972. var reTrim = /^\s+|\s+$/g;
  973. this.trim = function(s)
  974. {
  975. return s.replace(reTrim, "");
  976. };
  977. // ************************************************************************************************
  978. // Empty
  979. this.emptyFn = function(){};
  980. // ************************************************************************************************
  981. // Visibility
  982. this.isVisible = function(elt)
  983. {
  984. /*
  985. if (elt instanceof XULElement)
  986. {
  987. //FBTrace.sysout("isVisible elt.offsetWidth: "+elt.offsetWidth+" offsetHeight:"+ elt.offsetHeight+" localName:"+ elt.localName+" nameSpace:"+elt.nameSpaceURI+"\n");
  988. return (!elt.hidden && !elt.collapsed);
  989. }
  990. /**/
  991. return this.getStyle(elt, "visibility") != "hidden" &&
  992. ( elt.offsetWidth > 0 || elt.offsetHeight > 0
  993. || elt.tagName in invisibleTags
  994. || elt.namespaceURI == "http://www.w3.org/2000/svg"
  995. || elt.namespaceURI == "http://www.w3.org/1998/Math/MathML" );
  996. };
  997. this.collapse = function(elt, collapsed)
  998. {
  999. // IE6 doesn't support the [collapsed] CSS selector. IE7 does support the selector,
  1000. // but it is causing a bug (the element disappears when you set the "collapsed"
  1001. // attribute, but it doesn't appear when you remove the attribute. So, for those
  1002. // cases, we need to use the class attribute.
  1003. if (this.isIElt8)
  1004. {
  1005. if (collapsed)
  1006. this.setClass(elt, "collapsed");
  1007. else
  1008. this.removeClass(elt, "collapsed");
  1009. }
  1010. else
  1011. elt.setAttribute("collapsed", collapsed ? "true" : "false");
  1012. };
  1013. this.obscure = function(elt, obscured)
  1014. {
  1015. if (obscured)
  1016. this.setClass(elt, "obscured");
  1017. else
  1018. this.removeClass(elt, "obscured");
  1019. };
  1020. this.hide = function(elt, hidden)
  1021. {
  1022. elt.style.visibility = hidden ? "hidden" : "visible";
  1023. };
  1024. this.clearNode = function(node)
  1025. {
  1026. var nodeName = " " + node.nodeName.toLowerCase() + " ";
  1027. var ignoreTags = " table tbody thead tfoot th tr td ";
  1028. // IE can't use innerHTML of table elements
  1029. if (this.isIE && ignoreTags.indexOf(nodeName) != -1)
  1030. this.eraseNode(node);
  1031. else
  1032. node.innerHTML = "";
  1033. };
  1034. this.eraseNode = function(node)
  1035. {
  1036. while (node.lastChild)
  1037. node.removeChild(node.lastChild);
  1038. };
  1039. // ************************************************************************************************
  1040. // Window iteration
  1041. this.iterateWindows = function(win, handler)
  1042. {
  1043. if (!win || !win.document)
  1044. return;
  1045. handler(win);
  1046. if (win == top || !win.frames) return; // XXXjjb hack for chromeBug
  1047. for (var i = 0; i < win.frames.length; ++i)
  1048. {
  1049. var subWin = win.frames[i];
  1050. if (subWin != win)
  1051. this.iterateWindows(subWin, handler);
  1052. }
  1053. };
  1054. this.getRootWindow = function(win)
  1055. {
  1056. for (; win; win = win.parent)
  1057. {
  1058. if (!win.parent || win == win.parent || !this.instanceOf(win.parent, "Window"))
  1059. return win;
  1060. }
  1061. return null;
  1062. };
  1063. // ************************************************************************************************
  1064. // Graphics
  1065. this.getClientOffset = function(elt)
  1066. {
  1067. var addOffset = function addOffset(elt, coords, view)
  1068. {
  1069. var p = elt.offsetParent;
  1070. var style = isIE ? elt.currentStyle : view.getComputedStyle(elt, "");
  1071. if (elt.offsetLeft)
  1072. coords.x += elt.offsetLeft + parseInt(style.borderLeftWidth);
  1073. if (elt.offsetTop)
  1074. coords.y += elt.offsetTop + parseInt(style.borderTopWidth);
  1075. if (p)
  1076. {
  1077. if (p.nodeType == 1)
  1078. addOffset(p, coords, view);
  1079. }
  1080. else
  1081. {
  1082. var otherView = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView;
  1083. if (otherView.frameElement)
  1084. addOffset(otherView.frameElement, coords, otherView);
  1085. }
  1086. };
  1087. var isIE = this.isIE;
  1088. var coords = {x: 0, y: 0};
  1089. if (elt)
  1090. {
  1091. var view = isIE ? elt.ownerDocument.parentWindow : elt.ownerDocument.defaultView;
  1092. addOffset(elt, coords, view);
  1093. }
  1094. return coords;
  1095. };
  1096. this.getViewOffset = function(elt, singleFrame)
  1097. {
  1098. function addOffset(elt, coords, view)
  1099. {
  1100. var p = elt.offsetParent;
  1101. coords.x += elt.offsetLeft - (p ? p.scrollLeft : 0);
  1102. coords.y += elt.offsetTop - (p ? p.scrollTop : 0);
  1103. if (p)
  1104. {
  1105. if (p.nodeType == 1)
  1106. {
  1107. var parentStyle = view.getComputedStyle(p, "");
  1108. if (parentStyle.position != "static")
  1109. {
  1110. coords.x += parseInt(parentStyle.borderLeftWidth);
  1111. coords.y += parseInt(parentStyle.borderTopWidth);
  1112. if (p.localName == "TABLE")
  1113. {
  1114. coords.x += parseInt(parentStyle.paddingLeft);
  1115. coords.y += parseInt(parentStyle.paddingTop);
  1116. }
  1117. else if (p.localName == "BODY")
  1118. {
  1119. var style = view.getComputedStyle(elt, "");
  1120. coords.x += parseInt(style.marginLeft);
  1121. coords.y += parseInt(style.marginTop);
  1122. }
  1123. }
  1124. else if (p.localName == "BODY")
  1125. {
  1126. coords.x += parseInt(parentStyle.borderLeftWidth);
  1127. coords.y += parseInt(parentStyle.borderTopWidth);
  1128. }
  1129. var parent = elt.parentNode;
  1130. while (p != parent)
  1131. {
  1132. coords.x -= parent.scrollLeft;
  1133. coords.y -= parent.scrollTop;
  1134. parent = parent.parentNode;
  1135. }
  1136. addOffset(p, coords, view);
  1137. }
  1138. }
  1139. else
  1140. {
  1141. if (elt.localName == "BODY")
  1142. {
  1143. var style = view.getComputedStyle(elt, "");
  1144. coords.x += parseInt(style.borderLeftWidth);
  1145. coords.y += parseInt(style.borderTopWidth);
  1146. var htmlStyle = view.getComputedStyle(elt.parentNode, "");
  1147. coords.x -= parseInt(htmlStyle.paddingLeft);
  1148. coords.y -= parseInt(htmlStyle.paddingTop);
  1149. }
  1150. if (elt.scrollLeft)
  1151. coords.x += elt.scrollLeft;
  1152. if (elt.scrollTop)
  1153. coords.y += elt.scrollTop;
  1154. var win = elt.ownerDocument.defaultView;
  1155. if (win && (!singleFrame && win.frameElement))
  1156. addOffset(win.frameElement, coords, win);
  1157. }
  1158. }
  1159. var coords = {x: 0, y: 0};
  1160. if (elt)
  1161. addOffset(elt, coords, elt.ownerDocument.defaultView);
  1162. return coords;
  1163. };
  1164. this.getLTRBWH = function(elt)
  1165. {
  1166. var bcrect,
  1167. dims = {"left": 0, "top": 0, "right": 0, "bottom": 0, "width": 0, "height": 0};
  1168. if (elt)
  1169. {
  1170. bcrect = elt.getBoundingClientRect();
  1171. dims.left = bcrect.left;
  1172. dims.top = bcrect.top;
  1173. dims.right = bcrect.right;
  1174. dims.bottom = bcrect.bottom;
  1175. if(bcrect.width)
  1176. {
  1177. dims.width = bcrect.width;
  1178. dims.height = bcrect.height;
  1179. }
  1180. else
  1181. {
  1182. dims.width = dims.right - dims.left;
  1183. dims.height = dims.bottom - dims.top;
  1184. }
  1185. }
  1186. return dims;
  1187. };
  1188. this.applyBodyOffsets = function(elt, clientRect)
  1189. {
  1190. var od = elt.ownerDocument;
  1191. if (!od.body)
  1192. return clientRect;
  1193. var style = od.defaultView.getComputedStyle(od.body, null);
  1194. var pos = style.getPropertyValue('position');
  1195. if(pos === 'absolute' || pos === 'relative')
  1196. {
  1197. var borderLeft = parseInt(style.getPropertyValue('border-left-width').replace('px', ''),10) || 0;
  1198. var borderTop = parseInt(style.getPropertyValue('border-top-width').replace('px', ''),10) || 0;
  1199. var paddingLeft = parseInt(style.getPropertyValue('padding-left').replace('px', ''),10) || 0;
  1200. var paddingTop = parseInt(style.getPropertyValue('padding-top').replace('px', ''),10) || 0;
  1201. var marginLeft = parseInt(style.getPropertyValue('margin-left').replace('px', ''),10) || 0;
  1202. var marginTop = parseInt(style.getPropertyValue('margin-top').replace('px', ''),10) || 0;
  1203. var offsetX = borderLeft + paddingLeft + marginLeft;
  1204. var offsetY = borderTop + paddingTop + marginTop;
  1205. clientRect.left -= offsetX;
  1206. clientRect.top -= offsetY;
  1207. clientRect.right -= offsetX;
  1208. clientRect.bottom -= offsetY;
  1209. }
  1210. return clientRect;
  1211. };
  1212. this.getOffsetSize = function(elt)
  1213. {
  1214. return {width: elt.offsetWidth, height: elt.offsetHeight};
  1215. };
  1216. this.getOverflowParent = function(element)
  1217. {
  1218. for (var scrollParent = element.parentNode; scrollParent; scrollParent = scrollParent.offsetParent)
  1219. {
  1220. if (scrollParent.scrollHeight > scrollParent.offsetHeight)
  1221. return scrollParent;
  1222. }
  1223. };
  1224. this.isScrolledToBottom = function(element)
  1225. {
  1226. var onBottom = (element.scrollTop + element.offsetHeight) == element.scrollHeight;
  1227. if (FBTrace.DBG_CONSOLE)
  1228. FBTrace.sysout("isScrolledToBottom offsetHeight: "+element.offsetHeight +" onBottom:"+onBottom);
  1229. return onBottom;
  1230. };
  1231. this.scrollToBottom = function(element)
  1232. {
  1233. element.scrollTop = element.scrollHeight;
  1234. if (FBTrace.DBG_CONSOLE)
  1235. {
  1236. FBTrace.sysout("scrollToBottom reset scrollTop "+element.scrollTop+" = "+element.scrollHeight);
  1237. if (element.scrollHeight == element.offsetHeight)
  1238. FBTrace.sysout("scrollToBottom attempt to scroll non-scrollable element "+element, element);
  1239. }
  1240. return (element.scrollTop == element.scrollHeight);
  1241. };
  1242. this.move = function(element, x, y)
  1243. {
  1244. element.style.left = x + "px";
  1245. element.style.top = y + "px";
  1246. };
  1247. this.resize = function(element, w, h)
  1248. {
  1249. element.style.width = w + "px";
  1250. element.style.height = h + "px";
  1251. };
  1252. this.linesIntoCenterView = function(element, scrollBox) // {before: int, after: int}
  1253. {
  1254. if (!scrollBox)
  1255. scrollBox = this.getOverflowParent(element);
  1256. if (!scrollBox)
  1257. return;
  1258. var offset = this.getClientOffset(element);
  1259. var topSpace = offset.y - scrollBox.scrollTop;
  1260. var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight)
  1261. - (offset.y + element.offsetHeight);
  1262. if (topSpace < 0 || bottomSpace < 0)
  1263. {
  1264. var split = (scrollBox.clientHeight/2);
  1265. var centerY = offset.y - split;
  1266. scrollBox.scrollTop = centerY;
  1267. topSpace = split;
  1268. bottomSpace = split - element.offsetHeight;
  1269. }
  1270. return {before: Math.round((topSpace/element.offsetHeight) + 0.5),
  1271. after: Math.round((bottomSpace/element.offsetHeight) + 0.5) };
  1272. };
  1273. this.scrollIntoCenterView = function(element, scrollBox, notX, notY)
  1274. {
  1275. if (!element)
  1276. return;
  1277. if (!scrollBox)
  1278. scrollBox = this.getOverflowParent(element);
  1279. if (!scrollBox)
  1280. return;
  1281. var offset = this.getClientOffset(element);
  1282. if (!notY)
  1283. {
  1284. var topSpace = offset.y - scrollBox.scrollTop;
  1285. var bottomSpace = (scrollBox.scrollTop + scrollBox.clientHeight)
  1286. - (offset.y + element.offsetHeight);
  1287. if (topSpace < 0 || bottomSpace < 0)
  1288. {
  1289. var centerY = offset.y - (scrollBox.clientHeight/2);
  1290. scrollBox.scrollTop = centerY;
  1291. }
  1292. }
  1293. if (!notX)
  1294. {
  1295. var leftSpace = offset.x - scrollBox.scrollLeft;
  1296. var rightSpace = (scrollBox.scrollLeft + scrollBox.clientWidth)
  1297. - (offset.x + element.clientWidth);
  1298. if (leftSpace < 0 || rightSpace < 0)
  1299. {
  1300. var centerX = offset.x - (scrollBox.clientWidth/2);
  1301. scrollBox.scrollLeft = centerX;
  1302. }
  1303. }
  1304. if (FBTrace.DBG_SOURCEFILES)
  1305. FBTrace.sysout("lib.scrollIntoCenterView ","Element:"+element.innerHTML);
  1306. };
  1307. // ************************************************************************************************
  1308. // CSS
  1309. var cssKeywordMap = null;
  1310. var cssPropNames = null;
  1311. var cssColorNames = null;
  1312. var imageRules = null;
  1313. this.getCSSKeywordsByProperty = function(propName)
  1314. {
  1315. if (!cssKeywordMap)
  1316. {
  1317. cssKeywordMap = {};
  1318. for (var name in this.cssInfo)
  1319. {
  1320. var list = [];
  1321. var types = this.cssInfo[name];
  1322. for (var i = 0; i < types.length; ++i)
  1323. {
  1324. var keywords = this.cssKeywords[types[i]];
  1325. if (keywords)
  1326. list.push.apply(list, keywords);
  1327. }
  1328. cssKeywordMap[name] = list;
  1329. }
  1330. }
  1331. return propName in cssKeywordMap ? cssKeywordMap[propName] : [];
  1332. };
  1333. this.getCSSPropertyNames = function()
  1334. {
  1335. if (!cssPropNames)
  1336. {
  1337. cssPropNames = [];
  1338. for (var name in this.cssInfo)
  1339. cssPropNames.push(name);
  1340. }
  1341. return cssPropNames;
  1342. };
  1343. this.isColorKeyword = function(keyword)
  1344. {
  1345. if (keyword == "transparent")
  1346. return false;
  1347. if (!cssColorNames)
  1348. {
  1349. cssColorNames = [];
  1350. var colors = this.cssKeywords["color"];
  1351. for (var i = 0; i < colors.length; ++i)
  1352. cssColorNames.push(colors[i].toLowerCase());
  1353. var systemColors = this.cssKeywords["systemColor"];
  1354. for (var i = 0; i < systemColors.length; ++i)
  1355. cssColorNames.push(systemColors[i].toLowerCase());
  1356. }
  1357. return cssColorNames.indexOf ? // Array.indexOf is not available in IE
  1358. cssColorNames.indexOf(keyword.toLowerCase()) != -1 :
  1359. (" " + cssColorNames.join(" ") + " ").indexOf(" " + keyword.toLowerCase() + " ") != -1;
  1360. };
  1361. this.isImageRule = function(rule)
  1362. {
  1363. if (!imageRules)
  1364. {
  1365. imageRules = [];
  1366. for (var i in this.cssInfo)
  1367. {
  1368. var r = i.toLowerCase();
  1369. var suffix = "image";
  1370. if (r.match(suffix + "$") == suffix || r == "background")
  1371. imageRules.push(r);
  1372. }
  1373. }
  1374. return imageRules.indexOf ? // Array.indexOf is not available in IE
  1375. imageRules.indexOf(rule.toLowerCase()) != -1 :
  1376. (" " + imageRules.join(" ") + " ").indexOf(" " + rule.toLowerCase() + " ") != -1;
  1377. };
  1378. this.copyTextStyles = function(fromNode, toNode, style)
  1379. {
  1380. var view = this.isIE ?
  1381. fromNode.ownerDocument.parentWindow :
  1382. fromNode.ownerDocument.defaultView;
  1383. if (view)
  1384. {
  1385. if (!style)
  1386. style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, "");
  1387. toNode.style.fontFamily = style.fontFamily;
  1388. // TODO: xxxpedro need to create a FBL.getComputedStyle() because IE
  1389. // returns wrong computed styles for inherited properties (like font-*)
  1390. //
  1391. // Also would be good to create a FBL.getStyle()
  1392. toNode.style.fontSize = style.fontSize;
  1393. toNode.style.fontWeight = style.fontWeight;
  1394. toNode.style.fontStyle = style.fontStyle;
  1395. return style;
  1396. }
  1397. };
  1398. this.copyBoxStyles = function(fromNode, toNode, style)
  1399. {
  1400. var view = this.isIE ?
  1401. fromNode.ownerDocument.parentWindow :
  1402. fromNode.ownerDocument.defaultView;
  1403. if (view)
  1404. {
  1405. if (!style)
  1406. style = this.isIE ? fromNode.currentStyle : view.getComputedStyle(fromNode, "");
  1407. toNode.style.marginTop = style.marginTop;
  1408. toNode.style.marginRight = style.marginRight;
  1409. toNode.style.marginBottom = style.marginBottom;
  1410. toNode.style.marginLeft = style.marginLeft;
  1411. toNode.style.borderTopWidth = style.borderTopWidth;
  1412. toNode.style.borderRightWidth = style.borderRightWidth;
  1413. toNode.style.borderBottomWidth = style.borderBottomWidth;
  1414. toNode.style.borderLeftWidth = style.borderLeftWidth;
  1415. return style;
  1416. }
  1417. };
  1418. this.readBoxStyles = function(style)
  1419. {
  1420. var styleNames = {
  1421. "margin-top": "marginTop", "margin-right": "marginRight",
  1422. "margin-left": "marginLeft", "margin-bottom": "marginBottom",
  1423. "border-top-width": "borderTop", "border-right-width": "borderRight",
  1424. "border-left-width": "borderLeft", "border-bottom-width": "borderBottom",
  1425. "padding-top": "paddingTop", "padding-right": "paddingRight",
  1426. "padding-left": "paddingLeft", "padding-bottom": "paddingBottom",
  1427. "z-index": "zIndex"
  1428. };
  1429. var styles = {};
  1430. for (var styleName in styleNames)
  1431. styles[styleNames[styleName]] = parseInt(style.getPropertyCSSValue(styleName).cssText) || 0;
  1432. if (FBTrace.DBG_INSPECT)
  1433. FBTrace.sysout("readBoxStyles ", styles);
  1434. return styles;
  1435. };
  1436. this.getBoxFromStyles = function(style, element)
  1437. {
  1438. var args = this.readBoxStyles(style);
  1439. args.width = element.offsetWidth
  1440. - (args.paddingLeft+args.paddingRight+args.borderLeft+args.borderRight);
  1441. args.height = element.offsetHeight
  1442. - (args.paddingTop+args.paddingBottom+args.borderTop+args.borderBottom);
  1443. return args;
  1444. };
  1445. this.getElementCSSSelector = function(element)
  1446. {
  1447. var label = element.localName.toLowerCase();
  1448. if (element.id)
  1449. label += "#" + element.id;
  1450. if (element.hasAttribute("class"))
  1451. label += "." + element.getAttribute("class").split(" ")[0];
  1452. return label;
  1453. };
  1454. this.getURLForStyleSheet= function(styleSheet)
  1455. {
  1456. //http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-StyleSheet. For inline style sheets, the value of this attribute is null.
  1457. return (styleSheet.href ? styleSheet.href : styleSheet.ownerNode.ownerDocument.URL);
  1458. };
  1459. this.getDocumentForStyleSheet = function(styleSheet)
  1460. {
  1461. while (styleSheet.parentStyleSheet && !styleSheet.ownerNode)
  1462. {
  1463. styleSheet = styleSheet.parentStyleSheet;
  1464. }
  1465. if (styleSheet.ownerNode)
  1466. return styleSheet.ownerNode.ownerDocument;
  1467. };
  1468. /**
  1469. * Retrieves the instance number for a given style sheet. The instance number
  1470. * is sheet's index within the set of all other sheets whose URL is the same.
  1471. */
  1472. this.getInstanceForStyleSheet = function(styleSheet, ownerDocument)
  1473. {
  1474. // System URLs are always unique (or at least we are making this assumption)
  1475. if (FBL.isSystemStyleSheet(styleSheet))
  1476. return 0;
  1477. // ownerDocument is an optional hint for performance
  1478. if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: " + styleSheet.href + " " + styleSheet.media.mediaText + " " + (styleSheet.ownerNode && FBL.getElementXPath(styleSheet.ownerNode)), ownerDocument);
  1479. ownerDocument = ownerDocument || FBL.getDocumentForStyleSheet(styleSheet);
  1480. var ret = 0,
  1481. styleSheets = ownerDocument.styleSheets,
  1482. href = styleSheet.href;
  1483. for (var i = 0; i < styleSheets.length; i++)
  1484. {
  1485. var curSheet = styleSheets[i];
  1486. if (FBTrace.DBG_CSS) FBTrace.sysout("getInstanceForStyleSheet: compare href " + i + " " + curSheet.href + " " + curSheet.media.mediaText + " " + (curSheet.ownerNode && FBL.getElementXPath(curSheet.ownerNode)));
  1487. if (curSheet == styleSheet)
  1488. break;
  1489. if (curSheet.href == href)
  1490. ret++;
  1491. }
  1492. return ret;
  1493. };
  1494. // ************************************************************************************************
  1495. // HTML and XML Serialization
  1496. var getElementType = this.getElementType = function(node)
  1497. {
  1498. if (isElementXUL(node))
  1499. return 'xul';
  1500. else if (isElementSVG(node))
  1501. return 'svg';
  1502. else if (isElementMathML(node))
  1503. return 'mathml';
  1504. else if (isElementXHTML(node))
  1505. return 'xhtml';
  1506. else if (isElementHTML(node))
  1507. return 'html';
  1508. }
  1509. var getElementSimpleType = this.getElementSimpleType = function(node)
  1510. {
  1511. if (isElementSVG(node))
  1512. return 'svg';
  1513. else if (isElementMathML(node))
  1514. return 'mathml';
  1515. else
  1516. return 'html';
  1517. }
  1518. var isElementHTML = this.isElementHTML = function(node)
  1519. {
  1520. return node.nodeName == node.nodeName.toUpperCase();
  1521. }
  1522. var isElementXHTML = this.isElementXHTML = function(node)
  1523. {
  1524. return node.nodeName == node.nodeName.toLowerCase();
  1525. }
  1526. var isElementMathML = this.isElementMathML = function(node)
  1527. {
  1528. return node.namespaceURI == 'http://www.w3.org/1998/Math/MathML';
  1529. }
  1530. var isElementSVG = this.isElementSVG = function(node)
  1531. {
  1532. return node.namespaceURI == 'http://www.w3.org/2000/svg';
  1533. }
  1534. var isElementXUL = this.isElementXUL = function(node)
  1535. {
  1536. return node instanceof XULElement;
  1537. }
  1538. this.isSelfClosing = function(element)
  1539. {
  1540. if (isElementSVG(element) || isElementMathML(element))
  1541. return true;
  1542. var tag = element.localName.toLowerCase();
  1543. return (this.selfClosingTags.hasOwnProperty(tag));
  1544. };
  1545. this.getElementHTML = function(element)
  1546. {
  1547. var self=this;
  1548. function toHTML(elt)
  1549. {
  1550. if (elt.nodeType == Node.ELEMENT_NODE)
  1551. {
  1552. if (unwrapObject(elt).firebugIgnore)
  1553. return;
  1554. html.push('<', elt.nodeName.toLowerCase());
  1555. for (var i = 0; i < elt.attributes.length; ++i)
  1556. {
  1557. var attr = elt.attributes[i];
  1558. // Hide attributes set by Firebug
  1559. if (attr.localName.indexOf("firebug-") == 0)
  1560. continue;
  1561. // MathML
  1562. if (attr.localName.indexOf("-moz-math") == 0)
  1563. {
  1564. // just hide for now
  1565. continue;
  1566. }
  1567. html.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"');
  1568. }
  1569. if (elt.firstChild)
  1570. {
  1571. html.push('>');
  1572. var pureText=true;
  1573. for (var child = element.firstChild; child; child = child.nextSibling)
  1574. pureText=pureText && (child.nodeType == Node.TEXT_NODE);
  1575. if (pureText)
  1576. html.push(escapeForHtmlEditor(elt.textContent));
  1577. else {
  1578. for (var child = elt.firstChild; child; child = child.nextSibling)
  1579. toHTML(child);
  1580. }
  1581. html.push('</', elt.nodeName.toLowerCase(), '>');
  1582. }
  1583. else if (isElementSVG(elt) || isElementMathML(elt))
  1584. {
  1585. html.push('/>');
  1586. }
  1587. else if (self.isSelfClosing(elt))
  1588. {
  1589. html.push((isElementXHTML(elt))?'/>':'>');
  1590. }
  1591. else
  1592. {
  1593. html.push('></', elt.nodeName.toLowerCase(), '>');
  1594. }
  1595. }
  1596. else if (elt.nodeType == Node.TEXT_NODE)
  1597. html.push(escapeForTextNode(elt.textContent));
  1598. else if (elt.nodeType == Node.CDATA_SECTION_NODE)
  1599. html.push('<![CDATA[', elt.nodeValue, ']]>');
  1600. else if (elt.nodeType == Node.COMMENT_NODE)
  1601. html.push('<!--', elt.nodeValue, '-->');
  1602. }
  1603. var html = [];
  1604. toHTML(element);
  1605. return html.join("");
  1606. };
  1607. this.getElementXML = function(element)
  1608. {
  1609. function toXML(elt)
  1610. {
  1611. if (elt.nodeType == Node.ELEMENT_NODE)
  1612. {
  1613. if (unwrapObject(elt).firebugIgnore)
  1614. return;
  1615. xml.push('<', elt.nodeName.toLowerCase());
  1616. for (var i = 0; i < elt.attributes.length; ++i)
  1617. {
  1618. var attr = elt.attributes[i];
  1619. // Hide attributes set by Firebug
  1620. if (attr.localName.indexOf("firebug-") == 0)
  1621. continue;
  1622. // MathML
  1623. if (attr.localName.indexOf("-moz-math") == 0)
  1624. {
  1625. // just hide for now
  1626. continue;
  1627. }
  1628. xml.push(' ', attr.nodeName, '="', escapeForElementAttribute(attr.nodeValue),'"');
  1629. }
  1630. if (elt.firstChild)
  1631. {
  1632. xml.push('>');
  1633. for (var child = elt.firstChild; child; child = child.nextSibling)
  1634. toXML(child);
  1635. xml.push('</', elt.nodeName.toLowerCase(), '>');
  1636. }
  1637. else
  1638. xml.push('/>');
  1639. }
  1640. else if (elt.nodeType == Node.TEXT_NODE)
  1641. xml.push(elt.nodeValue);
  1642. else if (elt.nodeType == Node.CDATA_SECTION_NODE)
  1643. xml.push('<![CDATA[', elt.nodeValue, ']]>');
  1644. else if (elt.nodeType == Node.COMMENT_NODE)
  1645. xml.push('<!--', elt.nodeValue, '-->');
  1646. }
  1647. var xml = [];
  1648. toXML(element);
  1649. return xml.join("");
  1650. };
  1651. // ************************************************************************************************
  1652. // CSS classes
  1653. this.hasClass = function(node, name) // className, className, ...
  1654. {
  1655. // TODO: xxxpedro when lib.hasClass is called with more than 2 arguments?
  1656. // this function can be optimized a lot if assumed 2 arguments only,
  1657. // which seems to be what happens 99% of the time
  1658. if (arguments.length == 2)
  1659. return (' '+node.className+' ').indexOf(' '+name+' ') != -1;
  1660. if (!node || node.nodeType != 1)
  1661. return false;
  1662. else
  1663. {
  1664. for (var i=1; i<arguments.length; ++i)
  1665. {
  1666. var name = arguments[i];
  1667. var re = new RegExp("(^|\\s)"+name+"($|\\s)");
  1668. if (!re.exec(node.className))
  1669. return false;
  1670. }
  1671. return true;
  1672. }
  1673. };
  1674. this.old_hasClass = function(node, name) // className, className, ...
  1675. {
  1676. if (!node || node.nodeType != 1)
  1677. return false;
  1678. else
  1679. {
  1680. for (var i=1; i<arguments.length; ++i)
  1681. {
  1682. var name = arguments[i];
  1683. var re = new RegExp("(^|\\s)"+name+"($|\\s)");
  1684. if (!re.exec(node.className))
  1685. return false;
  1686. }
  1687. return true;
  1688. }
  1689. };
  1690. this.setClass = function(node, name)
  1691. {
  1692. if (node && (' '+node.className+' ').indexOf(' '+name+' ') == -1)
  1693. ///if (node && !this.hasClass(node, name))
  1694. node.className += " " + name;
  1695. };
  1696. this.getClassValue = function(node, name)
  1697. {
  1698. var re = new RegExp(name+"-([^ ]+)");
  1699. var m = re.exec(node.className);
  1700. return m ? m[1] : "";
  1701. };
  1702. this.removeClass = function(node, name)
  1703. {
  1704. if (node && node.className)
  1705. {
  1706. var index = node.className.indexOf(name);
  1707. if (index >= 0)
  1708. {
  1709. var size = name.length;
  1710. node.className = node.className.substr(0,index-1) + node.className.substr(index+size);
  1711. }
  1712. }
  1713. };
  1714. this.toggleClass = function(elt, name)
  1715. {
  1716. if ((' '+elt.className+' ').indexOf(' '+name+' ') != -1)
  1717. ///if (this.hasClass(elt, name))
  1718. this.removeClass(elt, name);
  1719. else
  1720. this.setClass(elt, name);
  1721. };
  1722. this.setClassTimed = function(elt, name, context, timeout)
  1723. {
  1724. if (!timeout)
  1725. timeout = 1300;
  1726. if (elt.__setClassTimeout)
  1727. context.clearTimeout(elt.__setClassTimeout);
  1728. else
  1729. this.setClass(elt, name);
  1730. elt.__setClassTimeout = context.setTimeout(function()
  1731. {
  1732. delete elt.__setClassTimeout;
  1733. FBL.removeClass(elt, name);
  1734. }, timeout);
  1735. };
  1736. this.cancelClassTimed = function(elt, name, context)
  1737. {
  1738. if (elt.__setClassTimeout)
  1739. {
  1740. FBL.removeClass(elt, name);
  1741. context.clearTimeout(elt.__setClassTimeout);
  1742. delete elt.__setClassTimeout;
  1743. }
  1744. };
  1745. // ************************************************************************************************
  1746. // DOM queries
  1747. this.$ = function(id, doc)
  1748. {
  1749. if (doc)
  1750. return doc.getElementById(id);
  1751. else
  1752. {
  1753. return FBL.Firebug.chrome.document.getElementById(id);
  1754. }
  1755. };
  1756. this.$$ = function(selector, doc)
  1757. {
  1758. if (doc || !FBL.Firebug.chrome)
  1759. return FBL.Firebug.Selector(selector, doc);
  1760. else
  1761. {
  1762. return FBL.Firebug.Selector(selector, FBL.Firebug.chrome.document);
  1763. }
  1764. };
  1765. this.getChildByClass = function(node) // ,classname, classname, classname...
  1766. {
  1767. for (var i = 1; i < arguments.length; ++i)
  1768. {
  1769. var className = arguments[i];
  1770. var child = node.firstChild;
  1771. node = null;
  1772. for (; child; child = child.nextSibling)
  1773. {
  1774. if (this.hasClass(child, className))
  1775. {
  1776. node = child;
  1777. break;
  1778. }
  1779. }
  1780. }
  1781. return node;
  1782. };
  1783. this.getAncestorByClass = function(node, className)
  1784. {
  1785. for (var parent = node; parent; parent = parent.parentNode)
  1786. {
  1787. if (this.hasClass(parent, className))
  1788. return parent;
  1789. }
  1790. return null;
  1791. };
  1792. this.getElementsByClass = function(node, className)
  1793. {
  1794. var result = [];
  1795. for (var child = node.firstChild; child; child = child.nextSibling)
  1796. {
  1797. if (this.hasClass(child, className))
  1798. result.push(child);
  1799. }
  1800. return result;
  1801. };
  1802. this.getElementByClass = function(node, className) // className, className, ...
  1803. {
  1804. var args = cloneArray(arguments); args.splice(0, 1);
  1805. for (var child = node.firstChild; child; child = child.nextSibling)
  1806. {
  1807. var args1 = cloneArray(args); args1.unshift(child);
  1808. if (FBL.hasClass.apply(null, args1))
  1809. return child;
  1810. else
  1811. {
  1812. var found = FBL.getElementByClass.apply(null, args1);
  1813. if (found)
  1814. return found;
  1815. }
  1816. }
  1817. return null;
  1818. };
  1819. this.isAncestor = function(node, potentialAncestor)
  1820. {
  1821. for (var parent = node; parent; parent = parent.parentNode)
  1822. {
  1823. if (parent == potentialAncestor)
  1824. return true;
  1825. }
  1826. return false;
  1827. };
  1828. this.getNextElement = function(node)
  1829. {
  1830. while (node && node.nodeType != 1)
  1831. node = node.nextSibling;
  1832. return node;
  1833. };
  1834. this.getPreviousElement = function(node)
  1835. {
  1836. while (node && node.nodeType != 1)
  1837. node = node.previousSibling;
  1838. return node;
  1839. };
  1840. this.getBody = function(doc)
  1841. {
  1842. if (doc.body)
  1843. return doc.body;
  1844. var body = doc.getElementsByTagName("body")[0];
  1845. if (body)
  1846. return body;
  1847. return doc.firstChild; // For non-HTML docs
  1848. };
  1849. this.findNextDown = function(node, criteria)
  1850. {
  1851. if (!node)
  1852. return null;
  1853. for (var child = node.firstChild; child; child = child.nextSibling)
  1854. {
  1855. if (criteria(child))
  1856. return child;
  1857. var next = this.findNextDown(child, criteria);
  1858. if (next)
  1859. return next;
  1860. }
  1861. };
  1862. this.findPreviousUp = function(node, criteria)
  1863. {
  1864. if (!node)
  1865. return null;
  1866. for (var child = node.lastChild; child; child = child.previousSibling)
  1867. {
  1868. var next = this.findPreviousUp(child, criteria);
  1869. if (next)
  1870. return next;
  1871. if (criteria(child))
  1872. return child;
  1873. }
  1874. };
  1875. this.findNext = function(node, criteria, upOnly, maxRoot)
  1876. {
  1877. if (!node)
  1878. return null;
  1879. if (!upOnly)
  1880. {
  1881. var next = this.findNextDown(node, criteria);
  1882. if (next)
  1883. return next;
  1884. }
  1885. for (var sib = node.nextSibling; sib; sib = sib.nextSibling)
  1886. {
  1887. if (criteria(sib))
  1888. return sib;
  1889. var next = this.findNextDown(sib, criteria);
  1890. if (next)
  1891. return next;
  1892. }
  1893. if (node.parentNode && node.parentNode != maxRoot)
  1894. return this.findNext(node.parentNode, criteria, true);
  1895. };
  1896. this.findPrevious = function(node, criteria, downOnly, maxRoot)
  1897. {
  1898. if (!node)
  1899. return null;
  1900. for (var sib = node.previousSibling; sib; sib = sib.previousSibling)
  1901. {
  1902. var prev = this.findPreviousUp(sib, criteria);
  1903. if (prev)
  1904. return prev;
  1905. if (criteria(sib))
  1906. return sib;
  1907. }
  1908. if (!downOnly)
  1909. {
  1910. var next = this.findPreviousUp(node, criteria);
  1911. if (next)
  1912. return next;
  1913. }
  1914. if (node.parentNode && node.parentNode != maxRoot)
  1915. {
  1916. if (criteria(node.parentNode))
  1917. return node.parentNode;
  1918. return this.findPrevious(node.parentNode, criteria, true);
  1919. }
  1920. };
  1921. this.getNextByClass = function(root, state)
  1922. {
  1923. var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); };
  1924. return this.findNext(root, iter);
  1925. };
  1926. this.getPreviousByClass = function(root, state)
  1927. {
  1928. var iter = function iter(node) { return node.nodeType == 1 && FBL.hasClass(node, state); };
  1929. return this.findPrevious(root, iter);
  1930. };
  1931. this.isElement = function(o)
  1932. {
  1933. try {
  1934. return o && this.instanceOf(o, "Element");
  1935. }
  1936. catch (ex) {
  1937. return false;
  1938. }
  1939. };
  1940. // ************************************************************************************************
  1941. // DOM Modification
  1942. // TODO: xxxpedro use doc fragments in Context API
  1943. var appendFragment = null;
  1944. this.appendInnerHTML = function(element, html, referenceElement)
  1945. {
  1946. // if undefined, we must convert it to null otherwise it will throw an error in IE
  1947. // when executing element.insertBefore(firstChild, referenceElement)
  1948. referenceElement = referenceElement || null;
  1949. var doc = element.ownerDocument;
  1950. // doc.createRange not available in IE
  1951. if (doc.createRange)
  1952. {
  1953. var range = doc.createRange(); // a helper object
  1954. range.selectNodeContents(element); // the environment to interpret the html
  1955. var fragment = range.createContextualFragment(html); // parse
  1956. var firstChild = fragment.firstChild;
  1957. element.insertBefore(fragment, referenceElement);
  1958. }
  1959. else
  1960. {
  1961. if (!appendFragment || appendFragment.ownerDocument != doc)
  1962. appendFragment = doc.createDocumentFragment();
  1963. var div = doc.createElement("div");
  1964. div.innerHTML = html;
  1965. var firstChild = div.firstChild;
  1966. while (div.firstChild)
  1967. appendFragment.appendChild(div.firstChild);
  1968. element.insertBefore(appendFragment, referenceElement);
  1969. div = null;
  1970. }
  1971. return firstChild;
  1972. };
  1973. // ************************************************************************************************
  1974. // DOM creation
  1975. this.createElement = function(tagName, properties)
  1976. {
  1977. properties = properties || {};
  1978. var doc = properties.document || FBL.Firebug.chrome.document;
  1979. var element = doc.createElement(tagName);
  1980. for(var name in properties)
  1981. {
  1982. if (name != "document")
  1983. {
  1984. element[name] = properties[name];
  1985. }
  1986. }
  1987. return element;
  1988. };
  1989. this.createGlobalElement = function(tagName, properties)
  1990. {
  1991. properties = properties || {};
  1992. var doc = FBL.Env.browser.document;
  1993. var element = this.NS && doc.createElementNS ?
  1994. doc.createElementNS(FBL.NS, tagName) :
  1995. doc.createElement(tagName);
  1996. for(var name in properties)
  1997. {
  1998. var propname = name;
  1999. if (FBL.isIE && name == "class") propname = "className";
  2000. if (name != "document")
  2001. {
  2002. element.setAttribute(propname, properties[name]);
  2003. }
  2004. }
  2005. return element;
  2006. };
  2007. //************************************************************************************************
  2008. this.safeGetWindowLocation = function(window)
  2009. {
  2010. try
  2011. {
  2012. if (window)
  2013. {
  2014. if (window.closed)
  2015. return "(window.closed)";
  2016. if ("location" in window)
  2017. return window.location+"";
  2018. else
  2019. return "(no window.location)";
  2020. }
  2021. else
  2022. return "(no context.window)";
  2023. }
  2024. catch(exc)
  2025. {
  2026. if (FBTrace.DBG_WINDOWS || FBTrace.DBG_ERRORS)
  2027. FBTrace.sysout("TabContext.getWindowLocation failed "+exc, exc);
  2028. FBTrace.sysout("TabContext.getWindowLocation failed window:", window);
  2029. return "(getWindowLocation: "+exc+")";
  2030. }
  2031. };
  2032. // ************************************************************************************************
  2033. // Events
  2034. this.isLeftClick = function(event)
  2035. {
  2036. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2037. event.button == 1 : // IE "click" and "dblclick" button model
  2038. event.button == 0) && // others
  2039. this.noKeyModifiers(event);
  2040. };
  2041. this.isMiddleClick = function(event)
  2042. {
  2043. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2044. event.button == 4 : // IE "click" and "dblclick" button model
  2045. event.button == 1) &&
  2046. this.noKeyModifiers(event);
  2047. };
  2048. this.isRightClick = function(event)
  2049. {
  2050. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2051. event.button == 2 : // IE "click" and "dblclick" button model
  2052. event.button == 2) &&
  2053. this.noKeyModifiers(event);
  2054. };
  2055. this.noKeyModifiers = function(event)
  2056. {
  2057. return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
  2058. };
  2059. this.isControlClick = function(event)
  2060. {
  2061. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2062. event.button == 1 : // IE "click" and "dblclick" button model
  2063. event.button == 0) &&
  2064. this.isControl(event);
  2065. };
  2066. this.isShiftClick = function(event)
  2067. {
  2068. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2069. event.button == 1 : // IE "click" and "dblclick" button model
  2070. event.button == 0) &&
  2071. this.isShift(event);
  2072. };
  2073. this.isControl = function(event)
  2074. {
  2075. return (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey;
  2076. };
  2077. this.isAlt = function(event)
  2078. {
  2079. return event.altKey && !event.ctrlKey && !event.shiftKey && !event.metaKey;
  2080. };
  2081. this.isAltClick = function(event)
  2082. {
  2083. return (this.isIE && event.type != "click" && event.type != "dblclick" ?
  2084. event.button == 1 : // IE "click" and "dblclick" button model
  2085. event.button == 0) &&
  2086. this.isAlt(event);
  2087. };
  2088. this.isControlShift = function(event)
  2089. {
  2090. return (event.metaKey || event.ctrlKey) && event.shiftKey && !event.altKey;
  2091. };
  2092. this.isShift = function(event)
  2093. {
  2094. return event.shiftKey && !event.metaKey && !event.ctrlKey && !event.altKey;
  2095. };
  2096. this.addEvent = function(object, name, handler, useCapture)
  2097. {
  2098. if (object.addEventListener)
  2099. object.addEventListener(name, handler, useCapture);
  2100. else
  2101. object.attachEvent("on"+name, handler);
  2102. };
  2103. this.removeEvent = function(object, name, handler, useCapture)
  2104. {
  2105. try
  2106. {
  2107. if (object.removeEventListener)
  2108. object.removeEventListener(name, handler, useCapture);
  2109. else
  2110. object.detachEvent("on"+name, handler);
  2111. }
  2112. catch(e)
  2113. {
  2114. if (FBTrace.DBG_ERRORS)
  2115. FBTrace.sysout("FBL.removeEvent error: ", object, name);
  2116. }
  2117. };
  2118. this.cancelEvent = function(e, preventDefault)
  2119. {
  2120. if (!e) return;
  2121. if (preventDefault)
  2122. {
  2123. if (e.preventDefault)
  2124. e.preventDefault();
  2125. else
  2126. e.returnValue = false;
  2127. }
  2128. if (e.stopPropagation)
  2129. e.stopPropagation();
  2130. else
  2131. e.cancelBubble = true;
  2132. };
  2133. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2134. this.addGlobalEvent = function(name, handler)
  2135. {
  2136. var doc = this.Firebug.browser.document;
  2137. var frames = this.Firebug.browser.window.frames;
  2138. this.addEvent(doc, name, handler);
  2139. if (this.Firebug.chrome.type == "popup")
  2140. this.addEvent(this.Firebug.chrome.document, name, handler);
  2141. for (var i = 0, frame; frame = frames[i]; i++)
  2142. {
  2143. try
  2144. {
  2145. this.addEvent(frame.document, name, handler);
  2146. }
  2147. catch(E)
  2148. {
  2149. // Avoid acess denied
  2150. }
  2151. }
  2152. };
  2153. this.removeGlobalEvent = function(name, handler)
  2154. {
  2155. var doc = this.Firebug.browser.document;
  2156. var frames = this.Firebug.browser.window.frames;
  2157. this.removeEvent(doc, name, handler);
  2158. if (this.Firebug.chrome.type == "popup")
  2159. this.removeEvent(this.Firebug.chrome.document, name, handler);
  2160. for (var i = 0, frame; frame = frames[i]; i++)
  2161. {
  2162. try
  2163. {
  2164. this.removeEvent(frame.document, name, handler);
  2165. }
  2166. catch(E)
  2167. {
  2168. // Avoid acess denied
  2169. }
  2170. }
  2171. };
  2172. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2173. this.dispatch = function(listeners, name, args)
  2174. {
  2175. if (!listeners) return;
  2176. try
  2177. {/**/
  2178. if (typeof listeners.length != "undefined")
  2179. {
  2180. if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to "+listeners.length+" listeners");
  2181. for (var i = 0; i < listeners.length; ++i)
  2182. {
  2183. var listener = listeners[i];
  2184. if ( listener[name] )
  2185. listener[name].apply(listener, args);
  2186. }
  2187. }
  2188. else
  2189. {
  2190. if (FBTrace.DBG_DISPATCH) FBTrace.sysout("FBL.dispatch", name+" to listeners of an object");
  2191. for (var prop in listeners)
  2192. {
  2193. var listener = listeners[prop];
  2194. if ( listener[name] )
  2195. listener[name].apply(listener, args);
  2196. }
  2197. }
  2198. }
  2199. catch (exc)
  2200. {
  2201. if (FBTrace.DBG_ERRORS)
  2202. {
  2203. FBTrace.sysout(" Exception in lib.dispatch "+ name, exc);
  2204. //FBTrace.dumpProperties(" Exception in lib.dispatch listener", listener);
  2205. }
  2206. }
  2207. /**/
  2208. };
  2209. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2210. var disableTextSelectionHandler = function(event)
  2211. {
  2212. FBL.cancelEvent(event, true);
  2213. return false;
  2214. };
  2215. this.disableTextSelection = function(e)
  2216. {
  2217. if (typeof e.onselectstart != "undefined") // IE
  2218. this.addEvent(e, "selectstart", disableTextSelectionHandler);
  2219. else // others
  2220. {
  2221. e.style.cssText = "user-select: none; -khtml-user-select: none; -moz-user-select: none;";
  2222. // canceling the event in FF will prevent the menu popups to close when clicking over
  2223. // text-disabled elements
  2224. if (!this.isFirefox)
  2225. this.addEvent(e, "mousedown", disableTextSelectionHandler);
  2226. }
  2227. e.style.cursor = "default";
  2228. };
  2229. this.restoreTextSelection = function(e)
  2230. {
  2231. if (typeof e.onselectstart != "undefined") // IE
  2232. this.removeEvent(e, "selectstart", disableTextSelectionHandler);
  2233. else // others
  2234. {
  2235. e.style.cssText = "cursor: default;";
  2236. // canceling the event in FF will prevent the menu popups to close when clicking over
  2237. // text-disabled elements
  2238. if (!this.isFirefox)
  2239. this.removeEvent(e, "mousedown", disableTextSelectionHandler);
  2240. }
  2241. };
  2242. // ************************************************************************************************
  2243. // DOM Events
  2244. var eventTypes =
  2245. {
  2246. composition: [
  2247. "composition",
  2248. "compositionstart",
  2249. "compositionend" ],
  2250. contextmenu: [
  2251. "contextmenu" ],
  2252. drag: [
  2253. "dragenter",
  2254. "dragover",
  2255. "dragexit",
  2256. "dragdrop",
  2257. "draggesture" ],
  2258. focus: [
  2259. "focus",
  2260. "blur" ],
  2261. form: [
  2262. "submit",
  2263. "reset",
  2264. "change",
  2265. "select",
  2266. "input" ],
  2267. key: [
  2268. "keydown",
  2269. "keyup",
  2270. "keypress" ],
  2271. load: [
  2272. "load",
  2273. "beforeunload",
  2274. "unload",
  2275. "abort",
  2276. "error" ],
  2277. mouse: [
  2278. "mousedown",
  2279. "mouseup",
  2280. "click",
  2281. "dblclick",
  2282. "mouseover",
  2283. "mouseout",
  2284. "mousemove" ],
  2285. mutation: [
  2286. "DOMSubtreeModified",
  2287. "DOMNodeInserted",
  2288. "DOMNodeRemoved",
  2289. "DOMNodeRemovedFromDocument",
  2290. "DOMNodeInsertedIntoDocument",
  2291. "DOMAttrModified",
  2292. "DOMCharacterDataModified" ],
  2293. paint: [
  2294. "paint",
  2295. "resize",
  2296. "scroll" ],
  2297. scroll: [
  2298. "overflow",
  2299. "underflow",
  2300. "overflowchanged" ],
  2301. text: [
  2302. "text" ],
  2303. ui: [
  2304. "DOMActivate",
  2305. "DOMFocusIn",
  2306. "DOMFocusOut" ],
  2307. xul: [
  2308. "popupshowing",
  2309. "popupshown",
  2310. "popuphiding",
  2311. "popuphidden",
  2312. "close",
  2313. "command",
  2314. "broadcast",
  2315. "commandupdate" ]
  2316. };
  2317. this.getEventFamily = function(eventType)
  2318. {
  2319. if (!this.families)
  2320. {
  2321. this.families = {};
  2322. for (var family in eventTypes)
  2323. {
  2324. var types = eventTypes[family];
  2325. for (var i = 0; i < types.length; ++i)
  2326. this.families[types[i]] = family;
  2327. }
  2328. }
  2329. return this.families[eventType];
  2330. };
  2331. // ************************************************************************************************
  2332. // URLs
  2333. this.getFileName = function(url)
  2334. {
  2335. var split = this.splitURLBase(url);
  2336. return split.name;
  2337. };
  2338. this.splitURLBase = function(url)
  2339. {
  2340. if (this.isDataURL(url))
  2341. return this.splitDataURL(url);
  2342. return this.splitURLTrue(url);
  2343. };
  2344. this.splitDataURL = function(url)
  2345. {
  2346. var mark = url.indexOf(':', 3);
  2347. if (mark != 4)
  2348. return false; // the first 5 chars must be 'data:'
  2349. var point = url.indexOf(',', mark+1);
  2350. if (point < mark)
  2351. return false; // syntax error
  2352. var props = { encodedContent: url.substr(point+1) };
  2353. var metadataBuffer = url.substr(mark+1, point);
  2354. var metadata = metadataBuffer.split(';');
  2355. for (var i = 0; i < metadata.length; i++)
  2356. {
  2357. var nv = metadata[i].split('=');
  2358. if (nv.length == 2)
  2359. props[nv[0]] = nv[1];
  2360. }
  2361. // Additional Firebug-specific properties
  2362. if (props.hasOwnProperty('fileName'))
  2363. {
  2364. var caller_URL = decodeURIComponent(props['fileName']);
  2365. var caller_split = this.splitURLTrue(caller_URL);
  2366. if (props.hasOwnProperty('baseLineNumber')) // this means it's probably an eval()
  2367. {
  2368. props['path'] = caller_split.path;
  2369. props['line'] = props['baseLineNumber'];
  2370. var hint = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, "");
  2371. props['name'] = 'eval->'+hint;
  2372. }
  2373. else
  2374. {
  2375. props['name'] = caller_split.name;
  2376. props['path'] = caller_split.path;
  2377. }
  2378. }
  2379. else
  2380. {
  2381. if (!props.hasOwnProperty('path'))
  2382. props['path'] = "data:";
  2383. if (!props.hasOwnProperty('name'))
  2384. props['name'] = decodeURIComponent(props['encodedContent'].substr(0,200)).replace(/\s*$/, "");
  2385. }
  2386. return props;
  2387. };
  2388. this.splitURLTrue = function(url)
  2389. {
  2390. var m = reSplitFile.exec(url);
  2391. if (!m)
  2392. return {name: url, path: url};
  2393. else if (!m[2])
  2394. return {path: m[1], name: m[1]};
  2395. else
  2396. return {path: m[1], name: m[2]+m[3]};
  2397. };
  2398. this.getFileExtension = function(url)
  2399. {
  2400. if (!url)
  2401. return null;
  2402. // Remove query string from the URL if any.
  2403. var queryString = url.indexOf("?");
  2404. if (queryString != -1)
  2405. url = url.substr(0, queryString);
  2406. // Now get the file extension.
  2407. var lastDot = url.lastIndexOf(".");
  2408. return url.substr(lastDot+1);
  2409. };
  2410. this.isSystemURL = function(url)
  2411. {
  2412. if (!url) return true;
  2413. if (url.length == 0) return true;
  2414. if (url[0] == 'h') return false;
  2415. if (url.substr(0, 9) == "resource:")
  2416. return true;
  2417. else if (url.substr(0, 16) == "chrome://firebug")
  2418. return true;
  2419. else if (url == "XPCSafeJSObjectWrapper.cpp")
  2420. return true;
  2421. else if (url.substr(0, 6) == "about:")
  2422. return true;
  2423. else if (url.indexOf("firebug-service.js") != -1)
  2424. return true;
  2425. else
  2426. return false;
  2427. };
  2428. this.isSystemPage = function(win)
  2429. {
  2430. try
  2431. {
  2432. var doc = win.document;
  2433. if (!doc)
  2434. return false;
  2435. // Detect pages for pretty printed XML
  2436. if ((doc.styleSheets.length && doc.styleSheets[0].href
  2437. == "chrome://global/content/xml/XMLPrettyPrint.css")
  2438. || (doc.styleSheets.length > 1 && doc.styleSheets[1].href
  2439. == "chrome://browser/skin/feeds/subscribe.css"))
  2440. return true;
  2441. return FBL.isSystemURL(win.location.href);
  2442. }
  2443. catch (exc)
  2444. {
  2445. // Sometimes documents just aren't ready to be manipulated here, but don't let that
  2446. // gum up the works
  2447. ERROR("tabWatcher.isSystemPage document not ready:"+ exc);
  2448. return false;
  2449. }
  2450. };
  2451. this.isSystemStyleSheet = function(sheet)
  2452. {
  2453. var href = sheet && sheet.href;
  2454. return href && FBL.isSystemURL(href);
  2455. };
  2456. this.getURIHost = function(uri)
  2457. {
  2458. try
  2459. {
  2460. if (uri)
  2461. return uri.host;
  2462. else
  2463. return "";
  2464. }
  2465. catch (exc)
  2466. {
  2467. return "";
  2468. }
  2469. };
  2470. this.isLocalURL = function(url)
  2471. {
  2472. if (url.substr(0, 5) == "file:")
  2473. return true;
  2474. else if (url.substr(0, 8) == "wyciwyg:")
  2475. return true;
  2476. else
  2477. return false;
  2478. };
  2479. this.isDataURL = function(url)
  2480. {
  2481. return (url && url.substr(0,5) == "data:");
  2482. };
  2483. this.getLocalPath = function(url)
  2484. {
  2485. if (this.isLocalURL(url))
  2486. {
  2487. var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
  2488. var file = fileHandler.getFileFromURLSpec(url);
  2489. return file.path;
  2490. }
  2491. };
  2492. this.getURLFromLocalFile = function(file)
  2493. {
  2494. var fileHandler = ioService.getProtocolHandler("file").QueryInterface(Ci.nsIFileProtocolHandler);
  2495. var URL = fileHandler.getURLSpecFromFile(file);
  2496. return URL;
  2497. };
  2498. this.getDataURLForContent = function(content, url)
  2499. {
  2500. // data:text/javascript;fileName=x%2Cy.js;baseLineNumber=10,<the-url-encoded-data>
  2501. var uri = "data:text/html;";
  2502. uri += "fileName="+encodeURIComponent(url)+ ",";
  2503. uri += encodeURIComponent(content);
  2504. return uri;
  2505. },
  2506. this.getDomain = function(url)
  2507. {
  2508. var m = /[^:]+:\/{1,3}([^\/]+)/.exec(url);
  2509. return m ? m[1] : "";
  2510. };
  2511. this.getURLPath = function(url)
  2512. {
  2513. var m = /[^:]+:\/{1,3}[^\/]+(\/.*?)$/.exec(url);
  2514. return m ? m[1] : "";
  2515. };
  2516. this.getPrettyDomain = function(url)
  2517. {
  2518. var m = /[^:]+:\/{1,3}(www\.)?([^\/]+)/.exec(url);
  2519. return m ? m[2] : "";
  2520. };
  2521. this.absoluteURL = function(url, baseURL)
  2522. {
  2523. return this.absoluteURLWithDots(url, baseURL).replace("/./", "/", "g");
  2524. };
  2525. this.absoluteURLWithDots = function(url, baseURL)
  2526. {
  2527. if (url[0] == "?")
  2528. return baseURL + url;
  2529. var reURL = /(([^:]+:)\/{1,2}[^\/]*)(.*?)$/;
  2530. var m = reURL.exec(url);
  2531. if (m)
  2532. return url;
  2533. var m = reURL.exec(baseURL);
  2534. if (!m)
  2535. return "";
  2536. var head = m[1];
  2537. var tail = m[3];
  2538. if (url.substr(0, 2) == "//")
  2539. return m[2] + url;
  2540. else if (url[0] == "/")
  2541. {
  2542. return head + url;
  2543. }
  2544. else if (tail[tail.length-1] == "/")
  2545. return baseURL + url;
  2546. else
  2547. {
  2548. var parts = tail.split("/");
  2549. return head + parts.slice(0, parts.length-1).join("/") + "/" + url;
  2550. }
  2551. };
  2552. this.normalizeURL = function(url) // this gets called a lot, any performance improvement welcome
  2553. {
  2554. if (!url)
  2555. return "";
  2556. // Replace one or more characters that are not forward-slash followed by /.., by space.
  2557. if (url.length < 255) // guard against monsters.
  2558. {
  2559. // Replace one or more characters that are not forward-slash followed by /.., by space.
  2560. url = url.replace(/[^\/]+\/\.\.\//, "", "g");
  2561. // Issue 1496, avoid #
  2562. url = url.replace(/#.*/,"");
  2563. // For some reason, JSDS reports file URLs like "file:/" instead of "file:///", so they
  2564. // don't match up with the URLs we get back from the DOM
  2565. url = url.replace(/file:\/([^\/])/g, "file:///$1");
  2566. if (url.indexOf('chrome:')==0)
  2567. {
  2568. var m = reChromeCase.exec(url); // 1 is package name, 2 is path
  2569. if (m)
  2570. {
  2571. url = "chrome://"+m[1].toLowerCase()+"/"+m[2];
  2572. }
  2573. }
  2574. }
  2575. return url;
  2576. };
  2577. this.denormalizeURL = function(url)
  2578. {
  2579. return url.replace(/file:\/\/\//g, "file:/");
  2580. };
  2581. this.parseURLParams = function(url)
  2582. {
  2583. var q = url ? url.indexOf("?") : -1;
  2584. if (q == -1)
  2585. return [];
  2586. var search = url.substr(q+1);
  2587. var h = search.lastIndexOf("#");
  2588. if (h != -1)
  2589. search = search.substr(0, h);
  2590. if (!search)
  2591. return [];
  2592. return this.parseURLEncodedText(search);
  2593. };
  2594. this.parseURLEncodedText = function(text)
  2595. {
  2596. var maxValueLength = 25000;
  2597. var params = [];
  2598. // Unescape '+' characters that are used to encode a space.
  2599. // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt
  2600. text = text.replace(/\+/g, " ");
  2601. var args = text.split("&");
  2602. for (var i = 0; i < args.length; ++i)
  2603. {
  2604. try {
  2605. var parts = args[i].split("=");
  2606. if (parts.length == 2)
  2607. {
  2608. if (parts[1].length > maxValueLength)
  2609. parts[1] = this.$STR("LargeData");
  2610. params.push({name: decodeURIComponent(parts[0]), value: decodeURIComponent(parts[1])});
  2611. }
  2612. else
  2613. params.push({name: decodeURIComponent(parts[0]), value: ""});
  2614. }
  2615. catch (e)
  2616. {
  2617. if (FBTrace.DBG_ERRORS)
  2618. {
  2619. FBTrace.sysout("parseURLEncodedText EXCEPTION ", e);
  2620. FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]);
  2621. }
  2622. }
  2623. }
  2624. params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; });
  2625. return params;
  2626. };
  2627. // TODO: xxxpedro lib. why loops in domplate are requiring array in parameters
  2628. // as in response/request headers and get/post parameters in Net module?
  2629. this.parseURLParamsArray = function(url)
  2630. {
  2631. var q = url ? url.indexOf("?") : -1;
  2632. if (q == -1)
  2633. return [];
  2634. var search = url.substr(q+1);
  2635. var h = search.lastIndexOf("#");
  2636. if (h != -1)
  2637. search = search.substr(0, h);
  2638. if (!search)
  2639. return [];
  2640. return this.parseURLEncodedTextArray(search);
  2641. };
  2642. this.parseURLEncodedTextArray = function(text)
  2643. {
  2644. var maxValueLength = 25000;
  2645. var params = [];
  2646. // Unescape '+' characters that are used to encode a space.
  2647. // See section 2.2.in RFC 3986: http://www.ietf.org/rfc/rfc3986.txt
  2648. text = text.replace(/\+/g, " ");
  2649. var args = text.split("&");
  2650. for (var i = 0; i < args.length; ++i)
  2651. {
  2652. try {
  2653. var parts = args[i].split("=");
  2654. if (parts.length == 2)
  2655. {
  2656. if (parts[1].length > maxValueLength)
  2657. parts[1] = this.$STR("LargeData");
  2658. params.push({name: decodeURIComponent(parts[0]), value: [decodeURIComponent(parts[1])]});
  2659. }
  2660. else
  2661. params.push({name: decodeURIComponent(parts[0]), value: [""]});
  2662. }
  2663. catch (e)
  2664. {
  2665. if (FBTrace.DBG_ERRORS)
  2666. {
  2667. FBTrace.sysout("parseURLEncodedText EXCEPTION ", e);
  2668. FBTrace.sysout("parseURLEncodedText EXCEPTION URI", args[i]);
  2669. }
  2670. }
  2671. }
  2672. params.sort(function(a, b) { return a.name <= b.name ? -1 : 1; });
  2673. return params;
  2674. };
  2675. this.reEncodeURL = function(file, text)
  2676. {
  2677. var lines = text.split("\n");
  2678. var params = this.parseURLEncodedText(lines[lines.length-1]);
  2679. var args = [];
  2680. for (var i = 0; i < params.length; ++i)
  2681. args.push(encodeURIComponent(params[i].name)+"="+encodeURIComponent(params[i].value));
  2682. var url = file.href;
  2683. url += (url.indexOf("?") == -1 ? "?" : "&") + args.join("&");
  2684. return url;
  2685. };
  2686. this.getResource = function(aURL)
  2687. {
  2688. try
  2689. {
  2690. var channel=ioService.newChannel(aURL,null,null);
  2691. var input=channel.open();
  2692. return FBL.readFromStream(input);
  2693. }
  2694. catch (e)
  2695. {
  2696. if (FBTrace.DBG_ERRORS)
  2697. FBTrace.sysout("lib.getResource FAILS for "+aURL, e);
  2698. }
  2699. };
  2700. this.parseJSONString = function(jsonString, originURL)
  2701. {
  2702. // See if this is a Prototype style *-secure request.
  2703. var regex = new RegExp(/^\/\*-secure-([\s\S]*)\*\/\s*$/);
  2704. var matches = regex.exec(jsonString);
  2705. if (matches)
  2706. {
  2707. jsonString = matches[1];
  2708. if (jsonString[0] == "\\" && jsonString[1] == "n")
  2709. jsonString = jsonString.substr(2);
  2710. if (jsonString[jsonString.length-2] == "\\" && jsonString[jsonString.length-1] == "n")
  2711. jsonString = jsonString.substr(0, jsonString.length-2);
  2712. }
  2713. if (jsonString.indexOf("&&&START&&&"))
  2714. {
  2715. regex = new RegExp(/&&&START&&& (.+) &&&END&&&/);
  2716. matches = regex.exec(jsonString);
  2717. if (matches)
  2718. jsonString = matches[1];
  2719. }
  2720. // throw on the extra parentheses
  2721. jsonString = "(" + jsonString + ")";
  2722. ///var s = Components.utils.Sandbox(originURL);
  2723. var jsonObject = null;
  2724. try
  2725. {
  2726. ///jsonObject = Components.utils.evalInSandbox(jsonString, s);
  2727. //jsonObject = Firebug.context.eval(jsonString);
  2728. jsonObject = Firebug.context.evaluate(jsonString, null, null, function(){return null;});
  2729. }
  2730. catch(e)
  2731. {
  2732. /***
  2733. if (e.message.indexOf("is not defined"))
  2734. {
  2735. var parts = e.message.split(" ");
  2736. s[parts[0]] = function(str){ return str; };
  2737. try {
  2738. jsonObject = Components.utils.evalInSandbox(jsonString, s);
  2739. } catch(ex) {
  2740. if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER)
  2741. FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e);
  2742. return null;
  2743. }
  2744. }
  2745. else
  2746. {/**/
  2747. if (FBTrace.DBG_ERRORS || FBTrace.DBG_JSONVIEWER)
  2748. FBTrace.sysout("jsonviewer.parseJSON EXCEPTION", e);
  2749. return null;
  2750. ///}
  2751. }
  2752. return jsonObject;
  2753. };
  2754. // ************************************************************************************************
  2755. this.objectToString = function(object)
  2756. {
  2757. try
  2758. {
  2759. return object+"";
  2760. }
  2761. catch (exc)
  2762. {
  2763. return null;
  2764. }
  2765. };
  2766. // ************************************************************************************************
  2767. // Input Caret Position
  2768. this.setSelectionRange = function(input, start, length)
  2769. {
  2770. if (input.createTextRange)
  2771. {
  2772. var range = input.createTextRange();
  2773. range.moveStart("character", start);
  2774. range.moveEnd("character", length - input.value.length);
  2775. range.select();
  2776. }
  2777. else if (input.setSelectionRange)
  2778. {
  2779. input.setSelectionRange(start, length);
  2780. input.focus();
  2781. }
  2782. };
  2783. // ************************************************************************************************
  2784. // Input Selection Start / Caret Position
  2785. this.getInputSelectionStart = function(input)
  2786. {
  2787. if (document.selection)
  2788. {
  2789. var range = input.ownerDocument.selection.createRange();
  2790. var text = range.text;
  2791. //console.log("range", range.text);
  2792. // if there is a selection, find the start position
  2793. if (text)
  2794. {
  2795. return input.value.indexOf(text);
  2796. }
  2797. // if there is no selection, find the caret position
  2798. else
  2799. {
  2800. range.moveStart("character", -input.value.length);
  2801. return range.text.length;
  2802. }
  2803. }
  2804. else if (typeof input.selectionStart != "undefined")
  2805. return input.selectionStart;
  2806. return 0;
  2807. };
  2808. // ************************************************************************************************
  2809. // Opera Tab Fix
  2810. function onOperaTabBlur(e)
  2811. {
  2812. if (this.lastKey == 9)
  2813. this.focus();
  2814. };
  2815. function onOperaTabKeyDown(e)
  2816. {
  2817. this.lastKey = e.keyCode;
  2818. };
  2819. function onOperaTabFocus(e)
  2820. {
  2821. this.lastKey = null;
  2822. };
  2823. this.fixOperaTabKey = function(el)
  2824. {
  2825. el.onfocus = onOperaTabFocus;
  2826. el.onblur = onOperaTabBlur;
  2827. el.onkeydown = onOperaTabKeyDown;
  2828. };
  2829. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2830. this.Property = function(object, name)
  2831. {
  2832. this.object = object;
  2833. this.name = name;
  2834. this.getObject = function()
  2835. {
  2836. return object[name];
  2837. };
  2838. };
  2839. this.ErrorCopy = function(message)
  2840. {
  2841. this.message = message;
  2842. };
  2843. function EventCopy(event)
  2844. {
  2845. // Because event objects are destroyed arbitrarily by Gecko, we must make a copy of them to
  2846. // represent them long term in the inspector.
  2847. for (var name in event)
  2848. {
  2849. try {
  2850. this[name] = event[name];
  2851. } catch (exc) { }
  2852. }
  2853. }
  2854. this.EventCopy = EventCopy;
  2855. // ************************************************************************************************
  2856. // Type Checking
  2857. var toString = Object.prototype.toString;
  2858. var reFunction = /^\s*function(\s+[\w_$][\w\d_$]*)?\s*\(/;
  2859. this.isArray = function(object) {
  2860. return toString.call(object) === '[object Array]';
  2861. };
  2862. this.isFunction = function(object) {
  2863. if (!object) return false;
  2864. return toString.call(object) === "[object Function]" ||
  2865. this.isIE && typeof object != "string" && reFunction.test(""+object);
  2866. };
  2867. // ************************************************************************************************
  2868. // Instance Checking
  2869. this.instanceOf = function(object, className)
  2870. {
  2871. if (!object || typeof object != "object")
  2872. return false;
  2873. // Try to use the native instanceof operator. We can only use it when we know
  2874. // exactly the window where the object is located at
  2875. if (object.ownerDocument)
  2876. {
  2877. // find the correct window of the object
  2878. var win = object.ownerDocument.defaultView || object.ownerDocument.parentWindow;
  2879. // if the class is accessible in the window, uses the native instanceof operator
  2880. // if the instanceof evaluates to "true" we can assume it is a instance, but if it
  2881. // evaluates to "false" we must continue with the duck type detection below because
  2882. // the native object may be extended, thus breaking the instanceof result
  2883. // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended
  2884. if (className in win && object instanceof win[className])
  2885. return true;
  2886. }
  2887. // If the object doesn't have the ownerDocument property, we'll try to look at
  2888. // the current context's window
  2889. else
  2890. {
  2891. // TODO: xxxpedro context
  2892. // Since we're not using yet a Firebug.context, we'll just use the top window
  2893. // (browser) as a reference
  2894. var win = Firebug.browser.window;
  2895. if (className in win)
  2896. return object instanceof win[className];
  2897. }
  2898. // get the duck type model from the cache
  2899. var cache = instanceCheckMap[className];
  2900. if (!cache)
  2901. return false;
  2902. // starts the hacky duck type detection
  2903. for(var n in cache)
  2904. {
  2905. var obj = cache[n];
  2906. var type = typeof obj;
  2907. obj = type == "object" ? obj : [obj];
  2908. for(var name in obj)
  2909. {
  2910. // avoid problems with extended native objects
  2911. // See Issue 3524: Firebug Lite Style Panel doesn't work if the native Element is extended
  2912. if (!obj.hasOwnProperty(name))
  2913. continue;
  2914. var value = obj[name];
  2915. if( n == "property" && !(value in object) ||
  2916. n == "method" && !this.isFunction(object[value]) ||
  2917. n == "value" && (""+object[name]).toLowerCase() != (""+value).toLowerCase() )
  2918. return false;
  2919. }
  2920. }
  2921. return true;
  2922. };
  2923. var instanceCheckMap =
  2924. {
  2925. // DuckTypeCheck:
  2926. // {
  2927. // property: ["window", "document"],
  2928. // method: "setTimeout",
  2929. // value: {nodeType: 1}
  2930. // },
  2931. Window:
  2932. {
  2933. property: ["window", "document"],
  2934. method: "setTimeout"
  2935. },
  2936. Document:
  2937. {
  2938. property: ["body", "cookie"],
  2939. method: "getElementById"
  2940. },
  2941. Node:
  2942. {
  2943. property: "ownerDocument",
  2944. method: "appendChild"
  2945. },
  2946. Element:
  2947. {
  2948. property: "tagName",
  2949. value: {nodeType: 1}
  2950. },
  2951. Location:
  2952. {
  2953. property: ["hostname", "protocol"],
  2954. method: "assign"
  2955. },
  2956. HTMLImageElement:
  2957. {
  2958. property: "useMap",
  2959. value:
  2960. {
  2961. nodeType: 1,
  2962. tagName: "img"
  2963. }
  2964. },
  2965. HTMLAnchorElement:
  2966. {
  2967. property: "hreflang",
  2968. value:
  2969. {
  2970. nodeType: 1,
  2971. tagName: "a"
  2972. }
  2973. },
  2974. HTMLInputElement:
  2975. {
  2976. property: "form",
  2977. value:
  2978. {
  2979. nodeType: 1,
  2980. tagName: "input"
  2981. }
  2982. },
  2983. HTMLButtonElement:
  2984. {
  2985. // ?
  2986. },
  2987. HTMLFormElement:
  2988. {
  2989. method: "submit",
  2990. value:
  2991. {
  2992. nodeType: 1,
  2993. tagName: "form"
  2994. }
  2995. },
  2996. HTMLBodyElement:
  2997. {
  2998. },
  2999. HTMLHtmlElement:
  3000. {
  3001. },
  3002. CSSStyleRule:
  3003. {
  3004. property: ["selectorText", "style"]
  3005. }
  3006. };
  3007. // ************************************************************************************************
  3008. // DOM Constants
  3009. /*
  3010. Problems:
  3011. - IE does not have window.Node, window.Element, etc
  3012. - for (var name in Node.prototype) return nothing on FF
  3013. */
  3014. var domMemberMap2 = {};
  3015. var domMemberMap2Sandbox = null;
  3016. var getDomMemberMap2 = function(name)
  3017. {
  3018. if (!domMemberMap2Sandbox)
  3019. {
  3020. var doc = Firebug.chrome.document;
  3021. var frame = doc.createElement("iframe");
  3022. frame.id = "FirebugSandbox";
  3023. frame.style.display = "none";
  3024. frame.src = "about:blank";
  3025. doc.body.appendChild(frame);
  3026. domMemberMap2Sandbox = frame.window || frame.contentWindow;
  3027. }
  3028. var props = [];
  3029. //var object = domMemberMap2Sandbox[name];
  3030. //object = object.prototype || object;
  3031. var object = null;
  3032. if (name == "Window")
  3033. object = domMemberMap2Sandbox.window;
  3034. else if (name == "Document")
  3035. object = domMemberMap2Sandbox.document;
  3036. else if (name == "HTMLScriptElement")
  3037. object = domMemberMap2Sandbox.document.createElement("script");
  3038. else if (name == "HTMLAnchorElement")
  3039. object = domMemberMap2Sandbox.document.createElement("a");
  3040. else if (name.indexOf("Element") != -1)
  3041. {
  3042. object = domMemberMap2Sandbox.document.createElement("div");
  3043. }
  3044. if (object)
  3045. {
  3046. //object = object.prototype || object;
  3047. //props = 'addEventListener,document,location,navigator,window'.split(',');
  3048. for (var n in object)
  3049. props.push(n);
  3050. }
  3051. /**/
  3052. return props;
  3053. return extendArray(props, domMemberMap[name]);
  3054. };
  3055. // xxxpedro experimental get DOM members
  3056. this.getDOMMembers = function(object)
  3057. {
  3058. if (!domMemberCache)
  3059. {
  3060. FBL.domMemberCache = domMemberCache = {};
  3061. for (var name in domMemberMap)
  3062. {
  3063. var builtins = getDomMemberMap2(name);
  3064. var cache = domMemberCache[name] = {};
  3065. /*
  3066. if (name.indexOf("Element") != -1)
  3067. {
  3068. this.append(cache, this.getDOMMembers("Node"));
  3069. this.append(cache, this.getDOMMembers("Element"));
  3070. }
  3071. /**/
  3072. for (var i = 0; i < builtins.length; ++i)
  3073. cache[builtins[i]] = i;
  3074. }
  3075. }
  3076. try
  3077. {
  3078. if (this.instanceOf(object, "Window"))
  3079. { return domMemberCache.Window; }
  3080. else if (this.instanceOf(object, "Document") || this.instanceOf(object, "XMLDocument"))
  3081. { return domMemberCache.Document; }
  3082. else if (this.instanceOf(object, "Location"))
  3083. { return domMemberCache.Location; }
  3084. else if (this.instanceOf(object, "HTMLImageElement"))
  3085. { return domMemberCache.HTMLImageElement; }
  3086. else if (this.instanceOf(object, "HTMLAnchorElement"))
  3087. { return domMemberCache.HTMLAnchorElement; }
  3088. else if (this.instanceOf(object, "HTMLInputElement"))
  3089. { return domMemberCache.HTMLInputElement; }
  3090. else if (this.instanceOf(object, "HTMLButtonElement"))
  3091. { return domMemberCache.HTMLButtonElement; }
  3092. else if (this.instanceOf(object, "HTMLFormElement"))
  3093. { return domMemberCache.HTMLFormElement; }
  3094. else if (this.instanceOf(object, "HTMLBodyElement"))
  3095. { return domMemberCache.HTMLBodyElement; }
  3096. else if (this.instanceOf(object, "HTMLHtmlElement"))
  3097. { return domMemberCache.HTMLHtmlElement; }
  3098. else if (this.instanceOf(object, "HTMLScriptElement"))
  3099. { return domMemberCache.HTMLScriptElement; }
  3100. else if (this.instanceOf(object, "HTMLTableElement"))
  3101. { return domMemberCache.HTMLTableElement; }
  3102. else if (this.instanceOf(object, "HTMLTableRowElement"))
  3103. { return domMemberCache.HTMLTableRowElement; }
  3104. else if (this.instanceOf(object, "HTMLTableCellElement"))
  3105. { return domMemberCache.HTMLTableCellElement; }
  3106. else if (this.instanceOf(object, "HTMLIFrameElement"))
  3107. { return domMemberCache.HTMLIFrameElement; }
  3108. else if (this.instanceOf(object, "SVGSVGElement"))
  3109. { return domMemberCache.SVGSVGElement; }
  3110. else if (this.instanceOf(object, "SVGElement"))
  3111. { return domMemberCache.SVGElement; }
  3112. else if (this.instanceOf(object, "Element"))
  3113. { return domMemberCache.Element; }
  3114. else if (this.instanceOf(object, "Text") || this.instanceOf(object, "CDATASection"))
  3115. { return domMemberCache.Text; }
  3116. else if (this.instanceOf(object, "Attr"))
  3117. { return domMemberCache.Attr; }
  3118. else if (this.instanceOf(object, "Node"))
  3119. { return domMemberCache.Node; }
  3120. else if (this.instanceOf(object, "Event") || this.instanceOf(object, "EventCopy"))
  3121. { return domMemberCache.Event; }
  3122. else
  3123. return {};
  3124. }
  3125. catch(E)
  3126. {
  3127. if (FBTrace.DBG_ERRORS)
  3128. FBTrace.sysout("lib.getDOMMembers FAILED ", E);
  3129. return {};
  3130. }
  3131. };
  3132. /*
  3133. this.getDOMMembers = function(object)
  3134. {
  3135. if (!domMemberCache)
  3136. {
  3137. domMemberCache = {};
  3138. for (var name in domMemberMap)
  3139. {
  3140. var builtins = domMemberMap[name];
  3141. var cache = domMemberCache[name] = {};
  3142. for (var i = 0; i < builtins.length; ++i)
  3143. cache[builtins[i]] = i;
  3144. }
  3145. }
  3146. try
  3147. {
  3148. if (this.instanceOf(object, "Window"))
  3149. { return domMemberCache.Window; }
  3150. else if (object instanceof Document || object instanceof XMLDocument)
  3151. { return domMemberCache.Document; }
  3152. else if (object instanceof Location)
  3153. { return domMemberCache.Location; }
  3154. else if (object instanceof HTMLImageElement)
  3155. { return domMemberCache.HTMLImageElement; }
  3156. else if (object instanceof HTMLAnchorElement)
  3157. { return domMemberCache.HTMLAnchorElement; }
  3158. else if (object instanceof HTMLInputElement)
  3159. { return domMemberCache.HTMLInputElement; }
  3160. else if (object instanceof HTMLButtonElement)
  3161. { return domMemberCache.HTMLButtonElement; }
  3162. else if (object instanceof HTMLFormElement)
  3163. { return domMemberCache.HTMLFormElement; }
  3164. else if (object instanceof HTMLBodyElement)
  3165. { return domMemberCache.HTMLBodyElement; }
  3166. else if (object instanceof HTMLHtmlElement)
  3167. { return domMemberCache.HTMLHtmlElement; }
  3168. else if (object instanceof HTMLScriptElement)
  3169. { return domMemberCache.HTMLScriptElement; }
  3170. else if (object instanceof HTMLTableElement)
  3171. { return domMemberCache.HTMLTableElement; }
  3172. else if (object instanceof HTMLTableRowElement)
  3173. { return domMemberCache.HTMLTableRowElement; }
  3174. else if (object instanceof HTMLTableCellElement)
  3175. { return domMemberCache.HTMLTableCellElement; }
  3176. else if (object instanceof HTMLIFrameElement)
  3177. { return domMemberCache.HTMLIFrameElement; }
  3178. else if (object instanceof SVGSVGElement)
  3179. { return domMemberCache.SVGSVGElement; }
  3180. else if (object instanceof SVGElement)
  3181. { return domMemberCache.SVGElement; }
  3182. else if (object instanceof Element)
  3183. { return domMemberCache.Element; }
  3184. else if (object instanceof Text || object instanceof CDATASection)
  3185. { return domMemberCache.Text; }
  3186. else if (object instanceof Attr)
  3187. { return domMemberCache.Attr; }
  3188. else if (object instanceof Node)
  3189. { return domMemberCache.Node; }
  3190. else if (object instanceof Event || object instanceof EventCopy)
  3191. { return domMemberCache.Event; }
  3192. else
  3193. return {};
  3194. }
  3195. catch(E)
  3196. {
  3197. return {};
  3198. }
  3199. };
  3200. /**/
  3201. this.isDOMMember = function(object, propName)
  3202. {
  3203. var members = this.getDOMMembers(object);
  3204. return members && propName in members;
  3205. };
  3206. var domMemberCache = null;
  3207. var domMemberMap = {};
  3208. domMemberMap.Window =
  3209. [
  3210. "document",
  3211. "frameElement",
  3212. "innerWidth",
  3213. "innerHeight",
  3214. "outerWidth",
  3215. "outerHeight",
  3216. "screenX",
  3217. "screenY",
  3218. "pageXOffset",
  3219. "pageYOffset",
  3220. "scrollX",
  3221. "scrollY",
  3222. "scrollMaxX",
  3223. "scrollMaxY",
  3224. "status",
  3225. "defaultStatus",
  3226. "parent",
  3227. "opener",
  3228. "top",
  3229. "window",
  3230. "content",
  3231. "self",
  3232. "location",
  3233. "history",
  3234. "frames",
  3235. "navigator",
  3236. "screen",
  3237. "menubar",
  3238. "toolbar",
  3239. "locationbar",
  3240. "personalbar",
  3241. "statusbar",
  3242. "directories",
  3243. "scrollbars",
  3244. "fullScreen",
  3245. "netscape",
  3246. "java",
  3247. "console",
  3248. "Components",
  3249. "controllers",
  3250. "closed",
  3251. "crypto",
  3252. "pkcs11",
  3253. "name",
  3254. "property",
  3255. "length",
  3256. "sessionStorage",
  3257. "globalStorage",
  3258. "setTimeout",
  3259. "setInterval",
  3260. "clearTimeout",
  3261. "clearInterval",
  3262. "addEventListener",
  3263. "removeEventListener",
  3264. "dispatchEvent",
  3265. "getComputedStyle",
  3266. "captureEvents",
  3267. "releaseEvents",
  3268. "routeEvent",
  3269. "enableExternalCapture",
  3270. "disableExternalCapture",
  3271. "moveTo",
  3272. "moveBy",
  3273. "resizeTo",
  3274. "resizeBy",
  3275. "scroll",
  3276. "scrollTo",
  3277. "scrollBy",
  3278. "scrollByLines",
  3279. "scrollByPages",
  3280. "sizeToContent",
  3281. "setResizable",
  3282. "getSelection",
  3283. "open",
  3284. "openDialog",
  3285. "close",
  3286. "alert",
  3287. "confirm",
  3288. "prompt",
  3289. "dump",
  3290. "focus",
  3291. "blur",
  3292. "find",
  3293. "back",
  3294. "forward",
  3295. "home",
  3296. "stop",
  3297. "print",
  3298. "atob",
  3299. "btoa",
  3300. "updateCommands",
  3301. "XPCNativeWrapper",
  3302. "GeckoActiveXObject",
  3303. "applicationCache" // FF3
  3304. ];
  3305. domMemberMap.Location =
  3306. [
  3307. "href",
  3308. "protocol",
  3309. "host",
  3310. "hostname",
  3311. "port",
  3312. "pathname",
  3313. "search",
  3314. "hash",
  3315. "assign",
  3316. "reload",
  3317. "replace"
  3318. ];
  3319. domMemberMap.Node =
  3320. [
  3321. "id",
  3322. "className",
  3323. "nodeType",
  3324. "tagName",
  3325. "nodeName",
  3326. "localName",
  3327. "prefix",
  3328. "namespaceURI",
  3329. "nodeValue",
  3330. "ownerDocument",
  3331. "parentNode",
  3332. "offsetParent",
  3333. "nextSibling",
  3334. "previousSibling",
  3335. "firstChild",
  3336. "lastChild",
  3337. "childNodes",
  3338. "attributes",
  3339. "dir",
  3340. "baseURI",
  3341. "textContent",
  3342. "innerHTML",
  3343. "addEventListener",
  3344. "removeEventListener",
  3345. "dispatchEvent",
  3346. "cloneNode",
  3347. "appendChild",
  3348. "insertBefore",
  3349. "replaceChild",
  3350. "removeChild",
  3351. "compareDocumentPosition",
  3352. "hasAttributes",
  3353. "hasChildNodes",
  3354. "lookupNamespaceURI",
  3355. "lookupPrefix",
  3356. "normalize",
  3357. "isDefaultNamespace",
  3358. "isEqualNode",
  3359. "isSameNode",
  3360. "isSupported",
  3361. "getFeature",
  3362. "getUserData",
  3363. "setUserData"
  3364. ];
  3365. domMemberMap.Document = extendArray(domMemberMap.Node,
  3366. [
  3367. "documentElement",
  3368. "body",
  3369. "title",
  3370. "location",
  3371. "referrer",
  3372. "cookie",
  3373. "contentType",
  3374. "lastModified",
  3375. "characterSet",
  3376. "inputEncoding",
  3377. "xmlEncoding",
  3378. "xmlStandalone",
  3379. "xmlVersion",
  3380. "strictErrorChecking",
  3381. "documentURI",
  3382. "URL",
  3383. "defaultView",
  3384. "doctype",
  3385. "implementation",
  3386. "styleSheets",
  3387. "images",
  3388. "links",
  3389. "forms",
  3390. "anchors",
  3391. "embeds",
  3392. "plugins",
  3393. "applets",
  3394. "width",
  3395. "height",
  3396. "designMode",
  3397. "compatMode",
  3398. "async",
  3399. "preferredStylesheetSet",
  3400. "alinkColor",
  3401. "linkColor",
  3402. "vlinkColor",
  3403. "bgColor",
  3404. "fgColor",
  3405. "domain",
  3406. "addEventListener",
  3407. "removeEventListener",
  3408. "dispatchEvent",
  3409. "captureEvents",
  3410. "releaseEvents",
  3411. "routeEvent",
  3412. "clear",
  3413. "open",
  3414. "close",
  3415. "execCommand",
  3416. "execCommandShowHelp",
  3417. "getElementsByName",
  3418. "getSelection",
  3419. "queryCommandEnabled",
  3420. "queryCommandIndeterm",
  3421. "queryCommandState",
  3422. "queryCommandSupported",
  3423. "queryCommandText",
  3424. "queryCommandValue",
  3425. "write",
  3426. "writeln",
  3427. "adoptNode",
  3428. "appendChild",
  3429. "removeChild",
  3430. "renameNode",
  3431. "cloneNode",
  3432. "compareDocumentPosition",
  3433. "createAttribute",
  3434. "createAttributeNS",
  3435. "createCDATASection",
  3436. "createComment",
  3437. "createDocumentFragment",
  3438. "createElement",
  3439. "createElementNS",
  3440. "createEntityReference",
  3441. "createEvent",
  3442. "createExpression",
  3443. "createNSResolver",
  3444. "createNodeIterator",
  3445. "createProcessingInstruction",
  3446. "createRange",
  3447. "createTextNode",
  3448. "createTreeWalker",
  3449. "domConfig",
  3450. "evaluate",
  3451. "evaluateFIXptr",
  3452. "evaluateXPointer",
  3453. "getAnonymousElementByAttribute",
  3454. "getAnonymousNodes",
  3455. "addBinding",
  3456. "removeBinding",
  3457. "getBindingParent",
  3458. "getBoxObjectFor",
  3459. "setBoxObjectFor",
  3460. "getElementById",
  3461. "getElementsByTagName",
  3462. "getElementsByTagNameNS",
  3463. "hasAttributes",
  3464. "hasChildNodes",
  3465. "importNode",
  3466. "insertBefore",
  3467. "isDefaultNamespace",
  3468. "isEqualNode",
  3469. "isSameNode",
  3470. "isSupported",
  3471. "load",
  3472. "loadBindingDocument",
  3473. "lookupNamespaceURI",
  3474. "lookupPrefix",
  3475. "normalize",
  3476. "normalizeDocument",
  3477. "getFeature",
  3478. "getUserData",
  3479. "setUserData"
  3480. ]);
  3481. domMemberMap.Element = extendArray(domMemberMap.Node,
  3482. [
  3483. "clientWidth",
  3484. "clientHeight",
  3485. "offsetLeft",
  3486. "offsetTop",
  3487. "offsetWidth",
  3488. "offsetHeight",
  3489. "scrollLeft",
  3490. "scrollTop",
  3491. "scrollWidth",
  3492. "scrollHeight",
  3493. "style",
  3494. "tabIndex",
  3495. "title",
  3496. "lang",
  3497. "align",
  3498. "spellcheck",
  3499. "addEventListener",
  3500. "removeEventListener",
  3501. "dispatchEvent",
  3502. "focus",
  3503. "blur",
  3504. "cloneNode",
  3505. "appendChild",
  3506. "insertBefore",
  3507. "replaceChild",
  3508. "removeChild",
  3509. "compareDocumentPosition",
  3510. "getElementsByTagName",
  3511. "getElementsByTagNameNS",
  3512. "getAttribute",
  3513. "getAttributeNS",
  3514. "getAttributeNode",
  3515. "getAttributeNodeNS",
  3516. "setAttribute",
  3517. "setAttributeNS",
  3518. "setAttributeNode",
  3519. "setAttributeNodeNS",
  3520. "removeAttribute",
  3521. "removeAttributeNS",
  3522. "removeAttributeNode",
  3523. "hasAttribute",
  3524. "hasAttributeNS",
  3525. "hasAttributes",
  3526. "hasChildNodes",
  3527. "lookupNamespaceURI",
  3528. "lookupPrefix",
  3529. "normalize",
  3530. "isDefaultNamespace",
  3531. "isEqualNode",
  3532. "isSameNode",
  3533. "isSupported",
  3534. "getFeature",
  3535. "getUserData",
  3536. "setUserData"
  3537. ]);
  3538. domMemberMap.SVGElement = extendArray(domMemberMap.Element,
  3539. [
  3540. "x",
  3541. "y",
  3542. "width",
  3543. "height",
  3544. "rx",
  3545. "ry",
  3546. "transform",
  3547. "href",
  3548. "ownerSVGElement",
  3549. "viewportElement",
  3550. "farthestViewportElement",
  3551. "nearestViewportElement",
  3552. "getBBox",
  3553. "getCTM",
  3554. "getScreenCTM",
  3555. "getTransformToElement",
  3556. "getPresentationAttribute",
  3557. "preserveAspectRatio"
  3558. ]);
  3559. domMemberMap.SVGSVGElement = extendArray(domMemberMap.Element,
  3560. [
  3561. "x",
  3562. "y",
  3563. "width",
  3564. "height",
  3565. "rx",
  3566. "ry",
  3567. "transform",
  3568. "viewBox",
  3569. "viewport",
  3570. "currentView",
  3571. "useCurrentView",
  3572. "pixelUnitToMillimeterX",
  3573. "pixelUnitToMillimeterY",
  3574. "screenPixelToMillimeterX",
  3575. "screenPixelToMillimeterY",
  3576. "currentScale",
  3577. "currentTranslate",
  3578. "zoomAndPan",
  3579. "ownerSVGElement",
  3580. "viewportElement",
  3581. "farthestViewportElement",
  3582. "nearestViewportElement",
  3583. "contentScriptType",
  3584. "contentStyleType",
  3585. "getBBox",
  3586. "getCTM",
  3587. "getScreenCTM",
  3588. "getTransformToElement",
  3589. "getEnclosureList",
  3590. "getIntersectionList",
  3591. "getViewboxToViewportTransform",
  3592. "getPresentationAttribute",
  3593. "getElementById",
  3594. "checkEnclosure",
  3595. "checkIntersection",
  3596. "createSVGAngle",
  3597. "createSVGLength",
  3598. "createSVGMatrix",
  3599. "createSVGNumber",
  3600. "createSVGPoint",
  3601. "createSVGRect",
  3602. "createSVGString",
  3603. "createSVGTransform",
  3604. "createSVGTransformFromMatrix",
  3605. "deSelectAll",
  3606. "preserveAspectRatio",
  3607. "forceRedraw",
  3608. "suspendRedraw",
  3609. "unsuspendRedraw",
  3610. "unsuspendRedrawAll",
  3611. "getCurrentTime",
  3612. "setCurrentTime",
  3613. "animationsPaused",
  3614. "pauseAnimations",
  3615. "unpauseAnimations"
  3616. ]);
  3617. domMemberMap.HTMLImageElement = extendArray(domMemberMap.Element,
  3618. [
  3619. "src",
  3620. "naturalWidth",
  3621. "naturalHeight",
  3622. "width",
  3623. "height",
  3624. "x",
  3625. "y",
  3626. "name",
  3627. "alt",
  3628. "longDesc",
  3629. "lowsrc",
  3630. "border",
  3631. "complete",
  3632. "hspace",
  3633. "vspace",
  3634. "isMap",
  3635. "useMap"
  3636. ]);
  3637. domMemberMap.HTMLAnchorElement = extendArray(domMemberMap.Element,
  3638. [
  3639. "name",
  3640. "target",
  3641. "accessKey",
  3642. "href",
  3643. "protocol",
  3644. "host",
  3645. "hostname",
  3646. "port",
  3647. "pathname",
  3648. "search",
  3649. "hash",
  3650. "hreflang",
  3651. "coords",
  3652. "shape",
  3653. "text",
  3654. "type",
  3655. "rel",
  3656. "rev",
  3657. "charset"
  3658. ]);
  3659. domMemberMap.HTMLIFrameElement = extendArray(domMemberMap.Element,
  3660. [
  3661. "contentDocument",
  3662. "contentWindow",
  3663. "frameBorder",
  3664. "height",
  3665. "longDesc",
  3666. "marginHeight",
  3667. "marginWidth",
  3668. "name",
  3669. "scrolling",
  3670. "src",
  3671. "width"
  3672. ]);
  3673. domMemberMap.HTMLTableElement = extendArray(domMemberMap.Element,
  3674. [
  3675. "bgColor",
  3676. "border",
  3677. "caption",
  3678. "cellPadding",
  3679. "cellSpacing",
  3680. "frame",
  3681. "rows",
  3682. "rules",
  3683. "summary",
  3684. "tBodies",
  3685. "tFoot",
  3686. "tHead",
  3687. "width",
  3688. "createCaption",
  3689. "createTFoot",
  3690. "createTHead",
  3691. "deleteCaption",
  3692. "deleteRow",
  3693. "deleteTFoot",
  3694. "deleteTHead",
  3695. "insertRow"
  3696. ]);
  3697. domMemberMap.HTMLTableRowElement = extendArray(domMemberMap.Element,
  3698. [
  3699. "bgColor",
  3700. "cells",
  3701. "ch",
  3702. "chOff",
  3703. "rowIndex",
  3704. "sectionRowIndex",
  3705. "vAlign",
  3706. "deleteCell",
  3707. "insertCell"
  3708. ]);
  3709. domMemberMap.HTMLTableCellElement = extendArray(domMemberMap.Element,
  3710. [
  3711. "abbr",
  3712. "axis",
  3713. "bgColor",
  3714. "cellIndex",
  3715. "ch",
  3716. "chOff",
  3717. "colSpan",
  3718. "headers",
  3719. "height",
  3720. "noWrap",
  3721. "rowSpan",
  3722. "scope",
  3723. "vAlign",
  3724. "width"
  3725. ]);
  3726. domMemberMap.HTMLScriptElement = extendArray(domMemberMap.Element,
  3727. [
  3728. "src"
  3729. ]);
  3730. domMemberMap.HTMLButtonElement = extendArray(domMemberMap.Element,
  3731. [
  3732. "accessKey",
  3733. "disabled",
  3734. "form",
  3735. "name",
  3736. "type",
  3737. "value",
  3738. "click"
  3739. ]);
  3740. domMemberMap.HTMLInputElement = extendArray(domMemberMap.Element,
  3741. [
  3742. "type",
  3743. "value",
  3744. "checked",
  3745. "accept",
  3746. "accessKey",
  3747. "alt",
  3748. "controllers",
  3749. "defaultChecked",
  3750. "defaultValue",
  3751. "disabled",
  3752. "form",
  3753. "maxLength",
  3754. "name",
  3755. "readOnly",
  3756. "selectionEnd",
  3757. "selectionStart",
  3758. "size",
  3759. "src",
  3760. "textLength",
  3761. "useMap",
  3762. "click",
  3763. "select",
  3764. "setSelectionRange"
  3765. ]);
  3766. domMemberMap.HTMLFormElement = extendArray(domMemberMap.Element,
  3767. [
  3768. "acceptCharset",
  3769. "action",
  3770. "author",
  3771. "elements",
  3772. "encoding",
  3773. "enctype",
  3774. "entry_id",
  3775. "length",
  3776. "method",
  3777. "name",
  3778. "post",
  3779. "target",
  3780. "text",
  3781. "url",
  3782. "reset",
  3783. "submit"
  3784. ]);
  3785. domMemberMap.HTMLBodyElement = extendArray(domMemberMap.Element,
  3786. [
  3787. "aLink",
  3788. "background",
  3789. "bgColor",
  3790. "link",
  3791. "text",
  3792. "vLink"
  3793. ]);
  3794. domMemberMap.HTMLHtmlElement = extendArray(domMemberMap.Element,
  3795. [
  3796. "version"
  3797. ]);
  3798. domMemberMap.Text = extendArray(domMemberMap.Node,
  3799. [
  3800. "data",
  3801. "length",
  3802. "appendData",
  3803. "deleteData",
  3804. "insertData",
  3805. "replaceData",
  3806. "splitText",
  3807. "substringData"
  3808. ]);
  3809. domMemberMap.Attr = extendArray(domMemberMap.Node,
  3810. [
  3811. "name",
  3812. "value",
  3813. "specified",
  3814. "ownerElement"
  3815. ]);
  3816. domMemberMap.Event =
  3817. [
  3818. "type",
  3819. "target",
  3820. "currentTarget",
  3821. "originalTarget",
  3822. "explicitOriginalTarget",
  3823. "relatedTarget",
  3824. "rangeParent",
  3825. "rangeOffset",
  3826. "view",
  3827. "keyCode",
  3828. "charCode",
  3829. "screenX",
  3830. "screenY",
  3831. "clientX",
  3832. "clientY",
  3833. "layerX",
  3834. "layerY",
  3835. "pageX",
  3836. "pageY",
  3837. "detail",
  3838. "button",
  3839. "which",
  3840. "ctrlKey",
  3841. "shiftKey",
  3842. "altKey",
  3843. "metaKey",
  3844. "eventPhase",
  3845. "timeStamp",
  3846. "bubbles",
  3847. "cancelable",
  3848. "cancelBubble",
  3849. "isTrusted",
  3850. "isChar",
  3851. "getPreventDefault",
  3852. "initEvent",
  3853. "initMouseEvent",
  3854. "initKeyEvent",
  3855. "initUIEvent",
  3856. "preventBubble",
  3857. "preventCapture",
  3858. "preventDefault",
  3859. "stopPropagation"
  3860. ];
  3861. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  3862. this.domConstantMap =
  3863. {
  3864. "ELEMENT_NODE": 1,
  3865. "ATTRIBUTE_NODE": 1,
  3866. "TEXT_NODE": 1,
  3867. "CDATA_SECTION_NODE": 1,
  3868. "ENTITY_REFERENCE_NODE": 1,
  3869. "ENTITY_NODE": 1,
  3870. "PROCESSING_INSTRUCTION_NODE": 1,
  3871. "COMMENT_NODE": 1,
  3872. "DOCUMENT_NODE": 1,
  3873. "DOCUMENT_TYPE_NODE": 1,
  3874. "DOCUMENT_FRAGMENT_NODE": 1,
  3875. "NOTATION_NODE": 1,
  3876. "DOCUMENT_POSITION_DISCONNECTED": 1,
  3877. "DOCUMENT_POSITION_PRECEDING": 1,
  3878. "DOCUMENT_POSITION_FOLLOWING": 1,
  3879. "DOCUMENT_POSITION_CONTAINS": 1,
  3880. "DOCUMENT_POSITION_CONTAINED_BY": 1,
  3881. "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC": 1,
  3882. "UNKNOWN_RULE": 1,
  3883. "STYLE_RULE": 1,
  3884. "CHARSET_RULE": 1,
  3885. "IMPORT_RULE": 1,
  3886. "MEDIA_RULE": 1,
  3887. "FONT_FACE_RULE": 1,
  3888. "PAGE_RULE": 1,
  3889. "CAPTURING_PHASE": 1,
  3890. "AT_TARGET": 1,
  3891. "BUBBLING_PHASE": 1,
  3892. "SCROLL_PAGE_UP": 1,
  3893. "SCROLL_PAGE_DOWN": 1,
  3894. "MOUSEUP": 1,
  3895. "MOUSEDOWN": 1,
  3896. "MOUSEOVER": 1,
  3897. "MOUSEOUT": 1,
  3898. "MOUSEMOVE": 1,
  3899. "MOUSEDRAG": 1,
  3900. "CLICK": 1,
  3901. "DBLCLICK": 1,
  3902. "KEYDOWN": 1,
  3903. "KEYUP": 1,
  3904. "KEYPRESS": 1,
  3905. "DRAGDROP": 1,
  3906. "FOCUS": 1,
  3907. "BLUR": 1,
  3908. "SELECT": 1,
  3909. "CHANGE": 1,
  3910. "RESET": 1,
  3911. "SUBMIT": 1,
  3912. "SCROLL": 1,
  3913. "LOAD": 1,
  3914. "UNLOAD": 1,
  3915. "XFER_DONE": 1,
  3916. "ABORT": 1,
  3917. "ERROR": 1,
  3918. "LOCATE": 1,
  3919. "MOVE": 1,
  3920. "RESIZE": 1,
  3921. "FORWARD": 1,
  3922. "HELP": 1,
  3923. "BACK": 1,
  3924. "TEXT": 1,
  3925. "ALT_MASK": 1,
  3926. "CONTROL_MASK": 1,
  3927. "SHIFT_MASK": 1,
  3928. "META_MASK": 1,
  3929. "DOM_VK_TAB": 1,
  3930. "DOM_VK_PAGE_UP": 1,
  3931. "DOM_VK_PAGE_DOWN": 1,
  3932. "DOM_VK_UP": 1,
  3933. "DOM_VK_DOWN": 1,
  3934. "DOM_VK_LEFT": 1,
  3935. "DOM_VK_RIGHT": 1,
  3936. "DOM_VK_CANCEL": 1,
  3937. "DOM_VK_HELP": 1,
  3938. "DOM_VK_BACK_SPACE": 1,
  3939. "DOM_VK_CLEAR": 1,
  3940. "DOM_VK_RETURN": 1,
  3941. "DOM_VK_ENTER": 1,
  3942. "DOM_VK_SHIFT": 1,
  3943. "DOM_VK_CONTROL": 1,
  3944. "DOM_VK_ALT": 1,
  3945. "DOM_VK_PAUSE": 1,
  3946. "DOM_VK_CAPS_LOCK": 1,
  3947. "DOM_VK_ESCAPE": 1,
  3948. "DOM_VK_SPACE": 1,
  3949. "DOM_VK_END": 1,
  3950. "DOM_VK_HOME": 1,
  3951. "DOM_VK_PRINTSCREEN": 1,
  3952. "DOM_VK_INSERT": 1,
  3953. "DOM_VK_DELETE": 1,
  3954. "DOM_VK_0": 1,
  3955. "DOM_VK_1": 1,
  3956. "DOM_VK_2": 1,
  3957. "DOM_VK_3": 1,
  3958. "DOM_VK_4": 1,
  3959. "DOM_VK_5": 1,
  3960. "DOM_VK_6": 1,
  3961. "DOM_VK_7": 1,
  3962. "DOM_VK_8": 1,
  3963. "DOM_VK_9": 1,
  3964. "DOM_VK_SEMICOLON": 1,
  3965. "DOM_VK_EQUALS": 1,
  3966. "DOM_VK_A": 1,
  3967. "DOM_VK_B": 1,
  3968. "DOM_VK_C": 1,
  3969. "DOM_VK_D": 1,
  3970. "DOM_VK_E": 1,
  3971. "DOM_VK_F": 1,
  3972. "DOM_VK_G": 1,
  3973. "DOM_VK_H": 1,
  3974. "DOM_VK_I": 1,
  3975. "DOM_VK_J": 1,
  3976. "DOM_VK_K": 1,
  3977. "DOM_VK_L": 1,
  3978. "DOM_VK_M": 1,
  3979. "DOM_VK_N": 1,
  3980. "DOM_VK_O": 1,
  3981. "DOM_VK_P": 1,
  3982. "DOM_VK_Q": 1,
  3983. "DOM_VK_R": 1,
  3984. "DOM_VK_S": 1,
  3985. "DOM_VK_T": 1,
  3986. "DOM_VK_U": 1,
  3987. "DOM_VK_V": 1,
  3988. "DOM_VK_W": 1,
  3989. "DOM_VK_X": 1,
  3990. "DOM_VK_Y": 1,
  3991. "DOM_VK_Z": 1,
  3992. "DOM_VK_CONTEXT_MENU": 1,
  3993. "DOM_VK_NUMPAD0": 1,
  3994. "DOM_VK_NUMPAD1": 1,
  3995. "DOM_VK_NUMPAD2": 1,
  3996. "DOM_VK_NUMPAD3": 1,
  3997. "DOM_VK_NUMPAD4": 1,
  3998. "DOM_VK_NUMPAD5": 1,
  3999. "DOM_VK_NUMPAD6": 1,
  4000. "DOM_VK_NUMPAD7": 1,
  4001. "DOM_VK_NUMPAD8": 1,
  4002. "DOM_VK_NUMPAD9": 1,
  4003. "DOM_VK_MULTIPLY": 1,
  4004. "DOM_VK_ADD": 1,
  4005. "DOM_VK_SEPARATOR": 1,
  4006. "DOM_VK_SUBTRACT": 1,
  4007. "DOM_VK_DECIMAL": 1,
  4008. "DOM_VK_DIVIDE": 1,
  4009. "DOM_VK_F1": 1,
  4010. "DOM_VK_F2": 1,
  4011. "DOM_VK_F3": 1,
  4012. "DOM_VK_F4": 1,
  4013. "DOM_VK_F5": 1,
  4014. "DOM_VK_F6": 1,
  4015. "DOM_VK_F7": 1,
  4016. "DOM_VK_F8": 1,
  4017. "DOM_VK_F9": 1,
  4018. "DOM_VK_F10": 1,
  4019. "DOM_VK_F11": 1,
  4020. "DOM_VK_F12": 1,
  4021. "DOM_VK_F13": 1,
  4022. "DOM_VK_F14": 1,
  4023. "DOM_VK_F15": 1,
  4024. "DOM_VK_F16": 1,
  4025. "DOM_VK_F17": 1,
  4026. "DOM_VK_F18": 1,
  4027. "DOM_VK_F19": 1,
  4028. "DOM_VK_F20": 1,
  4029. "DOM_VK_F21": 1,
  4030. "DOM_VK_F22": 1,
  4031. "DOM_VK_F23": 1,
  4032. "DOM_VK_F24": 1,
  4033. "DOM_VK_NUM_LOCK": 1,
  4034. "DOM_VK_SCROLL_LOCK": 1,
  4035. "DOM_VK_COMMA": 1,
  4036. "DOM_VK_PERIOD": 1,
  4037. "DOM_VK_SLASH": 1,
  4038. "DOM_VK_BACK_QUOTE": 1,
  4039. "DOM_VK_OPEN_BRACKET": 1,
  4040. "DOM_VK_BACK_SLASH": 1,
  4041. "DOM_VK_CLOSE_BRACKET": 1,
  4042. "DOM_VK_QUOTE": 1,
  4043. "DOM_VK_META": 1,
  4044. "SVG_ZOOMANDPAN_DISABLE": 1,
  4045. "SVG_ZOOMANDPAN_MAGNIFY": 1,
  4046. "SVG_ZOOMANDPAN_UNKNOWN": 1
  4047. };
  4048. this.cssInfo =
  4049. {
  4050. "background": ["bgRepeat", "bgAttachment", "bgPosition", "color", "systemColor", "none"],
  4051. "background-attachment": ["bgAttachment"],
  4052. "background-color": ["color", "systemColor"],
  4053. "background-image": ["none"],
  4054. "background-position": ["bgPosition"],
  4055. "background-repeat": ["bgRepeat"],
  4056. "border": ["borderStyle", "thickness", "color", "systemColor", "none"],
  4057. "border-top": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
  4058. "border-right": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
  4059. "border-bottom": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
  4060. "border-left": ["borderStyle", "borderCollapse", "color", "systemColor", "none"],
  4061. "border-collapse": ["borderCollapse"],
  4062. "border-color": ["color", "systemColor"],
  4063. "border-top-color": ["color", "systemColor"],
  4064. "border-right-color": ["color", "systemColor"],
  4065. "border-bottom-color": ["color", "systemColor"],
  4066. "border-left-color": ["color", "systemColor"],
  4067. "border-spacing": [],
  4068. "border-style": ["borderStyle"],
  4069. "border-top-style": ["borderStyle"],
  4070. "border-right-style": ["borderStyle"],
  4071. "border-bottom-style": ["borderStyle"],
  4072. "border-left-style": ["borderStyle"],
  4073. "border-width": ["thickness"],
  4074. "border-top-width": ["thickness"],
  4075. "border-right-width": ["thickness"],
  4076. "border-bottom-width": ["thickness"],
  4077. "border-left-width": ["thickness"],
  4078. "bottom": ["auto"],
  4079. "caption-side": ["captionSide"],
  4080. "clear": ["clear", "none"],
  4081. "clip": ["auto"],
  4082. "color": ["color", "systemColor"],
  4083. "content": ["content"],
  4084. "counter-increment": ["none"],
  4085. "counter-reset": ["none"],
  4086. "cursor": ["cursor", "none"],
  4087. "direction": ["direction"],
  4088. "display": ["display", "none"],
  4089. "empty-cells": [],
  4090. "float": ["float", "none"],
  4091. "font": ["fontStyle", "fontVariant", "fontWeight", "fontFamily"],
  4092. "font-family": ["fontFamily"],
  4093. "font-size": ["fontSize"],
  4094. "font-size-adjust": [],
  4095. "font-stretch": [],
  4096. "font-style": ["fontStyle"],
  4097. "font-variant": ["fontVariant"],
  4098. "font-weight": ["fontWeight"],
  4099. "height": ["auto"],
  4100. "left": ["auto"],
  4101. "letter-spacing": [],
  4102. "line-height": [],
  4103. "list-style": ["listStyleType", "listStylePosition", "none"],
  4104. "list-style-image": ["none"],
  4105. "list-style-position": ["listStylePosition"],
  4106. "list-style-type": ["listStyleType", "none"],
  4107. "margin": [],
  4108. "margin-top": [],
  4109. "margin-right": [],
  4110. "margin-bottom": [],
  4111. "margin-left": [],
  4112. "marker-offset": ["auto"],
  4113. "min-height": ["none"],
  4114. "max-height": ["none"],
  4115. "min-width": ["none"],
  4116. "max-width": ["none"],
  4117. "outline": ["borderStyle", "color", "systemColor", "none"],
  4118. "outline-color": ["color", "systemColor"],
  4119. "outline-style": ["borderStyle"],
  4120. "outline-width": [],
  4121. "overflow": ["overflow", "auto"],
  4122. "overflow-x": ["overflow", "auto"],
  4123. "overflow-y": ["overflow", "auto"],
  4124. "padding": [],
  4125. "padding-top": [],
  4126. "padding-right": [],
  4127. "padding-bottom": [],
  4128. "padding-left": [],
  4129. "position": ["position"],
  4130. "quotes": ["none"],
  4131. "right": ["auto"],
  4132. "table-layout": ["tableLayout", "auto"],
  4133. "text-align": ["textAlign"],
  4134. "text-decoration": ["textDecoration", "none"],
  4135. "text-indent": [],
  4136. "text-shadow": [],
  4137. "text-transform": ["textTransform", "none"],
  4138. "top": ["auto"],
  4139. "unicode-bidi": [],
  4140. "vertical-align": ["verticalAlign"],
  4141. "white-space": ["whiteSpace"],
  4142. "width": ["auto"],
  4143. "word-spacing": [],
  4144. "z-index": [],
  4145. "-moz-appearance": ["mozAppearance"],
  4146. "-moz-border-radius": [],
  4147. "-moz-border-radius-bottomleft": [],
  4148. "-moz-border-radius-bottomright": [],
  4149. "-moz-border-radius-topleft": [],
  4150. "-moz-border-radius-topright": [],
  4151. "-moz-border-top-colors": ["color", "systemColor"],
  4152. "-moz-border-right-colors": ["color", "systemColor"],
  4153. "-moz-border-bottom-colors": ["color", "systemColor"],
  4154. "-moz-border-left-colors": ["color", "systemColor"],
  4155. "-moz-box-align": ["mozBoxAlign"],
  4156. "-moz-box-direction": ["mozBoxDirection"],
  4157. "-moz-box-flex": [],
  4158. "-moz-box-ordinal-group": [],
  4159. "-moz-box-orient": ["mozBoxOrient"],
  4160. "-moz-box-pack": ["mozBoxPack"],
  4161. "-moz-box-sizing": ["mozBoxSizing"],
  4162. "-moz-opacity": [],
  4163. "-moz-user-focus": ["userFocus", "none"],
  4164. "-moz-user-input": ["userInput"],
  4165. "-moz-user-modify": [],
  4166. "-moz-user-select": ["userSelect", "none"],
  4167. "-moz-background-clip": [],
  4168. "-moz-background-inline-policy": [],
  4169. "-moz-background-origin": [],
  4170. "-moz-binding": [],
  4171. "-moz-column-count": [],
  4172. "-moz-column-gap": [],
  4173. "-moz-column-width": [],
  4174. "-moz-image-region": []
  4175. };
  4176. this.inheritedStyleNames =
  4177. {
  4178. "border-collapse": 1,
  4179. "border-spacing": 1,
  4180. "border-style": 1,
  4181. "caption-side": 1,
  4182. "color": 1,
  4183. "cursor": 1,
  4184. "direction": 1,
  4185. "empty-cells": 1,
  4186. "font": 1,
  4187. "font-family": 1,
  4188. "font-size-adjust": 1,
  4189. "font-size": 1,
  4190. "font-style": 1,
  4191. "font-variant": 1,
  4192. "font-weight": 1,
  4193. "letter-spacing": 1,
  4194. "line-height": 1,
  4195. "list-style": 1,
  4196. "list-style-image": 1,
  4197. "list-style-position": 1,
  4198. "list-style-type": 1,
  4199. "quotes": 1,
  4200. "text-align": 1,
  4201. "text-decoration": 1,
  4202. "text-indent": 1,
  4203. "text-shadow": 1,
  4204. "text-transform": 1,
  4205. "white-space": 1,
  4206. "word-spacing": 1
  4207. };
  4208. this.cssKeywords =
  4209. {
  4210. "appearance":
  4211. [
  4212. "button",
  4213. "button-small",
  4214. "checkbox",
  4215. "checkbox-container",
  4216. "checkbox-small",
  4217. "dialog",
  4218. "listbox",
  4219. "menuitem",
  4220. "menulist",
  4221. "menulist-button",
  4222. "menulist-textfield",
  4223. "menupopup",
  4224. "progressbar",
  4225. "radio",
  4226. "radio-container",
  4227. "radio-small",
  4228. "resizer",
  4229. "scrollbar",
  4230. "scrollbarbutton-down",
  4231. "scrollbarbutton-left",
  4232. "scrollbarbutton-right",
  4233. "scrollbarbutton-up",
  4234. "scrollbartrack-horizontal",
  4235. "scrollbartrack-vertical",
  4236. "separator",
  4237. "statusbar",
  4238. "tab",
  4239. "tab-left-edge",
  4240. "tabpanels",
  4241. "textfield",
  4242. "toolbar",
  4243. "toolbarbutton",
  4244. "toolbox",
  4245. "tooltip",
  4246. "treeheadercell",
  4247. "treeheadersortarrow",
  4248. "treeitem",
  4249. "treetwisty",
  4250. "treetwistyopen",
  4251. "treeview",
  4252. "window"
  4253. ],
  4254. "systemColor":
  4255. [
  4256. "ActiveBorder",
  4257. "ActiveCaption",
  4258. "AppWorkspace",
  4259. "Background",
  4260. "ButtonFace",
  4261. "ButtonHighlight",
  4262. "ButtonShadow",
  4263. "ButtonText",
  4264. "CaptionText",
  4265. "GrayText",
  4266. "Highlight",
  4267. "HighlightText",
  4268. "InactiveBorder",
  4269. "InactiveCaption",
  4270. "InactiveCaptionText",
  4271. "InfoBackground",
  4272. "InfoText",
  4273. "Menu",
  4274. "MenuText",
  4275. "Scrollbar",
  4276. "ThreeDDarkShadow",
  4277. "ThreeDFace",
  4278. "ThreeDHighlight",
  4279. "ThreeDLightShadow",
  4280. "ThreeDShadow",
  4281. "Window",
  4282. "WindowFrame",
  4283. "WindowText",
  4284. "-moz-field",
  4285. "-moz-fieldtext",
  4286. "-moz-workspace",
  4287. "-moz-visitedhyperlinktext",
  4288. "-moz-use-text-color"
  4289. ],
  4290. "color":
  4291. [
  4292. "AliceBlue",
  4293. "AntiqueWhite",
  4294. "Aqua",
  4295. "Aquamarine",
  4296. "Azure",
  4297. "Beige",
  4298. "Bisque",
  4299. "Black",
  4300. "BlanchedAlmond",
  4301. "Blue",
  4302. "BlueViolet",
  4303. "Brown",
  4304. "BurlyWood",
  4305. "CadetBlue",
  4306. "Chartreuse",
  4307. "Chocolate",
  4308. "Coral",
  4309. "CornflowerBlue",
  4310. "Cornsilk",
  4311. "Crimson",
  4312. "Cyan",
  4313. "DarkBlue",
  4314. "DarkCyan",
  4315. "DarkGoldenRod",
  4316. "DarkGray",
  4317. "DarkGreen",
  4318. "DarkKhaki",
  4319. "DarkMagenta",
  4320. "DarkOliveGreen",
  4321. "DarkOrange",
  4322. "DarkOrchid",
  4323. "DarkRed",
  4324. "DarkSalmon",
  4325. "DarkSeaGreen",
  4326. "DarkSlateBlue",
  4327. "DarkSlateGray",
  4328. "DarkTurquoise",
  4329. "DarkViolet",
  4330. "DeepPink",
  4331. "DarkSkyBlue",
  4332. "DimGray",
  4333. "DodgerBlue",
  4334. "Feldspar",
  4335. "FireBrick",
  4336. "FloralWhite",
  4337. "ForestGreen",
  4338. "Fuchsia",
  4339. "Gainsboro",
  4340. "GhostWhite",
  4341. "Gold",
  4342. "GoldenRod",
  4343. "Gray",
  4344. "Green",
  4345. "GreenYellow",
  4346. "HoneyDew",
  4347. "HotPink",
  4348. "IndianRed",
  4349. "Indigo",
  4350. "Ivory",
  4351. "Khaki",
  4352. "Lavender",
  4353. "LavenderBlush",
  4354. "LawnGreen",
  4355. "LemonChiffon",
  4356. "LightBlue",
  4357. "LightCoral",
  4358. "LightCyan",
  4359. "LightGoldenRodYellow",
  4360. "LightGrey",
  4361. "LightGreen",
  4362. "LightPink",
  4363. "LightSalmon",
  4364. "LightSeaGreen",
  4365. "LightSkyBlue",
  4366. "LightSlateBlue",
  4367. "LightSlateGray",
  4368. "LightSteelBlue",
  4369. "LightYellow",
  4370. "Lime",
  4371. "LimeGreen",
  4372. "Linen",
  4373. "Magenta",
  4374. "Maroon",
  4375. "MediumAquaMarine",
  4376. "MediumBlue",
  4377. "MediumOrchid",
  4378. "MediumPurple",
  4379. "MediumSeaGreen",
  4380. "MediumSlateBlue",
  4381. "MediumSpringGreen",
  4382. "MediumTurquoise",
  4383. "MediumVioletRed",
  4384. "MidnightBlue",
  4385. "MintCream",
  4386. "MistyRose",
  4387. "Moccasin",
  4388. "NavajoWhite",
  4389. "Navy",
  4390. "OldLace",
  4391. "Olive",
  4392. "OliveDrab",
  4393. "Orange",
  4394. "OrangeRed",
  4395. "Orchid",
  4396. "PaleGoldenRod",
  4397. "PaleGreen",
  4398. "PaleTurquoise",
  4399. "PaleVioletRed",
  4400. "PapayaWhip",
  4401. "PeachPuff",
  4402. "Peru",
  4403. "Pink",
  4404. "Plum",
  4405. "PowderBlue",
  4406. "Purple",
  4407. "Red",
  4408. "RosyBrown",
  4409. "RoyalBlue",
  4410. "SaddleBrown",
  4411. "Salmon",
  4412. "SandyBrown",
  4413. "SeaGreen",
  4414. "SeaShell",
  4415. "Sienna",
  4416. "Silver",
  4417. "SkyBlue",
  4418. "SlateBlue",
  4419. "SlateGray",
  4420. "Snow",
  4421. "SpringGreen",
  4422. "SteelBlue",
  4423. "Tan",
  4424. "Teal",
  4425. "Thistle",
  4426. "Tomato",
  4427. "Turquoise",
  4428. "Violet",
  4429. "VioletRed",
  4430. "Wheat",
  4431. "White",
  4432. "WhiteSmoke",
  4433. "Yellow",
  4434. "YellowGreen",
  4435. "transparent",
  4436. "invert"
  4437. ],
  4438. "auto":
  4439. [
  4440. "auto"
  4441. ],
  4442. "none":
  4443. [
  4444. "none"
  4445. ],
  4446. "captionSide":
  4447. [
  4448. "top",
  4449. "bottom",
  4450. "left",
  4451. "right"
  4452. ],
  4453. "clear":
  4454. [
  4455. "left",
  4456. "right",
  4457. "both"
  4458. ],
  4459. "cursor":
  4460. [
  4461. "auto",
  4462. "cell",
  4463. "context-menu",
  4464. "crosshair",
  4465. "default",
  4466. "help",
  4467. "pointer",
  4468. "progress",
  4469. "move",
  4470. "e-resize",
  4471. "all-scroll",
  4472. "ne-resize",
  4473. "nw-resize",
  4474. "n-resize",
  4475. "se-resize",
  4476. "sw-resize",
  4477. "s-resize",
  4478. "w-resize",
  4479. "ew-resize",
  4480. "ns-resize",
  4481. "nesw-resize",
  4482. "nwse-resize",
  4483. "col-resize",
  4484. "row-resize",
  4485. "text",
  4486. "vertical-text",
  4487. "wait",
  4488. "alias",
  4489. "copy",
  4490. "move",
  4491. "no-drop",
  4492. "not-allowed",
  4493. "-moz-alias",
  4494. "-moz-cell",
  4495. "-moz-copy",
  4496. "-moz-grab",
  4497. "-moz-grabbing",
  4498. "-moz-contextmenu",
  4499. "-moz-zoom-in",
  4500. "-moz-zoom-out",
  4501. "-moz-spinning"
  4502. ],
  4503. "direction":
  4504. [
  4505. "ltr",
  4506. "rtl"
  4507. ],
  4508. "bgAttachment":
  4509. [
  4510. "scroll",
  4511. "fixed"
  4512. ],
  4513. "bgPosition":
  4514. [
  4515. "top",
  4516. "center",
  4517. "bottom",
  4518. "left",
  4519. "right"
  4520. ],
  4521. "bgRepeat":
  4522. [
  4523. "repeat",
  4524. "repeat-x",
  4525. "repeat-y",
  4526. "no-repeat"
  4527. ],
  4528. "borderStyle":
  4529. [
  4530. "hidden",
  4531. "dotted",
  4532. "dashed",
  4533. "solid",
  4534. "double",
  4535. "groove",
  4536. "ridge",
  4537. "inset",
  4538. "outset",
  4539. "-moz-bg-inset",
  4540. "-moz-bg-outset",
  4541. "-moz-bg-solid"
  4542. ],
  4543. "borderCollapse":
  4544. [
  4545. "collapse",
  4546. "separate"
  4547. ],
  4548. "overflow":
  4549. [
  4550. "visible",
  4551. "hidden",
  4552. "scroll",
  4553. "-moz-scrollbars-horizontal",
  4554. "-moz-scrollbars-none",
  4555. "-moz-scrollbars-vertical"
  4556. ],
  4557. "listStyleType":
  4558. [
  4559. "disc",
  4560. "circle",
  4561. "square",
  4562. "decimal",
  4563. "decimal-leading-zero",
  4564. "lower-roman",
  4565. "upper-roman",
  4566. "lower-greek",
  4567. "lower-alpha",
  4568. "lower-latin",
  4569. "upper-alpha",
  4570. "upper-latin",
  4571. "hebrew",
  4572. "armenian",
  4573. "georgian",
  4574. "cjk-ideographic",
  4575. "hiragana",
  4576. "katakana",
  4577. "hiragana-iroha",
  4578. "katakana-iroha",
  4579. "inherit"
  4580. ],
  4581. "listStylePosition":
  4582. [
  4583. "inside",
  4584. "outside"
  4585. ],
  4586. "content":
  4587. [
  4588. "open-quote",
  4589. "close-quote",
  4590. "no-open-quote",
  4591. "no-close-quote",
  4592. "inherit"
  4593. ],
  4594. "fontStyle":
  4595. [
  4596. "normal",
  4597. "italic",
  4598. "oblique",
  4599. "inherit"
  4600. ],
  4601. "fontVariant":
  4602. [
  4603. "normal",
  4604. "small-caps",
  4605. "inherit"
  4606. ],
  4607. "fontWeight":
  4608. [
  4609. "normal",
  4610. "bold",
  4611. "bolder",
  4612. "lighter",
  4613. "inherit"
  4614. ],
  4615. "fontSize":
  4616. [
  4617. "xx-small",
  4618. "x-small",
  4619. "small",
  4620. "medium",
  4621. "large",
  4622. "x-large",
  4623. "xx-large",
  4624. "smaller",
  4625. "larger"
  4626. ],
  4627. "fontFamily":
  4628. [
  4629. "Arial",
  4630. "Comic Sans MS",
  4631. "Georgia",
  4632. "Tahoma",
  4633. "Verdana",
  4634. "Times New Roman",
  4635. "Trebuchet MS",
  4636. "Lucida Grande",
  4637. "Helvetica",
  4638. "serif",
  4639. "sans-serif",
  4640. "cursive",
  4641. "fantasy",
  4642. "monospace",
  4643. "caption",
  4644. "icon",
  4645. "menu",
  4646. "message-box",
  4647. "small-caption",
  4648. "status-bar",
  4649. "inherit"
  4650. ],
  4651. "display":
  4652. [
  4653. "block",
  4654. "inline",
  4655. "inline-block",
  4656. "list-item",
  4657. "marker",
  4658. "run-in",
  4659. "compact",
  4660. "table",
  4661. "inline-table",
  4662. "table-row-group",
  4663. "table-column",
  4664. "table-column-group",
  4665. "table-header-group",
  4666. "table-footer-group",
  4667. "table-row",
  4668. "table-cell",
  4669. "table-caption",
  4670. "-moz-box",
  4671. "-moz-compact",
  4672. "-moz-deck",
  4673. "-moz-grid",
  4674. "-moz-grid-group",
  4675. "-moz-grid-line",
  4676. "-moz-groupbox",
  4677. "-moz-inline-block",
  4678. "-moz-inline-box",
  4679. "-moz-inline-grid",
  4680. "-moz-inline-stack",
  4681. "-moz-inline-table",
  4682. "-moz-marker",
  4683. "-moz-popup",
  4684. "-moz-runin",
  4685. "-moz-stack"
  4686. ],
  4687. "position":
  4688. [
  4689. "static",
  4690. "relative",
  4691. "absolute",
  4692. "fixed",
  4693. "inherit"
  4694. ],
  4695. "float":
  4696. [
  4697. "left",
  4698. "right"
  4699. ],
  4700. "textAlign":
  4701. [
  4702. "left",
  4703. "right",
  4704. "center",
  4705. "justify"
  4706. ],
  4707. "tableLayout":
  4708. [
  4709. "fixed"
  4710. ],
  4711. "textDecoration":
  4712. [
  4713. "underline",
  4714. "overline",
  4715. "line-through",
  4716. "blink"
  4717. ],
  4718. "textTransform":
  4719. [
  4720. "capitalize",
  4721. "lowercase",
  4722. "uppercase",
  4723. "inherit"
  4724. ],
  4725. "unicodeBidi":
  4726. [
  4727. "normal",
  4728. "embed",
  4729. "bidi-override"
  4730. ],
  4731. "whiteSpace":
  4732. [
  4733. "normal",
  4734. "pre",
  4735. "nowrap"
  4736. ],
  4737. "verticalAlign":
  4738. [
  4739. "baseline",
  4740. "sub",
  4741. "super",
  4742. "top",
  4743. "text-top",
  4744. "middle",
  4745. "bottom",
  4746. "text-bottom",
  4747. "inherit"
  4748. ],
  4749. "thickness":
  4750. [
  4751. "thin",
  4752. "medium",
  4753. "thick"
  4754. ],
  4755. "userFocus":
  4756. [
  4757. "ignore",
  4758. "normal"
  4759. ],
  4760. "userInput":
  4761. [
  4762. "disabled",
  4763. "enabled"
  4764. ],
  4765. "userSelect":
  4766. [
  4767. "normal"
  4768. ],
  4769. "mozBoxSizing":
  4770. [
  4771. "content-box",
  4772. "padding-box",
  4773. "border-box"
  4774. ],
  4775. "mozBoxAlign":
  4776. [
  4777. "start",
  4778. "center",
  4779. "end",
  4780. "baseline",
  4781. "stretch"
  4782. ],
  4783. "mozBoxDirection":
  4784. [
  4785. "normal",
  4786. "reverse"
  4787. ],
  4788. "mozBoxOrient":
  4789. [
  4790. "horizontal",
  4791. "vertical"
  4792. ],
  4793. "mozBoxPack":
  4794. [
  4795. "start",
  4796. "center",
  4797. "end"
  4798. ]
  4799. };
  4800. this.nonEditableTags =
  4801. {
  4802. "HTML": 1,
  4803. "HEAD": 1,
  4804. "html": 1,
  4805. "head": 1
  4806. };
  4807. this.innerEditableTags =
  4808. {
  4809. "BODY": 1,
  4810. "body": 1
  4811. };
  4812. this.selfClosingTags =
  4813. { // End tags for void elements are forbidden http://wiki.whatwg.org/wiki/HTML_vs._XHTML
  4814. "meta": 1,
  4815. "link": 1,
  4816. "area": 1,
  4817. "base": 1,
  4818. "col": 1,
  4819. "input": 1,
  4820. "img": 1,
  4821. "br": 1,
  4822. "hr": 1,
  4823. "param":1,
  4824. "embed":1
  4825. };
  4826. var invisibleTags = this.invisibleTags =
  4827. {
  4828. "HTML": 1,
  4829. "HEAD": 1,
  4830. "TITLE": 1,
  4831. "META": 1,
  4832. "LINK": 1,
  4833. "STYLE": 1,
  4834. "SCRIPT": 1,
  4835. "NOSCRIPT": 1,
  4836. "BR": 1,
  4837. "PARAM": 1,
  4838. "COL": 1,
  4839. "html": 1,
  4840. "head": 1,
  4841. "title": 1,
  4842. "meta": 1,
  4843. "link": 1,
  4844. "style": 1,
  4845. "script": 1,
  4846. "noscript": 1,
  4847. "br": 1,
  4848. "param": 1,
  4849. "col": 1
  4850. /*
  4851. "window": 1,
  4852. "browser": 1,
  4853. "frame": 1,
  4854. "tabbrowser": 1,
  4855. "WINDOW": 1,
  4856. "BROWSER": 1,
  4857. "FRAME": 1,
  4858. "TABBROWSER": 1,
  4859. */
  4860. };
  4861. if (typeof KeyEvent == "undefined") {
  4862. this.KeyEvent = {
  4863. DOM_VK_CANCEL: 3,
  4864. DOM_VK_HELP: 6,
  4865. DOM_VK_BACK_SPACE: 8,
  4866. DOM_VK_TAB: 9,
  4867. DOM_VK_CLEAR: 12,
  4868. DOM_VK_RETURN: 13,
  4869. DOM_VK_ENTER: 14,
  4870. DOM_VK_SHIFT: 16,
  4871. DOM_VK_CONTROL: 17,
  4872. DOM_VK_ALT: 18,
  4873. DOM_VK_PAUSE: 19,
  4874. DOM_VK_CAPS_LOCK: 20,
  4875. DOM_VK_ESCAPE: 27,
  4876. DOM_VK_SPACE: 32,
  4877. DOM_VK_PAGE_UP: 33,
  4878. DOM_VK_PAGE_DOWN: 34,
  4879. DOM_VK_END: 35,
  4880. DOM_VK_HOME: 36,
  4881. DOM_VK_LEFT: 37,
  4882. DOM_VK_UP: 38,
  4883. DOM_VK_RIGHT: 39,
  4884. DOM_VK_DOWN: 40,
  4885. DOM_VK_PRINTSCREEN: 44,
  4886. DOM_VK_INSERT: 45,
  4887. DOM_VK_DELETE: 46,
  4888. DOM_VK_0: 48,
  4889. DOM_VK_1: 49,
  4890. DOM_VK_2: 50,
  4891. DOM_VK_3: 51,
  4892. DOM_VK_4: 52,
  4893. DOM_VK_5: 53,
  4894. DOM_VK_6: 54,
  4895. DOM_VK_7: 55,
  4896. DOM_VK_8: 56,
  4897. DOM_VK_9: 57,
  4898. DOM_VK_SEMICOLON: 59,
  4899. DOM_VK_EQUALS: 61,
  4900. DOM_VK_A: 65,
  4901. DOM_VK_B: 66,
  4902. DOM_VK_C: 67,
  4903. DOM_VK_D: 68,
  4904. DOM_VK_E: 69,
  4905. DOM_VK_F: 70,
  4906. DOM_VK_G: 71,
  4907. DOM_VK_H: 72,
  4908. DOM_VK_I: 73,
  4909. DOM_VK_J: 74,
  4910. DOM_VK_K: 75,
  4911. DOM_VK_L: 76,
  4912. DOM_VK_M: 77,
  4913. DOM_VK_N: 78,
  4914. DOM_VK_O: 79,
  4915. DOM_VK_P: 80,
  4916. DOM_VK_Q: 81,
  4917. DOM_VK_R: 82,
  4918. DOM_VK_S: 83,
  4919. DOM_VK_T: 84,
  4920. DOM_VK_U: 85,
  4921. DOM_VK_V: 86,
  4922. DOM_VK_W: 87,
  4923. DOM_VK_X: 88,
  4924. DOM_VK_Y: 89,
  4925. DOM_VK_Z: 90,
  4926. DOM_VK_CONTEXT_MENU: 93,
  4927. DOM_VK_NUMPAD0: 96,
  4928. DOM_VK_NUMPAD1: 97,
  4929. DOM_VK_NUMPAD2: 98,
  4930. DOM_VK_NUMPAD3: 99,
  4931. DOM_VK_NUMPAD4: 100,
  4932. DOM_VK_NUMPAD5: 101,
  4933. DOM_VK_NUMPAD6: 102,
  4934. DOM_VK_NUMPAD7: 103,
  4935. DOM_VK_NUMPAD8: 104,
  4936. DOM_VK_NUMPAD9: 105,
  4937. DOM_VK_MULTIPLY: 106,
  4938. DOM_VK_ADD: 107,
  4939. DOM_VK_SEPARATOR: 108,
  4940. DOM_VK_SUBTRACT: 109,
  4941. DOM_VK_DECIMAL: 110,
  4942. DOM_VK_DIVIDE: 111,
  4943. DOM_VK_F1: 112,
  4944. DOM_VK_F2: 113,
  4945. DOM_VK_F3: 114,
  4946. DOM_VK_F4: 115,
  4947. DOM_VK_F5: 116,
  4948. DOM_VK_F6: 117,
  4949. DOM_VK_F7: 118,
  4950. DOM_VK_F8: 119,
  4951. DOM_VK_F9: 120,
  4952. DOM_VK_F10: 121,
  4953. DOM_VK_F11: 122,
  4954. DOM_VK_F12: 123,
  4955. DOM_VK_F13: 124,
  4956. DOM_VK_F14: 125,
  4957. DOM_VK_F15: 126,
  4958. DOM_VK_F16: 127,
  4959. DOM_VK_F17: 128,
  4960. DOM_VK_F18: 129,
  4961. DOM_VK_F19: 130,
  4962. DOM_VK_F20: 131,
  4963. DOM_VK_F21: 132,
  4964. DOM_VK_F22: 133,
  4965. DOM_VK_F23: 134,
  4966. DOM_VK_F24: 135,
  4967. DOM_VK_NUM_LOCK: 144,
  4968. DOM_VK_SCROLL_LOCK: 145,
  4969. DOM_VK_COMMA: 188,
  4970. DOM_VK_PERIOD: 190,
  4971. DOM_VK_SLASH: 191,
  4972. DOM_VK_BACK_QUOTE: 192,
  4973. DOM_VK_OPEN_BRACKET: 219,
  4974. DOM_VK_BACK_SLASH: 220,
  4975. DOM_VK_CLOSE_BRACKET: 221,
  4976. DOM_VK_QUOTE: 222,
  4977. DOM_VK_META: 224
  4978. };
  4979. }
  4980. // ************************************************************************************************
  4981. // Ajax
  4982. /**
  4983. * @namespace
  4984. */
  4985. this.Ajax =
  4986. {
  4987. requests: [],
  4988. transport: null,
  4989. states: ["Uninitialized","Loading","Loaded","Interactive","Complete"],
  4990. initialize: function()
  4991. {
  4992. this.transport = this.getXHRObject();
  4993. },
  4994. getXHRObject: function()
  4995. {
  4996. var xhrObj = false;
  4997. try
  4998. {
  4999. xhrObj = new XMLHttpRequest();
  5000. }
  5001. catch(e)
  5002. {
  5003. var progid = [
  5004. "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0",
  5005. "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"
  5006. ];
  5007. for ( var i=0; i < progid.length; ++i ) {
  5008. try
  5009. {
  5010. xhrObj = new ActiveXObject(progid[i]);
  5011. }
  5012. catch(e)
  5013. {
  5014. continue;
  5015. }
  5016. break;
  5017. }
  5018. }
  5019. finally
  5020. {
  5021. return xhrObj;
  5022. }
  5023. },
  5024. /**
  5025. * Create a AJAX request.
  5026. *
  5027. * @name request
  5028. * @param {Object} options request options
  5029. * @param {String} options.url URL to be requested
  5030. * @param {String} options.type Request type ("get" ou "post"). Default is "get".
  5031. * @param {Boolean} options.async Asynchronous flag. Default is "true".
  5032. * @param {String} options.dataType Data type ("text", "html", "xml" or "json"). Default is "text".
  5033. * @param {String} options.contentType Content-type of the data being sent. Default is "application/x-www-form-urlencoded".
  5034. * @param {Function} options.onLoading onLoading callback
  5035. * @param {Function} options.onLoaded onLoaded callback
  5036. * @param {Function} options.onInteractive onInteractive callback
  5037. * @param {Function} options.onComplete onComplete callback
  5038. * @param {Function} options.onUpdate onUpdate callback
  5039. * @param {Function} options.onSuccess onSuccess callback
  5040. * @param {Function} options.onFailure onFailure callback
  5041. */
  5042. request: function(options)
  5043. {
  5044. // process options
  5045. var o = FBL.extend(
  5046. {
  5047. // default values
  5048. type: "get",
  5049. async: true,
  5050. dataType: "text",
  5051. contentType: "application/x-www-form-urlencoded"
  5052. },
  5053. options || {}
  5054. );
  5055. this.requests.push(o);
  5056. var s = this.getState();
  5057. if (s == "Uninitialized" || s == "Complete" || s == "Loaded")
  5058. this.sendRequest();
  5059. },
  5060. serialize: function(data)
  5061. {
  5062. var r = [""], rl = 0;
  5063. if (data) {
  5064. if (typeof data == "string") r[rl++] = data;
  5065. else if (data.innerHTML && data.elements) {
  5066. for (var i=0,el,l=(el=data.elements).length; i < l; i++)
  5067. if (el[i].name) {
  5068. r[rl++] = encodeURIComponent(el[i].name);
  5069. r[rl++] = "=";
  5070. r[rl++] = encodeURIComponent(el[i].value);
  5071. r[rl++] = "&";
  5072. }
  5073. } else
  5074. for(var param in data) {
  5075. r[rl++] = encodeURIComponent(param);
  5076. r[rl++] = "=";
  5077. r[rl++] = encodeURIComponent(data[param]);
  5078. r[rl++] = "&";
  5079. }
  5080. }
  5081. return r.join("").replace(/&$/, "");
  5082. },
  5083. sendRequest: function()
  5084. {
  5085. var t = FBL.Ajax.transport, r = FBL.Ajax.requests.shift(), data;
  5086. // open XHR object
  5087. t.open(r.type, r.url, r.async);
  5088. //setRequestHeaders();
  5089. // indicates that it is a XHR request to the server
  5090. t.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  5091. // if data is being sent, sets the appropriate content-type
  5092. if (data = FBL.Ajax.serialize(r.data))
  5093. t.setRequestHeader("Content-Type", r.contentType);
  5094. /** @ignore */
  5095. // onreadystatechange handler
  5096. t.onreadystatechange = function()
  5097. {
  5098. FBL.Ajax.onStateChange(r);
  5099. };
  5100. // send the request
  5101. t.send(data);
  5102. },
  5103. /**
  5104. * Handles the state change
  5105. */
  5106. onStateChange: function(options)
  5107. {
  5108. var fn, o = options, t = this.transport;
  5109. var state = this.getState(t);
  5110. if (fn = o["on" + state]) fn(this.getResponse(o), o);
  5111. if (state == "Complete")
  5112. {
  5113. var success = t.status == 200, response = this.getResponse(o);
  5114. if (fn = o["onUpdate"])
  5115. fn(response, o);
  5116. if (fn = o["on" + (success ? "Success" : "Failure")])
  5117. fn(response, o);
  5118. t.onreadystatechange = FBL.emptyFn;
  5119. if (this.requests.length > 0)
  5120. setTimeout(this.sendRequest, 10);
  5121. }
  5122. },
  5123. /**
  5124. * gets the appropriate response value according the type
  5125. */
  5126. getResponse: function(options)
  5127. {
  5128. var t = this.transport, type = options.dataType;
  5129. if (t.status != 200) return t.statusText;
  5130. else if (type == "text") return t.responseText;
  5131. else if (type == "html") return t.responseText;
  5132. else if (type == "xml") return t.responseXML;
  5133. else if (type == "json") return eval("(" + t.responseText + ")");
  5134. },
  5135. /**
  5136. * returns the current state of the XHR object
  5137. */
  5138. getState: function()
  5139. {
  5140. return this.states[this.transport.readyState];
  5141. }
  5142. };
  5143. // ************************************************************************************************
  5144. // Cookie, from http://www.quirksmode.org/js/cookies.html
  5145. this.createCookie = function(name,value,days)
  5146. {
  5147. if ('cookie' in document)
  5148. {
  5149. if (days)
  5150. {
  5151. var date = new Date();
  5152. date.setTime(date.getTime()+(days*24*60*60*1000));
  5153. var expires = "; expires="+date.toGMTString();
  5154. }
  5155. else
  5156. var expires = "";
  5157. document.cookie = name+"="+value+expires+"; path=/";
  5158. }
  5159. };
  5160. this.readCookie = function (name)
  5161. {
  5162. if ('cookie' in document)
  5163. {
  5164. var nameEQ = name + "=";
  5165. var ca = document.cookie.split(';');
  5166. for(var i=0; i < ca.length; i++)
  5167. {
  5168. var c = ca[i];
  5169. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  5170. if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  5171. }
  5172. }
  5173. return null;
  5174. };
  5175. this.removeCookie = function(name)
  5176. {
  5177. this.createCookie(name, "", -1);
  5178. };
  5179. // ************************************************************************************************
  5180. // http://www.mister-pixel.com/#Content__state=is_that_simple
  5181. var fixIE6BackgroundImageCache = function(doc)
  5182. {
  5183. doc = doc || document;
  5184. try
  5185. {
  5186. doc.execCommand("BackgroundImageCache", false, true);
  5187. }
  5188. catch(E)
  5189. {
  5190. }
  5191. };
  5192. // ************************************************************************************************
  5193. // calculatePixelsPerInch
  5194. var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
  5195. var calculatePixelsPerInch = function calculatePixelsPerInch(doc, body)
  5196. {
  5197. var inch = FBL.createGlobalElement("div");
  5198. inch.style.cssText = resetStyle + "width:1in; height:1in; position:absolute; top:-1234px; left:-1234px;";
  5199. body.appendChild(inch);
  5200. FBL.pixelsPerInch = {
  5201. x: inch.offsetWidth,
  5202. y: inch.offsetHeight
  5203. };
  5204. body.removeChild(inch);
  5205. };
  5206. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5207. this.SourceLink = function(url, line, type, object, instance)
  5208. {
  5209. this.href = url;
  5210. this.instance = instance;
  5211. this.line = line;
  5212. this.type = type;
  5213. this.object = object;
  5214. };
  5215. this.SourceLink.prototype =
  5216. {
  5217. toString: function()
  5218. {
  5219. return this.href;
  5220. },
  5221. toJSON: function() // until 3.1...
  5222. {
  5223. return "{\"href\":\""+this.href+"\", "+
  5224. (this.line?("\"line\":"+this.line+","):"")+
  5225. (this.type?(" \"type\":\""+this.type+"\","):"")+
  5226. "}";
  5227. }
  5228. };
  5229. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5230. this.SourceText = function(lines, owner)
  5231. {
  5232. this.lines = lines;
  5233. this.owner = owner;
  5234. };
  5235. this.SourceText.getLineAsHTML = function(lineNo)
  5236. {
  5237. return escapeForSourceLine(this.lines[lineNo-1]);
  5238. };
  5239. // ************************************************************************************************
  5240. }).apply(FBL);
  5241. /* See license.txt for terms of usage */
  5242. FBL.ns( /** @scope ns-i18n */ function() { with (FBL) {
  5243. // ************************************************************************************************
  5244. // TODO: xxxpedro localization
  5245. var oSTR =
  5246. {
  5247. "NoMembersWarning": "There are no properties to show for this object.",
  5248. "EmptyStyleSheet": "There are no rules in this stylesheet.",
  5249. "EmptyElementCSS": "This element has no style rules.",
  5250. "AccessRestricted": "Access to restricted URI denied.",
  5251. "net.label.Parameters": "Parameters",
  5252. "net.label.Source": "Source",
  5253. "URLParameters": "Params",
  5254. "EditStyle": "Edit Element Style...",
  5255. "NewRule": "New Rule...",
  5256. "NewProp": "New Property...",
  5257. "EditProp": 'Edit "%s"',
  5258. "DeleteProp": 'Delete "%s"',
  5259. "DisableProp": 'Disable "%s"'
  5260. };
  5261. // ************************************************************************************************
  5262. FBL.$STR = function(name)
  5263. {
  5264. return oSTR.hasOwnProperty(name) ? oSTR[name] : name;
  5265. };
  5266. FBL.$STRF = function(name, args)
  5267. {
  5268. if (!oSTR.hasOwnProperty(name)) return name;
  5269. var format = oSTR[name];
  5270. var objIndex = 0;
  5271. var parts = parseFormat(format);
  5272. var trialIndex = objIndex;
  5273. var objects = args;
  5274. for (var i= 0; i < parts.length; i++)
  5275. {
  5276. var part = parts[i];
  5277. if (part && typeof(part) == "object")
  5278. {
  5279. if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted.
  5280. {
  5281. format = "";
  5282. objIndex = -1;
  5283. parts.length = 0;
  5284. break;
  5285. }
  5286. }
  5287. }
  5288. var result = [];
  5289. for (var i = 0; i < parts.length; ++i)
  5290. {
  5291. var part = parts[i];
  5292. if (part && typeof(part) == "object")
  5293. {
  5294. result.push(""+args.shift());
  5295. }
  5296. else
  5297. result.push(part);
  5298. }
  5299. return result.join("");
  5300. };
  5301. // ************************************************************************************************
  5302. var parseFormat = function parseFormat(format)
  5303. {
  5304. var parts = [];
  5305. if (format.length <= 0)
  5306. return parts;
  5307. var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/;
  5308. for (var m = reg.exec(format); m; m = reg.exec(format))
  5309. {
  5310. if (m[0].substr(0, 2) == "%%")
  5311. {
  5312. parts.push(format.substr(0, m.index));
  5313. parts.push(m[0].substr(1));
  5314. }
  5315. else
  5316. {
  5317. var type = m[8] ? m[8] : m[5];
  5318. var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
  5319. var rep = null;
  5320. switch (type)
  5321. {
  5322. case "s":
  5323. rep = FirebugReps.Text;
  5324. break;
  5325. case "f":
  5326. case "i":
  5327. case "d":
  5328. rep = FirebugReps.Number;
  5329. break;
  5330. case "o":
  5331. rep = null;
  5332. break;
  5333. }
  5334. parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
  5335. parts.push({rep: rep, precision: precision, type: ("%" + type)});
  5336. }
  5337. format = format.substr(m.index+m[0].length);
  5338. }
  5339. parts.push(format);
  5340. return parts;
  5341. };
  5342. // ************************************************************************************************
  5343. }});
  5344. /* See license.txt for terms of usage */
  5345. FBL.ns( /** @scope ns-firebug */ function() { with (FBL) {
  5346. // ************************************************************************************************
  5347. // ************************************************************************************************
  5348. // Globals
  5349. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5350. // Internals
  5351. var modules = [];
  5352. var panelTypes = [];
  5353. var panelTypeMap = {};
  5354. var reps = [];
  5355. var parentPanelMap = {};
  5356. // ************************************************************************************************
  5357. // Firebug
  5358. /**
  5359. * @namespace describe Firebug
  5360. * @exports window.Firebug as Firebug
  5361. */
  5362. window.Firebug = FBL.Firebug =
  5363. {
  5364. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5365. version: "Firebug Lite 1.3.2",
  5366. revision: "$Revision: 9760 $",
  5367. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5368. modules: modules,
  5369. panelTypes: panelTypes,
  5370. panelTypeMap: panelTypeMap,
  5371. reps: reps,
  5372. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5373. // Initialization
  5374. initialize: function()
  5375. {
  5376. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.initialize", "initializing application");
  5377. Firebug.browser = new Context(Env.browser);
  5378. Firebug.context = Firebug.browser;
  5379. // Document must be cached before chrome initialization
  5380. cacheDocument();
  5381. if (Firebug.Inspector)
  5382. Firebug.Inspector.create();
  5383. if (FBL.processAllStyleSheets)
  5384. processAllStyleSheets(Firebug.browser.document);
  5385. FirebugChrome.initialize();
  5386. dispatch(modules, "initialize", []);
  5387. if (Env.onLoad)
  5388. {
  5389. var onLoad = Env.onLoad;
  5390. delete Env.onLoad;
  5391. setTimeout(onLoad, 200);
  5392. }
  5393. },
  5394. shutdown: function()
  5395. {
  5396. if (Firebug.Inspector)
  5397. Firebug.Inspector.destroy();
  5398. dispatch(modules, "shutdown", []);
  5399. var chromeMap = FirebugChrome.chromeMap;
  5400. for (var name in chromeMap)
  5401. {
  5402. if (chromeMap.hasOwnProperty(name))
  5403. {
  5404. chromeMap[name].destroy();
  5405. }
  5406. }
  5407. Firebug.Lite.Cache.Element.clear();
  5408. Firebug.Lite.Cache.StyleSheet.clear();
  5409. Firebug.browser = null;
  5410. Firebug.context = null;
  5411. },
  5412. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5413. // Registration
  5414. registerModule: function()
  5415. {
  5416. modules.push.apply(modules, arguments);
  5417. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule");
  5418. },
  5419. registerPanel: function()
  5420. {
  5421. panelTypes.push.apply(panelTypes, arguments);
  5422. for (var i = 0, panelType; panelType = arguments[i]; ++i)
  5423. {
  5424. panelTypeMap[panelType.prototype.name] = arguments[i];
  5425. if (panelType.prototype.parentPanel)
  5426. parentPanelMap[panelType.prototype.parentPanel] = 1;
  5427. }
  5428. if (FBTrace.DBG_INITIALIZE)
  5429. for (var i = 0; i < arguments.length; ++i)
  5430. FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name);
  5431. },
  5432. registerRep: function()
  5433. {
  5434. reps.push.apply(reps, arguments);
  5435. },
  5436. unregisterRep: function()
  5437. {
  5438. for (var i = 0; i < arguments.length; ++i)
  5439. remove(reps, arguments[i]);
  5440. },
  5441. setDefaultReps: function(funcRep, rep)
  5442. {
  5443. FBL.defaultRep = rep;
  5444. FBL.defaultFuncRep = funcRep;
  5445. },
  5446. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5447. // Reps
  5448. getRep: function(object)
  5449. {
  5450. var type = typeof object;
  5451. if (isIE && isFunction(object))
  5452. type = "function";
  5453. for (var i = 0; i < reps.length; ++i)
  5454. {
  5455. var rep = reps[i];
  5456. try
  5457. {
  5458. if (rep.supportsObject(object, type))
  5459. {
  5460. if (FBTrace.DBG_DOM)
  5461. FBTrace.sysout("getRep type: "+type+" object: "+object, rep);
  5462. return rep;
  5463. }
  5464. }
  5465. catch (exc)
  5466. {
  5467. if (FBTrace.DBG_ERRORS)
  5468. {
  5469. FBTrace.sysout("firebug.getRep FAILS: ", exc.message || exc);
  5470. FBTrace.sysout("firebug.getRep reps["+i+"/"+reps.length+"]: Rep="+reps[i].className);
  5471. // TODO: xxxpedro add trace to FBTrace logs like in Firebug
  5472. //firebug.trace();
  5473. }
  5474. }
  5475. }
  5476. return (type == 'function') ? defaultFuncRep : defaultRep;
  5477. },
  5478. getRepObject: function(node)
  5479. {
  5480. var target = null;
  5481. for (var child = node; child; child = child.parentNode)
  5482. {
  5483. if (hasClass(child, "repTarget"))
  5484. target = child;
  5485. if (child.repObject)
  5486. {
  5487. if (!target && hasClass(child, "repIgnore"))
  5488. break;
  5489. else
  5490. return child.repObject;
  5491. }
  5492. }
  5493. },
  5494. getRepNode: function(node)
  5495. {
  5496. for (var child = node; child; child = child.parentNode)
  5497. {
  5498. if (child.repObject)
  5499. return child;
  5500. }
  5501. },
  5502. getElementByRepObject: function(element, object)
  5503. {
  5504. for (var child = element.firstChild; child; child = child.nextSibling)
  5505. {
  5506. if (child.repObject == object)
  5507. return child;
  5508. }
  5509. },
  5510. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5511. // Preferences
  5512. getPref: function(name)
  5513. {
  5514. return Firebug[name];
  5515. },
  5516. setPref: function(name, value)
  5517. {
  5518. Firebug[name] = value;
  5519. this.savePrefs();
  5520. },
  5521. setPrefs: function(prefs)
  5522. {
  5523. for (var name in prefs)
  5524. {
  5525. if (prefs.hasOwnProperty(name))
  5526. Firebug[name] = prefs[name];
  5527. }
  5528. this.savePrefs();
  5529. },
  5530. restorePrefs: function()
  5531. {
  5532. var Options = Env.Options;
  5533. for (var name in Options)
  5534. {
  5535. Firebug[name] = Options[name];
  5536. }
  5537. },
  5538. loadPrefs: function(prefs)
  5539. {
  5540. this.restorePrefs();
  5541. prefs = prefs || eval("(" + readCookie("FirebugLite") + ")");
  5542. for (var name in prefs)
  5543. {
  5544. if (prefs.hasOwnProperty(name))
  5545. Firebug[name] = prefs[name];
  5546. }
  5547. },
  5548. savePrefs: function()
  5549. {
  5550. var json = ['{'], jl = 0;
  5551. var Options = Env.Options;
  5552. for (var name in Options)
  5553. {
  5554. if (Options.hasOwnProperty(name))
  5555. {
  5556. var value = Firebug[name];
  5557. json[++jl] = '"';
  5558. json[++jl] = name;
  5559. var type = typeof value;
  5560. if (type == "boolean" || type == "number")
  5561. {
  5562. json[++jl] = '":';
  5563. json[++jl] = value;
  5564. json[++jl] = ',';
  5565. }
  5566. else
  5567. {
  5568. json[++jl] = '":"';
  5569. json[++jl] = value;
  5570. json[++jl] = '",';
  5571. }
  5572. }
  5573. }
  5574. json.length = jl--;
  5575. json[++jl] = '}';
  5576. createCookie("FirebugLite", json.join(""));
  5577. },
  5578. erasePrefs: function()
  5579. {
  5580. removeCookie("FirebugLite");
  5581. }
  5582. };
  5583. Firebug.restorePrefs();
  5584. if (!Env.Options.enablePersistent ||
  5585. Env.Options.enablePersistent && Env.isChromeContext ||
  5586. Env.isDebugMode)
  5587. Env.browser.window.Firebug = FBL.Firebug;
  5588. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5589. // Other methods
  5590. FBL.cacheDocument = function cacheDocument()
  5591. {
  5592. var ElementCache = Firebug.Lite.Cache.Element;
  5593. var els = Firebug.browser.document.getElementsByTagName("*");
  5594. for (var i=0, l=els.length, el; i<l; i++)
  5595. {
  5596. el = els[i];
  5597. ElementCache(el);
  5598. }
  5599. };
  5600. // ************************************************************************************************
  5601. /**
  5602. * @class
  5603. *
  5604. * Support for listeners registration. This object also extended by Firebug.Module so,
  5605. * all modules supports listening automatically. Notice that array of listeners
  5606. * is created for each intance of a module within initialize method. Thus all derived
  5607. * module classes must ensure that Firebug.Module.initialize method is called for the
  5608. * super class.
  5609. */
  5610. Firebug.Listener = function()
  5611. {
  5612. // The array is created when the first listeners is added.
  5613. // It can't be created here since derived objects would share
  5614. // the same array.
  5615. this.fbListeners = null;
  5616. };
  5617. Firebug.Listener.prototype =
  5618. {
  5619. addListener: function(listener)
  5620. {
  5621. if (!this.fbListeners)
  5622. this.fbListeners = []; // delay the creation until the objects are created so 'this' causes new array for each module
  5623. this.fbListeners.push(listener);
  5624. },
  5625. removeListener: function(listener)
  5626. {
  5627. remove(this.fbListeners, listener); // if this.fbListeners is null, remove is being called with no add
  5628. }
  5629. };
  5630. // ************************************************************************************************
  5631. // ************************************************************************************************
  5632. // Module
  5633. /**
  5634. * @module Base class for all modules. Every derived module object must be registered using
  5635. * <code>Firebug.registerModule</code> method. There is always one instance of a module object
  5636. * per browser window.
  5637. * @extends Firebug.Listener
  5638. */
  5639. Firebug.Module = extend(new Firebug.Listener(),
  5640. /** @extend Firebug.Module */
  5641. {
  5642. /**
  5643. * Called when the window is opened.
  5644. */
  5645. initialize: function()
  5646. {
  5647. },
  5648. /**
  5649. * Called when the window is closed.
  5650. */
  5651. shutdown: function()
  5652. {
  5653. },
  5654. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5655. /**
  5656. * Called when a new context is created but before the page is loaded.
  5657. */
  5658. initContext: function(context)
  5659. {
  5660. },
  5661. /**
  5662. * Called after a context is detached to a separate window;
  5663. */
  5664. reattachContext: function(browser, context)
  5665. {
  5666. },
  5667. /**
  5668. * Called when a context is destroyed. Module may store info on persistedState for reloaded pages.
  5669. */
  5670. destroyContext: function(context, persistedState)
  5671. {
  5672. },
  5673. // Called when a FF tab is create or activated (user changes FF tab)
  5674. // Called after context is created or with context == null (to abort?)
  5675. showContext: function(browser, context)
  5676. {
  5677. },
  5678. /**
  5679. * Called after a context's page gets DOMContentLoaded
  5680. */
  5681. loadedContext: function(context)
  5682. {
  5683. },
  5684. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5685. showPanel: function(browser, panel)
  5686. {
  5687. },
  5688. showSidePanel: function(browser, panel)
  5689. {
  5690. },
  5691. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5692. updateOption: function(name, value)
  5693. {
  5694. },
  5695. getObjectByURL: function(context, url)
  5696. {
  5697. }
  5698. });
  5699. // ************************************************************************************************
  5700. // Panel
  5701. /**
  5702. * @panel Base class for all panels. Every derived panel must define a constructor and
  5703. * register with "Firebug.registerPanel" method. An instance of the panel
  5704. * object is created by the framework for each browser tab where Firebug is activated.
  5705. */
  5706. Firebug.Panel =
  5707. {
  5708. name: "HelloWorld",
  5709. title: "Hello World!",
  5710. parentPanel: null,
  5711. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5712. options: {
  5713. hasCommandLine: false,
  5714. hasStatusBar: false,
  5715. hasToolButtons: false,
  5716. // Pre-rendered panels are those included in the skin file (firebug.html)
  5717. isPreRendered: false,
  5718. innerHTMLSync: false
  5719. /*
  5720. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5721. // To be used by external extensions
  5722. panelHTML: "",
  5723. panelCSS: "",
  5724. toolButtonsHTML: ""
  5725. /**/
  5726. },
  5727. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5728. tabNode: null,
  5729. panelNode: null,
  5730. sidePanelNode: null,
  5731. statusBarNode: null,
  5732. toolButtonsNode: null,
  5733. panelBarNode: null,
  5734. sidePanelBarBoxNode: null,
  5735. sidePanelBarNode: null,
  5736. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5737. sidePanelBar: null,
  5738. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5739. searchable: false,
  5740. editable: true,
  5741. order: 2147483647,
  5742. statusSeparator: "<",
  5743. create: function(context, doc)
  5744. {
  5745. this.hasSidePanel = parentPanelMap.hasOwnProperty(this.name);
  5746. this.panelBarNode = $("fbPanelBar1");
  5747. this.sidePanelBarBoxNode = $("fbPanelBar2");
  5748. if (this.hasSidePanel)
  5749. {
  5750. this.sidePanelBar = extend({}, PanelBar);
  5751. this.sidePanelBar.create(this);
  5752. }
  5753. var options = this.options = extend(Firebug.Panel.options, this.options);
  5754. var panelId = "fb" + this.name;
  5755. if (options.isPreRendered)
  5756. {
  5757. this.panelNode = $(panelId);
  5758. this.tabNode = $(panelId + "Tab");
  5759. this.tabNode.style.display = "block";
  5760. if (options.hasToolButtons)
  5761. {
  5762. this.toolButtonsNode = $(panelId + "Buttons");
  5763. }
  5764. if (options.hasStatusBar)
  5765. {
  5766. this.statusBarBox = $("fbStatusBarBox");
  5767. this.statusBarNode = $(panelId + "StatusBar");
  5768. }
  5769. }
  5770. else
  5771. {
  5772. var containerSufix = this.parentPanel ? "2" : "1";
  5773. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5774. // Create Panel
  5775. var panelNode = this.panelNode = createElement("div", {
  5776. id: panelId,
  5777. className: "fbPanel"
  5778. });
  5779. $("fbPanel" + containerSufix).appendChild(panelNode);
  5780. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5781. // Create Panel Tab
  5782. var tabHTML = '<span class="fbTabL"></span><span class="fbTabText">' +
  5783. this.title + '</span><span class="fbTabR"></span>';
  5784. var tabNode = this.tabNode = createElement("a", {
  5785. id: panelId + "Tab",
  5786. className: "fbTab fbHover",
  5787. innerHTML: tabHTML
  5788. });
  5789. if (isIE6)
  5790. {
  5791. tabNode.href = "javascript:void(0)";
  5792. }
  5793. var panelBarNode = this.parentPanel ?
  5794. Firebug.chrome.getPanel(this.parentPanel).sidePanelBarNode :
  5795. this.panelBarNode;
  5796. panelBarNode.appendChild(tabNode);
  5797. tabNode.style.display = "block";
  5798. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5799. // create ToolButtons
  5800. if (options.hasToolButtons)
  5801. {
  5802. this.toolButtonsNode = createElement("span", {
  5803. id: panelId + "Buttons",
  5804. className: "fbToolbarButtons"
  5805. });
  5806. $("fbToolbarButtons").appendChild(this.toolButtonsNode);
  5807. }
  5808. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5809. // create StatusBar
  5810. if (options.hasStatusBar)
  5811. {
  5812. this.statusBarBox = $("fbStatusBarBox");
  5813. this.statusBarNode = createElement("span", {
  5814. id: panelId + "StatusBar",
  5815. className: "fbToolbarButtons fbStatusBar"
  5816. });
  5817. this.statusBarBox.appendChild(this.statusBarNode);
  5818. }
  5819. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5820. // create SidePanel
  5821. }
  5822. this.containerNode = this.panelNode.parentNode;
  5823. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.create", this.name);
  5824. // xxxpedro contextMenu
  5825. this.onContextMenu = bind(this.onContextMenu, this);
  5826. /*
  5827. this.context = context;
  5828. this.document = doc;
  5829. this.panelNode = doc.createElement("div");
  5830. this.panelNode.ownerPanel = this;
  5831. setClass(this.panelNode, "panelNode panelNode-"+this.name+" contextUID="+context.uid);
  5832. doc.body.appendChild(this.panelNode);
  5833. if (FBTrace.DBG_INITIALIZE)
  5834. FBTrace.sysout("firebug.initialize panelNode for "+this.name+"\n");
  5835. this.initializeNode(this.panelNode);
  5836. /**/
  5837. },
  5838. destroy: function(state) // Panel may store info on state
  5839. {
  5840. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.destroy", this.name);
  5841. if (this.hasSidePanel)
  5842. {
  5843. this.sidePanelBar.destroy();
  5844. this.sidePanelBar = null;
  5845. }
  5846. this.options = null;
  5847. this.name = null;
  5848. this.parentPanel = null;
  5849. this.tabNode = null;
  5850. this.panelNode = null;
  5851. this.containerNode = null;
  5852. this.toolButtonsNode = null;
  5853. this.statusBarBox = null;
  5854. this.statusBarNode = null;
  5855. //if (this.panelNode)
  5856. // delete this.panelNode.ownerPanel;
  5857. //this.destroyNode();
  5858. },
  5859. initialize: function()
  5860. {
  5861. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.initialize", this.name);
  5862. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5863. if (this.hasSidePanel)
  5864. {
  5865. this.sidePanelBar.initialize();
  5866. }
  5867. var options = this.options = extend(Firebug.Panel.options, this.options);
  5868. var panelId = "fb" + this.name;
  5869. this.panelNode = $(panelId);
  5870. this.tabNode = $(panelId + "Tab");
  5871. this.tabNode.style.display = "block";
  5872. if (options.hasStatusBar)
  5873. {
  5874. this.statusBarBox = $("fbStatusBarBox");
  5875. this.statusBarNode = $(panelId + "StatusBar");
  5876. }
  5877. if (options.hasToolButtons)
  5878. {
  5879. this.toolButtonsNode = $(panelId + "Buttons");
  5880. }
  5881. this.containerNode = this.panelNode.parentNode;
  5882. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5883. // restore persistent state
  5884. this.containerNode.scrollTop = this.lastScrollTop;
  5885. // xxxpedro contextMenu
  5886. addEvent(this.containerNode, "contextmenu", this.onContextMenu);
  5887. /// TODO: xxxpedro infoTip Hack
  5888. Firebug.chrome.currentPanel =
  5889. Firebug.chrome.selectedPanel && Firebug.chrome.selectedPanel.sidePanelBar ?
  5890. Firebug.chrome.selectedPanel.sidePanelBar.selectedPanel :
  5891. Firebug.chrome.selectedPanel;
  5892. Firebug.showInfoTips = true;
  5893. Firebug.InfoTip.initializeBrowser(Firebug.chrome);
  5894. },
  5895. shutdown: function()
  5896. {
  5897. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.Panel.shutdown", this.name);
  5898. /// TODO: xxxpedro infoTip Hack
  5899. Firebug.InfoTip.uninitializeBrowser(Firebug.chrome);
  5900. if (Firebug.chrome.largeCommandLineVisible)
  5901. Firebug.chrome.hideLargeCommandLine();
  5902. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5903. if (this.hasSidePanel)
  5904. {
  5905. // TODO: xxxpedro firebug1.3a6
  5906. // new PanelBar mechanism will need to call shutdown to hide the panels (so it
  5907. // doesn't appears in other panel's sidePanelBar. Therefore, we need to implement
  5908. // a "remember selected panel" feature in the sidePanelBar
  5909. //this.sidePanelBar.shutdown();
  5910. }
  5911. // store persistent state
  5912. this.lastScrollTop = this.containerNode.scrollTop;
  5913. // xxxpedro contextMenu
  5914. removeEvent(this.containerNode, "contextmenu", this.onContextMenu);
  5915. },
  5916. detach: function(oldChrome, newChrome)
  5917. {
  5918. if (oldChrome.selectedPanel.name == this.name)
  5919. this.lastScrollTop = oldChrome.selectedPanel.containerNode.scrollTop;
  5920. },
  5921. reattach: function(doc)
  5922. {
  5923. if (this.options.innerHTMLSync)
  5924. this.synchronizeUI();
  5925. },
  5926. synchronizeUI: function()
  5927. {
  5928. this.containerNode.scrollTop = this.lastScrollTop || 0;
  5929. },
  5930. show: function(state)
  5931. {
  5932. var options = this.options;
  5933. if (options.hasStatusBar)
  5934. {
  5935. this.statusBarBox.style.display = "inline";
  5936. this.statusBarNode.style.display = "inline";
  5937. }
  5938. if (options.hasToolButtons)
  5939. {
  5940. this.toolButtonsNode.style.display = "inline";
  5941. }
  5942. this.panelNode.style.display = "block";
  5943. this.visible = true;
  5944. if (!this.parentPanel)
  5945. Firebug.chrome.layout(this);
  5946. },
  5947. hide: function(state)
  5948. {
  5949. var options = this.options;
  5950. if (options.hasStatusBar)
  5951. {
  5952. this.statusBarBox.style.display = "none";
  5953. this.statusBarNode.style.display = "none";
  5954. }
  5955. if (options.hasToolButtons)
  5956. {
  5957. this.toolButtonsNode.style.display = "none";
  5958. }
  5959. this.panelNode.style.display = "none";
  5960. this.visible = false;
  5961. },
  5962. watchWindow: function(win)
  5963. {
  5964. },
  5965. unwatchWindow: function(win)
  5966. {
  5967. },
  5968. updateOption: function(name, value)
  5969. {
  5970. },
  5971. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5972. /**
  5973. * Toolbar helpers
  5974. */
  5975. showToolbarButtons: function(buttonsId, show)
  5976. {
  5977. try
  5978. {
  5979. if (!this.context.browser) // XXXjjb this is bug. Somehow the panel context is not FirebugContext.
  5980. {
  5981. if (FBTrace.DBG_ERRORS)
  5982. FBTrace.sysout("firebug.Panel showToolbarButtons this.context has no browser, this:", this);
  5983. return;
  5984. }
  5985. var buttons = this.context.browser.chrome.$(buttonsId);
  5986. if (buttons)
  5987. collapse(buttons, show ? "false" : "true");
  5988. }
  5989. catch (exc)
  5990. {
  5991. if (FBTrace.DBG_ERRORS)
  5992. {
  5993. FBTrace.dumpProperties("firebug.Panel showToolbarButtons FAILS", exc);
  5994. if (!this.context.browser)FBTrace.dumpStack("firebug.Panel showToolbarButtons no browser");
  5995. }
  5996. }
  5997. },
  5998. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  5999. /**
  6000. * Returns a number indicating the view's ability to inspect the object.
  6001. *
  6002. * Zero means not supported, and higher numbers indicate specificity.
  6003. */
  6004. supportsObject: function(object)
  6005. {
  6006. return 0;
  6007. },
  6008. hasObject: function(object) // beyond type testing, is this object selectable?
  6009. {
  6010. return false;
  6011. },
  6012. select: function(object, forceUpdate)
  6013. {
  6014. if (!object)
  6015. object = this.getDefaultSelection(this.context);
  6016. if(FBTrace.DBG_PANELS)
  6017. FBTrace.sysout("firebug.select "+this.name+" forceUpdate: "+forceUpdate+" "+object+((object==this.selection)?"==":"!=")+this.selection);
  6018. if (forceUpdate || object != this.selection)
  6019. {
  6020. this.selection = object;
  6021. this.updateSelection(object);
  6022. // TODO: xxxpedro
  6023. // XXXjoe This is kind of cheating, but, feh.
  6024. //Firebug.chrome.onPanelSelect(object, this);
  6025. //if (uiListeners.length > 0)
  6026. // dispatch(uiListeners, "onPanelSelect", [object, this]); // TODO: make Firebug.chrome a uiListener
  6027. }
  6028. },
  6029. updateSelection: function(object)
  6030. {
  6031. },
  6032. markChange: function(skipSelf)
  6033. {
  6034. if (this.dependents)
  6035. {
  6036. if (skipSelf)
  6037. {
  6038. for (var i = 0; i < this.dependents.length; ++i)
  6039. {
  6040. var panelName = this.dependents[i];
  6041. if (panelName != this.name)
  6042. this.context.invalidatePanels(panelName);
  6043. }
  6044. }
  6045. else
  6046. this.context.invalidatePanels.apply(this.context, this.dependents);
  6047. }
  6048. },
  6049. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6050. startInspecting: function()
  6051. {
  6052. },
  6053. stopInspecting: function(object, cancelled)
  6054. {
  6055. },
  6056. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6057. search: function(text, reverse)
  6058. {
  6059. },
  6060. /**
  6061. * Retrieves the search options that this modules supports.
  6062. * This is used by the search UI to present the proper options.
  6063. */
  6064. getSearchOptionsMenuItems: function()
  6065. {
  6066. return [
  6067. Firebug.Search.searchOptionMenu("search.Case Sensitive", "searchCaseSensitive")
  6068. ];
  6069. },
  6070. /**
  6071. * Navigates to the next document whose match parameter returns true.
  6072. */
  6073. navigateToNextDocument: function(match, reverse)
  6074. {
  6075. // This is an approximation of the UI that is displayed by the location
  6076. // selector. This should be close enough, although it may be better
  6077. // to simply generate the sorted list within the module, rather than
  6078. // sorting within the UI.
  6079. var self = this;
  6080. function compare(a, b) {
  6081. var locA = self.getObjectDescription(a);
  6082. var locB = self.getObjectDescription(b);
  6083. if(locA.path > locB.path)
  6084. return 1;
  6085. if(locA.path < locB.path)
  6086. return -1;
  6087. if(locA.name > locB.name)
  6088. return 1;
  6089. if(locA.name < locB.name)
  6090. return -1;
  6091. return 0;
  6092. }
  6093. var allLocs = this.getLocationList().sort(compare);
  6094. for (var curPos = 0; curPos < allLocs.length && allLocs[curPos] != this.location; curPos++);
  6095. function transformIndex(index) {
  6096. if (reverse) {
  6097. // For the reverse case we need to implement wrap around.
  6098. var intermediate = curPos - index - 1;
  6099. return (intermediate < 0 ? allLocs.length : 0) + intermediate;
  6100. } else {
  6101. return (curPos + index + 1) % allLocs.length;
  6102. }
  6103. };
  6104. for (var next = 0; next < allLocs.length - 1; next++)
  6105. {
  6106. var object = allLocs[transformIndex(next)];
  6107. if (match(object))
  6108. {
  6109. this.navigate(object);
  6110. return object;
  6111. }
  6112. }
  6113. },
  6114. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6115. // Called when "Options" clicked. Return array of
  6116. // {label: 'name', nol10n: true, type: "checkbox", checked: <value>, command:function to set <value>}
  6117. getOptionsMenuItems: function()
  6118. {
  6119. return null;
  6120. },
  6121. /*
  6122. * Called by chrome.onContextMenu to build the context menu when this panel has focus.
  6123. * See also FirebugRep for a similar function also called by onContextMenu
  6124. * Extensions may monkey patch and chain off this call
  6125. * @param object: the 'realObject', a model value, eg a DOM property
  6126. * @param target: the HTML element clicked on.
  6127. * @return an array of menu items.
  6128. */
  6129. getContextMenuItems: function(object, target)
  6130. {
  6131. return [];
  6132. },
  6133. getBreakOnMenuItems: function()
  6134. {
  6135. return [];
  6136. },
  6137. getEditor: function(target, value)
  6138. {
  6139. },
  6140. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6141. getDefaultSelection: function()
  6142. {
  6143. return null;
  6144. },
  6145. browseObject: function(object)
  6146. {
  6147. },
  6148. getPopupObject: function(target)
  6149. {
  6150. return Firebug.getRepObject(target);
  6151. },
  6152. getTooltipObject: function(target)
  6153. {
  6154. return Firebug.getRepObject(target);
  6155. },
  6156. showInfoTip: function(infoTip, x, y)
  6157. {
  6158. },
  6159. getObjectPath: function(object)
  6160. {
  6161. return null;
  6162. },
  6163. // An array of objects that can be passed to getObjectLocation.
  6164. // The list of things a panel can show, eg sourceFiles.
  6165. // Only shown if panel.location defined and supportsObject true
  6166. getLocationList: function()
  6167. {
  6168. return null;
  6169. },
  6170. getDefaultLocation: function()
  6171. {
  6172. return null;
  6173. },
  6174. getObjectLocation: function(object)
  6175. {
  6176. return "";
  6177. },
  6178. // Text for the location list menu eg script panel source file list
  6179. // return.path: group/category label, return.name: item label
  6180. getObjectDescription: function(object)
  6181. {
  6182. var url = this.getObjectLocation(object);
  6183. return FBL.splitURLBase(url);
  6184. },
  6185. /*
  6186. * UI signal that a tab needs attention, eg Script panel is currently stopped on a breakpoint
  6187. * @param: show boolean, true turns on.
  6188. */
  6189. highlight: function(show)
  6190. {
  6191. var tab = this.getTab();
  6192. if (!tab)
  6193. return;
  6194. if (show)
  6195. tab.setAttribute("highlight", "true");
  6196. else
  6197. tab.removeAttribute("highlight");
  6198. },
  6199. getTab: function()
  6200. {
  6201. var chrome = Firebug.chrome;
  6202. var tab = chrome.$("fbPanelBar2").getTab(this.name);
  6203. if (!tab)
  6204. tab = chrome.$("fbPanelBar1").getTab(this.name);
  6205. return tab;
  6206. },
  6207. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6208. // Support for Break On Next
  6209. /**
  6210. * Called by the framework when the user clicks on the Break On Next button.
  6211. * @param {Boolean} armed Set to true if the Break On Next feature is
  6212. * to be armed for action and set to false if the Break On Next should be disarmed.
  6213. * If 'armed' is true, then the next call to shouldBreakOnNext should be |true|.
  6214. */
  6215. breakOnNext: function(armed)
  6216. {
  6217. },
  6218. /**
  6219. * Called when a panel is selected/displayed. The method should return true
  6220. * if the Break On Next feature is currently armed for this panel.
  6221. */
  6222. shouldBreakOnNext: function()
  6223. {
  6224. return false;
  6225. },
  6226. /**
  6227. * Returns labels for Break On Next tooltip (one for enabled and one for disabled state).
  6228. * @param {Boolean} enabled Set to true if the Break On Next feature is
  6229. * currently activated for this panel.
  6230. */
  6231. getBreakOnNextTooltip: function(enabled)
  6232. {
  6233. return null;
  6234. },
  6235. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6236. // xxxpedro contextMenu
  6237. onContextMenu: function(event)
  6238. {
  6239. if (!this.getContextMenuItems)
  6240. return;
  6241. cancelEvent(event, true);
  6242. var target = event.target || event.srcElement;
  6243. var menu = this.getContextMenuItems(this.selection, target);
  6244. if (!menu)
  6245. return;
  6246. var contextMenu = new Menu(
  6247. {
  6248. id: "fbPanelContextMenu",
  6249. items: menu
  6250. });
  6251. contextMenu.show(event.clientX, event.clientY);
  6252. return true;
  6253. /*
  6254. // TODO: xxxpedro move code to somewhere. code to get cross-browser
  6255. // window to screen coordinates
  6256. var box = Firebug.browser.getElementPosition(Firebug.chrome.node);
  6257. var screenY = 0;
  6258. // Firefox
  6259. if (typeof window.mozInnerScreenY != "undefined")
  6260. {
  6261. screenY = window.mozInnerScreenY;
  6262. }
  6263. // Chrome
  6264. else if (typeof window.innerHeight != "undefined")
  6265. {
  6266. screenY = window.outerHeight - window.innerHeight;
  6267. }
  6268. // IE
  6269. else if (typeof window.screenTop != "undefined")
  6270. {
  6271. screenY = window.screenTop;
  6272. }
  6273. contextMenu.show(event.screenX-box.left, event.screenY-screenY-box.top);
  6274. /**/
  6275. }
  6276. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6277. };
  6278. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6279. /**
  6280. * MeasureBox
  6281. * To get pixels size.width and size.height:
  6282. * <ul><li> this.startMeasuring(view); </li>
  6283. * <li> var size = this.measureText(lineNoCharsSpacer); </li>
  6284. * <li> this.stopMeasuring(); </li>
  6285. * </ul>
  6286. *
  6287. * @namespace
  6288. */
  6289. Firebug.MeasureBox =
  6290. {
  6291. startMeasuring: function(target)
  6292. {
  6293. if (!this.measureBox)
  6294. {
  6295. this.measureBox = target.ownerDocument.createElement("span");
  6296. this.measureBox.className = "measureBox";
  6297. }
  6298. copyTextStyles(target, this.measureBox);
  6299. target.ownerDocument.body.appendChild(this.measureBox);
  6300. },
  6301. getMeasuringElement: function()
  6302. {
  6303. return this.measureBox;
  6304. },
  6305. measureText: function(value)
  6306. {
  6307. this.measureBox.innerHTML = value ? escapeForSourceLine(value) : "m";
  6308. return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1};
  6309. },
  6310. measureInputText: function(value)
  6311. {
  6312. value = value ? escapeForTextNode(value) : "m";
  6313. if (!Firebug.showTextNodesWithWhitespace)
  6314. value = value.replace(/\t/g,'mmmmmm').replace(/\ /g,'m');
  6315. this.measureBox.innerHTML = value;
  6316. return {width: this.measureBox.offsetWidth, height: this.measureBox.offsetHeight-1};
  6317. },
  6318. getBox: function(target)
  6319. {
  6320. var style = this.measureBox.ownerDocument.defaultView.getComputedStyle(this.measureBox, "");
  6321. var box = getBoxFromStyles(style, this.measureBox);
  6322. return box;
  6323. },
  6324. stopMeasuring: function()
  6325. {
  6326. this.measureBox.parentNode.removeChild(this.measureBox);
  6327. }
  6328. };
  6329. // ************************************************************************************************
  6330. if (FBL.domplate) Firebug.Rep = domplate(
  6331. {
  6332. className: "",
  6333. inspectable: true,
  6334. supportsObject: function(object, type)
  6335. {
  6336. return false;
  6337. },
  6338. inspectObject: function(object, context)
  6339. {
  6340. Firebug.chrome.select(object);
  6341. },
  6342. browseObject: function(object, context)
  6343. {
  6344. },
  6345. persistObject: function(object, context)
  6346. {
  6347. },
  6348. getRealObject: function(object, context)
  6349. {
  6350. return object;
  6351. },
  6352. getTitle: function(object)
  6353. {
  6354. var label = safeToString(object);
  6355. var re = /\[object (.*?)\]/;
  6356. var m = re.exec(label);
  6357. ///return m ? m[1] : label;
  6358. // if the label is in the "[object TYPE]" format return its type
  6359. if (m)
  6360. {
  6361. return m[1];
  6362. }
  6363. // if it is IE we need to handle some special cases
  6364. else if (
  6365. // safeToString() fails to recognize some objects in IE
  6366. isIE &&
  6367. // safeToString() returns "[object]" for some objects like window.Image
  6368. (label == "[object]" ||
  6369. // safeToString() returns undefined for some objects like window.clientInformation
  6370. typeof object == "object" && typeof label == "undefined")
  6371. )
  6372. {
  6373. return "Object";
  6374. }
  6375. else
  6376. {
  6377. return label;
  6378. }
  6379. },
  6380. getTooltip: function(object)
  6381. {
  6382. return null;
  6383. },
  6384. getContextMenuItems: function(object, target, context)
  6385. {
  6386. return [];
  6387. },
  6388. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6389. // Convenience for domplates
  6390. STR: function(name)
  6391. {
  6392. return $STR(name);
  6393. },
  6394. cropString: function(text)
  6395. {
  6396. return cropString(text);
  6397. },
  6398. cropMultipleLines: function(text, limit)
  6399. {
  6400. return cropMultipleLines(text, limit);
  6401. },
  6402. toLowerCase: function(text)
  6403. {
  6404. return text ? text.toLowerCase() : text;
  6405. },
  6406. plural: function(n)
  6407. {
  6408. return n == 1 ? "" : "s";
  6409. }
  6410. });
  6411. // ************************************************************************************************
  6412. // ************************************************************************************************
  6413. }});
  6414. /* See license.txt for terms of usage */
  6415. FBL.ns( /** @scope ns-gui */ function() { with (FBL) {
  6416. // ************************************************************************************************
  6417. // ************************************************************************************************
  6418. // Controller
  6419. /**@namespace*/
  6420. FBL.Controller = {
  6421. controllers: null,
  6422. controllerContext: null,
  6423. initialize: function(context)
  6424. {
  6425. this.controllers = [];
  6426. this.controllerContext = context || Firebug.chrome;
  6427. },
  6428. shutdown: function()
  6429. {
  6430. this.removeControllers();
  6431. //this.controllers = null;
  6432. //this.controllerContext = null;
  6433. },
  6434. addController: function()
  6435. {
  6436. for (var i=0, arg; arg=arguments[i]; i++)
  6437. {
  6438. // If the first argument is a string, make a selector query
  6439. // within the controller node context
  6440. if (typeof arg[0] == "string")
  6441. {
  6442. arg[0] = $$(arg[0], this.controllerContext);
  6443. }
  6444. // bind the handler to the proper context
  6445. var handler = arg[2];
  6446. arg[2] = bind(handler, this);
  6447. // save the original handler as an extra-argument, so we can
  6448. // look for it later, when removing a particular controller
  6449. arg[3] = handler;
  6450. this.controllers.push(arg);
  6451. addEvent.apply(this, arg);
  6452. }
  6453. },
  6454. removeController: function()
  6455. {
  6456. for (var i=0, arg; arg=arguments[i]; i++)
  6457. {
  6458. for (var j=0, c; c=this.controllers[j]; j++)
  6459. {
  6460. if (arg[0] == c[0] && arg[1] == c[1] && arg[2] == c[3])
  6461. removeEvent.apply(this, c);
  6462. }
  6463. }
  6464. },
  6465. removeControllers: function()
  6466. {
  6467. for (var i=0, c; c=this.controllers[i]; i++)
  6468. {
  6469. removeEvent.apply(this, c);
  6470. }
  6471. }
  6472. };
  6473. // ************************************************************************************************
  6474. // PanelBar
  6475. /**@namespace*/
  6476. FBL.PanelBar =
  6477. {
  6478. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6479. panelMap: null,
  6480. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6481. selectedPanel: null,
  6482. parentPanelName: null,
  6483. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6484. create: function(ownerPanel)
  6485. {
  6486. this.panelMap = {};
  6487. this.ownerPanel = ownerPanel;
  6488. if (ownerPanel)
  6489. {
  6490. ownerPanel.sidePanelBarNode = createElement("span");
  6491. ownerPanel.sidePanelBarNode.style.display = "none";
  6492. ownerPanel.sidePanelBarBoxNode.appendChild(ownerPanel.sidePanelBarNode);
  6493. }
  6494. var panels = Firebug.panelTypes;
  6495. for (var i=0, p; p=panels[i]; i++)
  6496. {
  6497. if ( // normal Panel of the Chrome's PanelBar
  6498. !ownerPanel && !p.prototype.parentPanel ||
  6499. // Child Panel of the current Panel's SidePanelBar
  6500. ownerPanel && p.prototype.parentPanel &&
  6501. ownerPanel.name == p.prototype.parentPanel)
  6502. {
  6503. this.addPanel(p.prototype.name);
  6504. }
  6505. }
  6506. },
  6507. destroy: function()
  6508. {
  6509. PanelBar.shutdown.call(this);
  6510. for (var name in this.panelMap)
  6511. {
  6512. this.removePanel(name);
  6513. var panel = this.panelMap[name];
  6514. panel.destroy();
  6515. this.panelMap[name] = null;
  6516. delete this.panelMap[name];
  6517. }
  6518. this.panelMap = null;
  6519. this.ownerPanel = null;
  6520. },
  6521. initialize: function()
  6522. {
  6523. if (this.ownerPanel)
  6524. this.ownerPanel.sidePanelBarNode.style.display = "inline";
  6525. for(var name in this.panelMap)
  6526. {
  6527. (function(self, name){
  6528. // tab click handler
  6529. var onTabClick = function onTabClick()
  6530. {
  6531. self.selectPanel(name);
  6532. return false;
  6533. };
  6534. Firebug.chrome.addController([self.panelMap[name].tabNode, "mousedown", onTabClick]);
  6535. })(this, name);
  6536. }
  6537. },
  6538. shutdown: function()
  6539. {
  6540. var selectedPanel = this.selectedPanel;
  6541. if (selectedPanel)
  6542. {
  6543. removeClass(selectedPanel.tabNode, "fbSelectedTab");
  6544. selectedPanel.hide();
  6545. selectedPanel.shutdown();
  6546. }
  6547. if (this.ownerPanel)
  6548. this.ownerPanel.sidePanelBarNode.style.display = "none";
  6549. this.selectedPanel = null;
  6550. },
  6551. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6552. addPanel: function(panelName, parentPanel)
  6553. {
  6554. var PanelType = Firebug.panelTypeMap[panelName];
  6555. var panel = this.panelMap[panelName] = new PanelType();
  6556. panel.create();
  6557. },
  6558. removePanel: function(panelName)
  6559. {
  6560. var panel = this.panelMap[panelName];
  6561. if (panel.hasOwnProperty(panelName))
  6562. panel.destroy();
  6563. },
  6564. selectPanel: function(panelName)
  6565. {
  6566. var selectedPanel = this.selectedPanel;
  6567. var panel = this.panelMap[panelName];
  6568. if (panel && selectedPanel != panel)
  6569. {
  6570. if (selectedPanel)
  6571. {
  6572. removeClass(selectedPanel.tabNode, "fbSelectedTab");
  6573. selectedPanel.shutdown();
  6574. selectedPanel.hide();
  6575. }
  6576. if (!panel.parentPanel)
  6577. FirebugChrome.selectedPanelName = panelName;
  6578. this.selectedPanel = panel;
  6579. setClass(panel.tabNode, "fbSelectedTab");
  6580. panel.show();
  6581. panel.initialize();
  6582. }
  6583. },
  6584. getPanel: function(panelName)
  6585. {
  6586. var panel = this.panelMap[panelName];
  6587. return panel;
  6588. }
  6589. };
  6590. //************************************************************************************************
  6591. // Button
  6592. /**
  6593. * options.element
  6594. * options.caption
  6595. * options.title
  6596. *
  6597. * options.owner
  6598. * options.className
  6599. * options.pressedClassName
  6600. *
  6601. * options.onPress
  6602. * options.onUnpress
  6603. * options.onClick
  6604. *
  6605. * @class
  6606. * @extends FBL.Controller
  6607. *
  6608. */
  6609. FBL.Button = function(options)
  6610. {
  6611. options = options || {};
  6612. append(this, options);
  6613. this.state = "unpressed";
  6614. this.display = "unpressed";
  6615. if (this.element)
  6616. {
  6617. this.container = this.element.parentNode;
  6618. }
  6619. else
  6620. {
  6621. this.shouldDestroy = true;
  6622. this.container = this.owner.getPanel().toolButtonsNode;
  6623. this.element = createElement("a", {
  6624. className: this.baseClassName + " " + this.className + " fbHover",
  6625. innerHTML: this.caption
  6626. });
  6627. if (this.title)
  6628. this.element.title = this.title;
  6629. this.container.appendChild(this.element);
  6630. }
  6631. };
  6632. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6633. Button.prototype = extend(Controller,
  6634. /**@extend FBL.Button.prototype*/
  6635. {
  6636. type: "normal",
  6637. caption: "caption",
  6638. title: null,
  6639. className: "", // custom class
  6640. baseClassName: "fbButton", // control class
  6641. pressedClassName: "fbBtnPressed", // control pressed class
  6642. element: null,
  6643. container: null,
  6644. owner: null,
  6645. state: null,
  6646. display: null,
  6647. destroy: function()
  6648. {
  6649. this.shutdown();
  6650. // only remove if it is a dynamically generated button (not pre-rendered)
  6651. if (this.shouldDestroy)
  6652. this.container.removeChild(this.element);
  6653. this.element = null;
  6654. this.container = null;
  6655. this.owner = null;
  6656. },
  6657. initialize: function()
  6658. {
  6659. Controller.initialize.apply(this);
  6660. var element = this.element;
  6661. this.addController([element, "mousedown", this.handlePress]);
  6662. if (this.type == "normal")
  6663. this.addController(
  6664. [element, "mouseup", this.handleUnpress],
  6665. [element, "mouseout", this.handleUnpress],
  6666. [element, "click", this.handleClick]
  6667. );
  6668. },
  6669. shutdown: function()
  6670. {
  6671. Controller.shutdown.apply(this);
  6672. },
  6673. restore: function()
  6674. {
  6675. this.changeState("unpressed");
  6676. },
  6677. changeState: function(state)
  6678. {
  6679. this.state = state;
  6680. this.changeDisplay(state);
  6681. },
  6682. changeDisplay: function(display)
  6683. {
  6684. if (display != this.display)
  6685. {
  6686. if (display == "pressed")
  6687. {
  6688. setClass(this.element, this.pressedClassName);
  6689. }
  6690. else if (display == "unpressed")
  6691. {
  6692. removeClass(this.element, this.pressedClassName);
  6693. }
  6694. this.display = display;
  6695. }
  6696. },
  6697. handlePress: function(event)
  6698. {
  6699. cancelEvent(event, true);
  6700. if (this.type == "normal")
  6701. {
  6702. this.changeDisplay("pressed");
  6703. this.beforeClick = true;
  6704. }
  6705. else if (this.type == "toggle")
  6706. {
  6707. if (this.state == "pressed")
  6708. {
  6709. this.changeState("unpressed");
  6710. if (this.onUnpress)
  6711. this.onUnpress.apply(this.owner, arguments);
  6712. }
  6713. else
  6714. {
  6715. this.changeState("pressed");
  6716. if (this.onPress)
  6717. this.onPress.apply(this.owner, arguments);
  6718. }
  6719. if (this.onClick)
  6720. this.onClick.apply(this.owner, arguments);
  6721. }
  6722. return false;
  6723. },
  6724. handleUnpress: function(event)
  6725. {
  6726. cancelEvent(event, true);
  6727. if (this.beforeClick)
  6728. this.changeDisplay("unpressed");
  6729. return false;
  6730. },
  6731. handleClick: function(event)
  6732. {
  6733. cancelEvent(event, true);
  6734. if (this.type == "normal")
  6735. {
  6736. if (this.onClick)
  6737. this.onClick.apply(this.owner);
  6738. this.changeState("unpressed");
  6739. }
  6740. this.beforeClick = false;
  6741. return false;
  6742. }
  6743. });
  6744. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6745. /**
  6746. * @class
  6747. * @extends FBL.Button
  6748. */
  6749. FBL.IconButton = function()
  6750. {
  6751. Button.apply(this, arguments);
  6752. };
  6753. IconButton.prototype = extend(Button.prototype,
  6754. /**@extend FBL.IconButton.prototype*/
  6755. {
  6756. baseClassName: "fbIconButton",
  6757. pressedClassName: "fbIconPressed"
  6758. });
  6759. //************************************************************************************************
  6760. // Menu
  6761. var menuItemProps = {"class": "$item.className", type: "$item.type", value: "$item.value",
  6762. _command: "$item.command"};
  6763. if (isIE6)
  6764. menuItemProps.href = "javascript:void(0)";
  6765. // Allow GUI to be loaded even when Domplate module is not installed.
  6766. if (FBL.domplate)
  6767. var MenuPlate = domplate(Firebug.Rep,
  6768. {
  6769. tag:
  6770. DIV({"class": "fbMenu fbShadow"},
  6771. DIV({"class": "fbMenuContent fbShadowContent"},
  6772. FOR("item", "$object.items|memberIterator",
  6773. TAG("$item.tag", {item: "$item"})
  6774. )
  6775. )
  6776. ),
  6777. itemTag:
  6778. A(menuItemProps,
  6779. "$item.label"
  6780. ),
  6781. checkBoxTag:
  6782. A(extend(menuItemProps, {checked : "$item.checked"}),
  6783. "$item.label"
  6784. ),
  6785. radioButtonTag:
  6786. A(extend(menuItemProps, {selected : "$item.selected"}),
  6787. "$item.label"
  6788. ),
  6789. groupTag:
  6790. A(extend(menuItemProps, {child: "$item.child"}),
  6791. "$item.label"
  6792. ),
  6793. shortcutTag:
  6794. A(menuItemProps,
  6795. "$item.label",
  6796. SPAN({"class": "fbMenuShortcutKey"},
  6797. "$item.key"
  6798. )
  6799. ),
  6800. separatorTag:
  6801. SPAN({"class": "fbMenuSeparator"}),
  6802. memberIterator: function(items)
  6803. {
  6804. var result = [];
  6805. for (var i=0, length=items.length; i<length; i++)
  6806. {
  6807. var item = items[i];
  6808. // separator representation
  6809. if (typeof item == "string" && item.indexOf("-") == 0)
  6810. {
  6811. result.push({tag: this.separatorTag});
  6812. continue;
  6813. }
  6814. item = extend(item, {});
  6815. item.type = item.type || "";
  6816. item.value = item.value || "";
  6817. var type = item.type;
  6818. // default item representation
  6819. item.tag = this.itemTag;
  6820. var className = item.className || "";
  6821. className += "fbMenuOption fbHover ";
  6822. // specific representations
  6823. if (type == "checkbox")
  6824. {
  6825. className += "fbMenuCheckBox ";
  6826. item.tag = this.checkBoxTag;
  6827. }
  6828. else if (type == "radiobutton")
  6829. {
  6830. className += "fbMenuRadioButton ";
  6831. item.tag = this.radioButtonTag;
  6832. }
  6833. else if (type == "group")
  6834. {
  6835. className += "fbMenuGroup ";
  6836. item.tag = this.groupTag;
  6837. }
  6838. else if (type == "shortcut")
  6839. {
  6840. className += "fbMenuShortcut ";
  6841. item.tag = this.shortcutTag;
  6842. }
  6843. if (item.checked)
  6844. className += "fbMenuChecked ";
  6845. else if (item.selected)
  6846. className += "fbMenuRadioSelected ";
  6847. if (item.disabled)
  6848. className += "fbMenuDisabled ";
  6849. item.className = className;
  6850. item.label = $STR(item.label);
  6851. result.push(item);
  6852. }
  6853. return result;
  6854. }
  6855. });
  6856. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6857. /**
  6858. * options
  6859. * options.element
  6860. * options.id
  6861. * options.items
  6862. *
  6863. * item.label
  6864. * item.className
  6865. * item.type
  6866. * item.value
  6867. * item.disabled
  6868. * item.checked
  6869. * item.selected
  6870. * item.command
  6871. * item.child
  6872. *
  6873. *
  6874. * @class
  6875. * @extends FBL.Controller
  6876. *
  6877. */
  6878. FBL.Menu = function(options)
  6879. {
  6880. // if element is not pre-rendered, we must render it now
  6881. if (!options.element)
  6882. {
  6883. if (options.getItems)
  6884. options.items = options.getItems();
  6885. options.element = MenuPlate.tag.append(
  6886. {object: options},
  6887. getElementByClass(Firebug.chrome.document, "fbBody"),
  6888. MenuPlate
  6889. );
  6890. }
  6891. // extend itself with the provided options
  6892. append(this, options);
  6893. if (typeof this.element == "string")
  6894. {
  6895. this.id = this.element;
  6896. this.element = $(this.id);
  6897. }
  6898. else if (this.id)
  6899. {
  6900. this.element.id = this.id;
  6901. }
  6902. this.element.firebugIgnore = true;
  6903. this.elementStyle = this.element.style;
  6904. this.isVisible = false;
  6905. this.handleMouseDown = bind(this.handleMouseDown, this);
  6906. this.handleMouseOver = bind(this.handleMouseOver, this);
  6907. this.handleMouseOut = bind(this.handleMouseOut, this);
  6908. this.handleWindowMouseDown = bind(this.handleWindowMouseDown, this);
  6909. };
  6910. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6911. var menuMap = {};
  6912. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  6913. Menu.prototype = extend(Controller,
  6914. /**@extend FBL.Menu.prototype*/
  6915. {
  6916. destroy: function()
  6917. {
  6918. //if (this.element) console.log("destroy", this.element.id);
  6919. this.hide();
  6920. // if it is a childMenu, remove its reference from the parentMenu
  6921. if (this.parentMenu)
  6922. this.parentMenu.childMenu = null;
  6923. // remove the element from the document
  6924. this.element.parentNode.removeChild(this.element);
  6925. // clear references
  6926. this.element = null;
  6927. this.elementStyle = null;
  6928. this.parentMenu = null;
  6929. this.parentTarget = null;
  6930. },
  6931. initialize: function()
  6932. {
  6933. Controller.initialize.call(this);
  6934. this.addController(
  6935. [this.element, "mousedown", this.handleMouseDown],
  6936. [this.element, "mouseover", this.handleMouseOver]
  6937. );
  6938. },
  6939. shutdown: function()
  6940. {
  6941. Controller.shutdown.call(this);
  6942. },
  6943. show: function(x, y)
  6944. {
  6945. this.initialize();
  6946. if (this.isVisible) return;
  6947. //console.log("show", this.element.id);
  6948. x = x || 0;
  6949. y = y || 0;
  6950. if (this.parentMenu)
  6951. {
  6952. var oldChildMenu = this.parentMenu.childMenu;
  6953. if (oldChildMenu && oldChildMenu != this)
  6954. {
  6955. oldChildMenu.destroy();
  6956. }
  6957. this.parentMenu.childMenu = this;
  6958. }
  6959. else
  6960. addEvent(Firebug.chrome.document, "mousedown", this.handleWindowMouseDown);
  6961. this.elementStyle.display = "block";
  6962. this.elementStyle.visibility = "hidden";
  6963. var size = Firebug.chrome.getSize();
  6964. x = Math.min(x, size.width - this.element.clientWidth - 10);
  6965. x = Math.max(x, 0);
  6966. y = Math.min(y, size.height - this.element.clientHeight - 10);
  6967. y = Math.max(y, 0);
  6968. this.elementStyle.left = x + "px";
  6969. this.elementStyle.top = y + "px";
  6970. this.elementStyle.visibility = "visible";
  6971. this.isVisible = true;
  6972. if (isFunction(this.onShow))
  6973. this.onShow.apply(this, arguments);
  6974. },
  6975. hide: function()
  6976. {
  6977. this.clearHideTimeout();
  6978. this.clearShowChildTimeout();
  6979. if (!this.isVisible) return;
  6980. //console.log("hide", this.element.id);
  6981. this.elementStyle.display = "none";
  6982. if(this.childMenu)
  6983. {
  6984. this.childMenu.destroy();
  6985. this.childMenu = null;
  6986. }
  6987. if(this.parentTarget)
  6988. removeClass(this.parentTarget, "fbMenuGroupSelected");
  6989. this.isVisible = false;
  6990. this.shutdown();
  6991. if (isFunction(this.onHide))
  6992. this.onHide.apply(this, arguments);
  6993. },
  6994. showChildMenu: function(target)
  6995. {
  6996. var id = target.getAttribute("child");
  6997. var parent = this;
  6998. var target = target;
  6999. this.showChildTimeout = Firebug.chrome.window.setTimeout(function(){
  7000. //if (!parent.isVisible) return;
  7001. var box = Firebug.chrome.getElementBox(target);
  7002. var childMenuObject = menuMap.hasOwnProperty(id) ?
  7003. menuMap[id] : {element: $(id)};
  7004. var childMenu = new Menu(extend(childMenuObject,
  7005. {
  7006. parentMenu: parent,
  7007. parentTarget: target
  7008. }));
  7009. var offsetLeft = isIE6 ? -1 : -6; // IE6 problem with fixed position
  7010. childMenu.show(box.left + box.width + offsetLeft, box.top -6);
  7011. setClass(target, "fbMenuGroupSelected");
  7012. },350);
  7013. },
  7014. clearHideTimeout: function()
  7015. {
  7016. if (this.hideTimeout)
  7017. {
  7018. Firebug.chrome.window.clearTimeout(this.hideTimeout);
  7019. delete this.hideTimeout;
  7020. }
  7021. },
  7022. clearShowChildTimeout: function()
  7023. {
  7024. if(this.showChildTimeout)
  7025. {
  7026. Firebug.chrome.window.clearTimeout(this.showChildTimeout);
  7027. this.showChildTimeout = null;
  7028. }
  7029. },
  7030. handleMouseDown: function(event)
  7031. {
  7032. cancelEvent(event, true);
  7033. var topParent = this;
  7034. while (topParent.parentMenu)
  7035. topParent = topParent.parentMenu;
  7036. var target = event.target || event.srcElement;
  7037. target = getAncestorByClass(target, "fbMenuOption");
  7038. if(!target || hasClass(target, "fbMenuGroup"))
  7039. return false;
  7040. if (target && !hasClass(target, "fbMenuDisabled"))
  7041. {
  7042. var type = target.getAttribute("type");
  7043. if (type == "checkbox")
  7044. {
  7045. var checked = target.getAttribute("checked");
  7046. var value = target.getAttribute("value");
  7047. var wasChecked = hasClass(target, "fbMenuChecked");
  7048. if (wasChecked)
  7049. {
  7050. removeClass(target, "fbMenuChecked");
  7051. target.setAttribute("checked", "");
  7052. }
  7053. else
  7054. {
  7055. setClass(target, "fbMenuChecked");
  7056. target.setAttribute("checked", "true");
  7057. }
  7058. if (isFunction(this.onCheck))
  7059. this.onCheck.call(this, target, value, !wasChecked)
  7060. }
  7061. if (type == "radiobutton")
  7062. {
  7063. var selectedRadios = getElementsByClass(target.parentNode, "fbMenuRadioSelected");
  7064. var group = target.getAttribute("group");
  7065. for (var i = 0, length = selectedRadios.length; i < length; i++)
  7066. {
  7067. radio = selectedRadios[i];
  7068. if (radio.getAttribute("group") == group)
  7069. {
  7070. removeClass(radio, "fbMenuRadioSelected");
  7071. radio.setAttribute("selected", "");
  7072. }
  7073. }
  7074. setClass(target, "fbMenuRadioSelected");
  7075. target.setAttribute("selected", "true");
  7076. }
  7077. var handler = null;
  7078. // target.command can be a function or a string.
  7079. var cmd = target.command;
  7080. // If it is a function it will be used as the handler
  7081. if (isFunction(cmd))
  7082. handler = cmd;
  7083. // If it is a string it the property of the current menu object
  7084. // will be used as the handler
  7085. else if (typeof cmd == "string")
  7086. handler = this[cmd];
  7087. var closeMenu = true;
  7088. if (handler)
  7089. closeMenu = handler.call(this, target) !== false;
  7090. if (closeMenu)
  7091. topParent.hide();
  7092. }
  7093. return false;
  7094. },
  7095. handleWindowMouseDown: function(event)
  7096. {
  7097. //console.log("handleWindowMouseDown");
  7098. var target = event.target || event.srcElement;
  7099. target = getAncestorByClass(target, "fbMenu");
  7100. if (!target)
  7101. {
  7102. removeEvent(Firebug.chrome.document, "mousedown", this.handleWindowMouseDown);
  7103. this.hide();
  7104. }
  7105. },
  7106. handleMouseOver: function(event)
  7107. {
  7108. //console.log("handleMouseOver", this.element.id);
  7109. this.clearHideTimeout();
  7110. this.clearShowChildTimeout();
  7111. var target = event.target || event.srcElement;
  7112. target = getAncestorByClass(target, "fbMenuOption");
  7113. if(!target)
  7114. return;
  7115. var childMenu = this.childMenu;
  7116. if(childMenu)
  7117. {
  7118. removeClass(childMenu.parentTarget, "fbMenuGroupSelected");
  7119. if (childMenu.parentTarget != target && childMenu.isVisible)
  7120. {
  7121. childMenu.clearHideTimeout();
  7122. childMenu.hideTimeout = Firebug.chrome.window.setTimeout(function(){
  7123. childMenu.destroy();
  7124. },300);
  7125. }
  7126. }
  7127. if(hasClass(target, "fbMenuGroup"))
  7128. {
  7129. this.showChildMenu(target);
  7130. }
  7131. }
  7132. });
  7133. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7134. append(Menu,
  7135. /**@extend FBL.Menu*/
  7136. {
  7137. register: function(object)
  7138. {
  7139. menuMap[object.id] = object;
  7140. },
  7141. check: function(element)
  7142. {
  7143. setClass(element, "fbMenuChecked");
  7144. element.setAttribute("checked", "true");
  7145. },
  7146. uncheck: function(element)
  7147. {
  7148. removeClass(element, "fbMenuChecked");
  7149. element.setAttribute("checked", "");
  7150. },
  7151. disable: function(element)
  7152. {
  7153. setClass(element, "fbMenuDisabled");
  7154. },
  7155. enable: function(element)
  7156. {
  7157. removeClass(element, "fbMenuDisabled");
  7158. }
  7159. });
  7160. //************************************************************************************************
  7161. // Status Bar
  7162. /**@class*/
  7163. function StatusBar(){};
  7164. StatusBar.prototype = extend(Controller, {
  7165. });
  7166. // ************************************************************************************************
  7167. // ************************************************************************************************
  7168. }});
  7169. /* See license.txt for terms of usage */
  7170. FBL.ns( /**@scope ns-context*/ function() { with (FBL) {
  7171. // ************************************************************************************************
  7172. // ************************************************************************************************
  7173. // Globals
  7174. var refreshDelay = 300;
  7175. // Opera and some versions of webkit returns the wrong value of document.elementFromPoint()
  7176. // function, without taking into account the scroll position. Safari 4 (webkit/531.21.8)
  7177. // still have this issue. Google Chrome 4 (webkit/532.5) does not. So, we're assuming this
  7178. // issue was fixed in the 532 version
  7179. var shouldFixElementFromPoint = isOpera || isSafari && browserVersion < "532";
  7180. var evalError = "___firebug_evaluation_error___";
  7181. var pixelsPerInch;
  7182. var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
  7183. var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";
  7184. // ************************************************************************************************
  7185. // Context
  7186. /** @class */
  7187. FBL.Context = function(win)
  7188. {
  7189. this.window = win.window;
  7190. this.document = win.document;
  7191. this.browser = Env.browser;
  7192. // Some windows in IE, like iframe, doesn't have the eval() method
  7193. if (isIE && !this.window.eval)
  7194. {
  7195. // But after executing the following line the method magically appears!
  7196. this.window.execScript("null");
  7197. // Just to make sure the "magic" really happened
  7198. if (!this.window.eval)
  7199. throw new Error("Firebug Error: eval() method not found in this window");
  7200. }
  7201. // Create a new "black-box" eval() method that runs in the global namespace
  7202. // of the context window, without exposing the local variables declared
  7203. // by the function that calls it
  7204. this.eval = this.window.eval("new Function('" +
  7205. "try{ return window.eval.apply(window,arguments) }catch(E){ E."+evalError+"=true; return E }" +
  7206. "')");
  7207. };
  7208. FBL.Context.prototype =
  7209. {
  7210. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7211. // partial-port of Firebug tabContext.js
  7212. browser: null,
  7213. loaded: true,
  7214. setTimeout: function(fn, delay)
  7215. {
  7216. var win = this.window;
  7217. if (win.setTimeout == this.setTimeout)
  7218. throw new Error("setTimeout recursion");
  7219. var timeout = win.setTimeout.apply ? // IE doesn't have apply method on setTimeout
  7220. win.setTimeout.apply(win, arguments) :
  7221. win.setTimeout(fn, delay);
  7222. if (!this.timeouts)
  7223. this.timeouts = {};
  7224. this.timeouts[timeout] = 1;
  7225. return timeout;
  7226. },
  7227. clearTimeout: function(timeout)
  7228. {
  7229. clearTimeout(timeout);
  7230. if (this.timeouts)
  7231. delete this.timeouts[timeout];
  7232. },
  7233. setInterval: function(fn, delay)
  7234. {
  7235. var win = this.window;
  7236. var timeout = win.setInterval.apply ? // IE doesn't have apply method on setTimeout
  7237. win.setInterval.apply(win, arguments) :
  7238. win.setInterval(fn, delay);
  7239. if (!this.intervals)
  7240. this.intervals = {};
  7241. this.intervals[timeout] = 1;
  7242. return timeout;
  7243. },
  7244. clearInterval: function(timeout)
  7245. {
  7246. clearInterval(timeout);
  7247. if (this.intervals)
  7248. delete this.intervals[timeout];
  7249. },
  7250. invalidatePanels: function()
  7251. {
  7252. if (!this.invalidPanels)
  7253. this.invalidPanels = {};
  7254. for (var i = 0; i < arguments.length; ++i)
  7255. {
  7256. var panelName = arguments[i];
  7257. // avoid error. need to create a better getPanel() function as explained below
  7258. if (!Firebug.chrome || !Firebug.chrome.selectedPanel)
  7259. return;
  7260. //var panel = this.getPanel(panelName, true);
  7261. //TODO: xxxpedro context how to get all panels using a single function?
  7262. // the current workaround to make the invalidation works is invalidating
  7263. // only sidePanels. There's also a problem with panel name (LowerCase in Firebug Lite)
  7264. var panel = Firebug.chrome.selectedPanel.sidePanelBar ?
  7265. Firebug.chrome.selectedPanel.sidePanelBar.getPanel(panelName, true) :
  7266. null;
  7267. if (panel && !panel.noRefresh)
  7268. this.invalidPanels[panelName] = 1;
  7269. }
  7270. if (this.refreshTimeout)
  7271. {
  7272. this.clearTimeout(this.refreshTimeout);
  7273. delete this.refreshTimeout;
  7274. }
  7275. this.refreshTimeout = this.setTimeout(bindFixed(function()
  7276. {
  7277. var invalids = [];
  7278. for (var panelName in this.invalidPanels)
  7279. {
  7280. //var panel = this.getPanel(panelName, true);
  7281. //TODO: xxxpedro context how to get all panels using a single function?
  7282. // the current workaround to make the invalidation works is invalidating
  7283. // only sidePanels. There's also a problem with panel name (LowerCase in Firebug Lite)
  7284. var panel = Firebug.chrome.selectedPanel.sidePanelBar ?
  7285. Firebug.chrome.selectedPanel.sidePanelBar.getPanel(panelName, true) :
  7286. null;
  7287. if (panel)
  7288. {
  7289. if (panel.visible && !panel.editing)
  7290. panel.refresh();
  7291. else
  7292. panel.needsRefresh = true;
  7293. // If the panel is being edited, we'll keep trying to
  7294. // refresh it until editing is done
  7295. if (panel.editing)
  7296. invalids.push(panelName);
  7297. }
  7298. }
  7299. delete this.invalidPanels;
  7300. delete this.refreshTimeout;
  7301. // Keep looping until every tab is valid
  7302. if (invalids.length)
  7303. this.invalidatePanels.apply(this, invalids);
  7304. }, this), refreshDelay);
  7305. },
  7306. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7307. // Evalutation Method
  7308. /**
  7309. * Evaluates an expression in the current context window.
  7310. *
  7311. * @param {String} expr expression to be evaluated
  7312. *
  7313. * @param {String} context string indicating the global location
  7314. * of the object that will be used as the
  7315. * context. The context is referred in
  7316. * the expression as the "this" keyword.
  7317. * If no context is informed, the "window"
  7318. * context is used.
  7319. *
  7320. * @param {String} api string indicating the global location
  7321. * of the object that will be used as the
  7322. * api of the evaluation.
  7323. *
  7324. * @param {Function} errorHandler(message) error handler to be called
  7325. * if the evaluation fails.
  7326. */
  7327. evaluate: function(expr, context, api, errorHandler)
  7328. {
  7329. // Need to remove line breaks otherwise only the first line will be executed
  7330. expr = stripNewLines(expr);
  7331. // the default context is the "window" object. It can be any string that represents
  7332. // a global accessible element as: "my.namespaced.object"
  7333. context = context || "window";
  7334. var cmd,
  7335. result;
  7336. // if the context is the "window" object, we don't need a closure
  7337. if (context == "window")
  7338. {
  7339. // try first the expression wrapped in parenthesis (so we can capture
  7340. // object literal expressions like "{}" and "{some:1,props:2}")
  7341. cmd = api ?
  7342. "with("+api+"){ ("+expr+") }" :
  7343. "(" + expr + ")";
  7344. result = this.eval(cmd);
  7345. // if it results in error, then try it without parenthesis
  7346. if (result && result[evalError])
  7347. {
  7348. cmd = api ?
  7349. "with("+api+"){ "+expr+" }" :
  7350. expr;
  7351. result = this.eval(cmd);
  7352. }
  7353. }
  7354. else
  7355. {
  7356. // try to execute the command using a "return" statement in the evaluation closure.
  7357. cmd = api ?
  7358. // with API and context, trying to get the return value
  7359. "(function(arguments){ with(" + api + "){ return (" +
  7360. expr +
  7361. ") } }).call(" + context + ",undefined)"
  7362. :
  7363. // with context only, trying to get the return value
  7364. "(function(arguments){ return (" +
  7365. expr +
  7366. ") }).call(" +context + ",undefined)";
  7367. result = this.eval(cmd);
  7368. // if it results in error, then try it without the "return" statement
  7369. if (result && result[evalError])
  7370. {
  7371. cmd = api ?
  7372. // with API and context, no return value
  7373. "(function(arguments){ with(" + api + "){ " +
  7374. expr +
  7375. " } }).call(" + context + ",undefined)"
  7376. :
  7377. // with context only, no return value
  7378. "(function(arguments){ " +
  7379. expr +
  7380. " }).call(" + context + ",undefined)";
  7381. result = this.eval(cmd);
  7382. }
  7383. }
  7384. if (result && result[evalError])
  7385. {
  7386. var msg = result.name ? (result.name + ": ") : "";
  7387. msg += result.message || result;
  7388. if (errorHandler)
  7389. result = errorHandler(msg)
  7390. else
  7391. result = msg;
  7392. }
  7393. return result;
  7394. },
  7395. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7396. // Window Methods
  7397. getWindowSize: function()
  7398. {
  7399. var width=0, height=0, el;
  7400. if (typeof this.window.innerWidth == "number")
  7401. {
  7402. width = this.window.innerWidth;
  7403. height = this.window.innerHeight;
  7404. }
  7405. else if ((el=this.document.documentElement) && (el.clientHeight || el.clientWidth))
  7406. {
  7407. width = el.clientWidth;
  7408. height = el.clientHeight;
  7409. }
  7410. else if ((el=this.document.body) && (el.clientHeight || el.clientWidth))
  7411. {
  7412. width = el.clientWidth;
  7413. height = el.clientHeight;
  7414. }
  7415. return {width: width, height: height};
  7416. },
  7417. getWindowScrollSize: function()
  7418. {
  7419. var width=0, height=0, el;
  7420. // first try the document.documentElement scroll size
  7421. if (!isIEQuiksMode && (el=this.document.documentElement) &&
  7422. (el.scrollHeight || el.scrollWidth))
  7423. {
  7424. width = el.scrollWidth;
  7425. height = el.scrollHeight;
  7426. }
  7427. // then we need to check if document.body has a bigger scroll size value
  7428. // because sometimes depending on the browser and the page, the document.body
  7429. // scroll size returns a smaller (and wrong) measure
  7430. if ((el=this.document.body) && (el.scrollHeight || el.scrollWidth) &&
  7431. (el.scrollWidth > width || el.scrollHeight > height))
  7432. {
  7433. width = el.scrollWidth;
  7434. height = el.scrollHeight;
  7435. }
  7436. return {width: width, height: height};
  7437. },
  7438. getWindowScrollPosition: function()
  7439. {
  7440. var top=0, left=0, el;
  7441. if(typeof this.window.pageYOffset == "number")
  7442. {
  7443. top = this.window.pageYOffset;
  7444. left = this.window.pageXOffset;
  7445. }
  7446. else if((el=this.document.body) && (el.scrollTop || el.scrollLeft))
  7447. {
  7448. top = el.scrollTop;
  7449. left = el.scrollLeft;
  7450. }
  7451. else if((el=this.document.documentElement) && (el.scrollTop || el.scrollLeft))
  7452. {
  7453. top = el.scrollTop;
  7454. left = el.scrollLeft;
  7455. }
  7456. return {top:top, left:left};
  7457. },
  7458. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7459. // Element Methods
  7460. getElementFromPoint: function(x, y)
  7461. {
  7462. if (shouldFixElementFromPoint)
  7463. {
  7464. var scroll = this.getWindowScrollPosition();
  7465. return this.document.elementFromPoint(x + scroll.left, y + scroll.top);
  7466. }
  7467. else
  7468. return this.document.elementFromPoint(x, y);
  7469. },
  7470. getElementPosition: function(el)
  7471. {
  7472. var left = 0
  7473. var top = 0;
  7474. do
  7475. {
  7476. left += el.offsetLeft;
  7477. top += el.offsetTop;
  7478. }
  7479. while (el = el.offsetParent);
  7480. return {left:left, top:top};
  7481. },
  7482. getElementBox: function(el)
  7483. {
  7484. var result = {};
  7485. if (el.getBoundingClientRect)
  7486. {
  7487. var rect = el.getBoundingClientRect();
  7488. // fix IE problem with offset when not in fullscreen mode
  7489. var offset = isIE ? this.document.body.clientTop || this.document.documentElement.clientTop: 0;
  7490. var scroll = this.getWindowScrollPosition();
  7491. result.top = Math.round(rect.top - offset + scroll.top);
  7492. result.left = Math.round(rect.left - offset + scroll.left);
  7493. result.height = Math.round(rect.bottom - rect.top);
  7494. result.width = Math.round(rect.right - rect.left);
  7495. }
  7496. else
  7497. {
  7498. var position = this.getElementPosition(el);
  7499. result.top = position.top;
  7500. result.left = position.left;
  7501. result.height = el.offsetHeight;
  7502. result.width = el.offsetWidth;
  7503. }
  7504. return result;
  7505. },
  7506. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7507. // Measurement Methods
  7508. getMeasurement: function(el, name)
  7509. {
  7510. var result = {value: 0, unit: "px"};
  7511. var cssValue = this.getStyle(el, name);
  7512. if (!cssValue) return result;
  7513. if (cssValue.toLowerCase() == "auto") return result;
  7514. var reMeasure = /(\d+\.?\d*)(.*)/;
  7515. var m = cssValue.match(reMeasure);
  7516. if (m)
  7517. {
  7518. result.value = m[1]-0;
  7519. result.unit = m[2].toLowerCase();
  7520. }
  7521. return result;
  7522. },
  7523. getMeasurementInPixels: function(el, name)
  7524. {
  7525. if (!el) return null;
  7526. var m = this.getMeasurement(el, name);
  7527. var value = m.value;
  7528. var unit = m.unit;
  7529. if (unit == "px")
  7530. return value;
  7531. else if (unit == "pt")
  7532. return this.pointsToPixels(name, value);
  7533. if (unit == "em")
  7534. return this.emToPixels(el, value);
  7535. else if (unit == "%")
  7536. return this.percentToPixels(el, value);
  7537. },
  7538. getMeasurementBox1: function(el, name)
  7539. {
  7540. var sufixes = ["Top", "Left", "Bottom", "Right"];
  7541. var result = [];
  7542. for(var i=0, sufix; sufix=sufixes[i]; i++)
  7543. result[i] = Math.round(this.getMeasurementInPixels(el, name + sufix));
  7544. return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
  7545. },
  7546. getMeasurementBox: function(el, name)
  7547. {
  7548. var result = [];
  7549. var sufixes = name == "border" ?
  7550. ["TopWidth", "LeftWidth", "BottomWidth", "RightWidth"] :
  7551. ["Top", "Left", "Bottom", "Right"];
  7552. if (isIE)
  7553. {
  7554. var propName, cssValue;
  7555. var autoMargin = null;
  7556. for(var i=0, sufix; sufix=sufixes[i]; i++)
  7557. {
  7558. propName = name + sufix;
  7559. cssValue = el.currentStyle[propName] || el.style[propName];
  7560. if (cssValue == "auto")
  7561. {
  7562. if (!autoMargin)
  7563. autoMargin = this.getCSSAutoMarginBox(el);
  7564. result[i] = autoMargin[sufix.toLowerCase()];
  7565. }
  7566. else
  7567. result[i] = this.getMeasurementInPixels(el, propName);
  7568. }
  7569. }
  7570. else
  7571. {
  7572. for(var i=0, sufix; sufix=sufixes[i]; i++)
  7573. result[i] = this.getMeasurementInPixels(el, name + sufix);
  7574. }
  7575. return {top:result[0], left:result[1], bottom:result[2], right:result[3]};
  7576. },
  7577. getCSSAutoMarginBox: function(el)
  7578. {
  7579. if (isIE && " meta title input script link a ".indexOf(" "+el.nodeName.toLowerCase()+" ") != -1)
  7580. return {top:0, left:0, bottom:0, right:0};
  7581. /**/
  7582. if (isIE && " h1 h2 h3 h4 h5 h6 h7 ul p ".indexOf(" "+el.nodeName.toLowerCase()+" ") == -1)
  7583. return {top:0, left:0, bottom:0, right:0};
  7584. /**/
  7585. var offsetTop = 0;
  7586. if (false && isIEStantandMode)
  7587. {
  7588. var scrollSize = Firebug.browser.getWindowScrollSize();
  7589. offsetTop = scrollSize.height;
  7590. }
  7591. var box = this.document.createElement("div");
  7592. //box.style.cssText = "margin:0; padding:1px; border: 0; position:static; overflow:hidden; visibility: hidden;";
  7593. box.style.cssText = "margin:0; padding:1px; border: 0; visibility: hidden;";
  7594. var clone = el.cloneNode(false);
  7595. var text = this.document.createTextNode("&nbsp;");
  7596. clone.appendChild(text);
  7597. box.appendChild(clone);
  7598. this.document.body.appendChild(box);
  7599. var marginTop = clone.offsetTop - box.offsetTop - 1;
  7600. var marginBottom = box.offsetHeight - clone.offsetHeight - 2 - marginTop;
  7601. var marginLeft = clone.offsetLeft - box.offsetLeft - 1;
  7602. var marginRight = box.offsetWidth - clone.offsetWidth - 2 - marginLeft;
  7603. this.document.body.removeChild(box);
  7604. return {top:marginTop+offsetTop, left:marginLeft, bottom:marginBottom-offsetTop, right:marginRight};
  7605. },
  7606. getFontSizeInPixels: function(el)
  7607. {
  7608. var size = this.getMeasurement(el, "fontSize");
  7609. if (size.unit == "px") return size.value;
  7610. // get font size, the dirty way
  7611. var computeDirtyFontSize = function(el, calibration)
  7612. {
  7613. var div = this.document.createElement("div");
  7614. var divStyle = offscreenStyle;
  7615. if (calibration)
  7616. divStyle += " font-size:"+calibration+"px;";
  7617. div.style.cssText = divStyle;
  7618. div.innerHTML = "A";
  7619. el.appendChild(div);
  7620. var value = div.offsetHeight;
  7621. el.removeChild(div);
  7622. return value;
  7623. }
  7624. /*
  7625. var calibrationBase = 200;
  7626. var calibrationValue = computeDirtyFontSize(el, calibrationBase);
  7627. var rate = calibrationBase / calibrationValue;
  7628. /**/
  7629. // the "dirty technique" fails in some environments, so we're using a static value
  7630. // based in some tests.
  7631. var rate = 200 / 225;
  7632. var value = computeDirtyFontSize(el);
  7633. return value * rate;
  7634. },
  7635. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7636. // Unit Funtions
  7637. pointsToPixels: function(name, value, returnFloat)
  7638. {
  7639. var axis = /Top$|Bottom$/.test(name) ? "y" : "x";
  7640. var result = value * pixelsPerInch[axis] / 72;
  7641. return returnFloat ? result : Math.round(result);
  7642. },
  7643. emToPixels: function(el, value)
  7644. {
  7645. if (!el) return null;
  7646. var fontSize = this.getFontSizeInPixels(el);
  7647. return Math.round(value * fontSize);
  7648. },
  7649. exToPixels: function(el, value)
  7650. {
  7651. if (!el) return null;
  7652. // get ex value, the dirty way
  7653. var div = this.document.createElement("div");
  7654. div.style.cssText = offscreenStyle + "width:"+value + "ex;";
  7655. el.appendChild(div);
  7656. var value = div.offsetWidth;
  7657. el.removeChild(div);
  7658. return value;
  7659. },
  7660. percentToPixels: function(el, value)
  7661. {
  7662. if (!el) return null;
  7663. // get % value, the dirty way
  7664. var div = this.document.createElement("div");
  7665. div.style.cssText = offscreenStyle + "width:"+value + "%;";
  7666. el.appendChild(div);
  7667. var value = div.offsetWidth;
  7668. el.removeChild(div);
  7669. return value;
  7670. },
  7671. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7672. getStyle: isIE ? function(el, name)
  7673. {
  7674. return el.currentStyle[name] || el.style[name] || undefined;
  7675. }
  7676. : function(el, name)
  7677. {
  7678. return this.document.defaultView.getComputedStyle(el,null)[name]
  7679. || el.style[name] || undefined;
  7680. }
  7681. };
  7682. // ************************************************************************************************
  7683. }});
  7684. /* See license.txt for terms of usage */
  7685. FBL.ns( /**@scope ns-chrome*/ function() { with (FBL) {
  7686. // ************************************************************************************************
  7687. // ************************************************************************************************
  7688. // Globals
  7689. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7690. // Window Options
  7691. var WindowDefaultOptions =
  7692. {
  7693. type: "frame",
  7694. id: "FirebugUI",
  7695. height: 250
  7696. },
  7697. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7698. // Instantiated objects
  7699. commandLine,
  7700. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7701. // Interface Elements Cache
  7702. fbTop,
  7703. fbContent,
  7704. fbContentStyle,
  7705. fbBottom,
  7706. fbBtnInspect,
  7707. fbToolbar,
  7708. fbPanelBox1,
  7709. fbPanelBox1Style,
  7710. fbPanelBox2,
  7711. fbPanelBox2Style,
  7712. fbPanelBar2Box,
  7713. fbPanelBar2BoxStyle,
  7714. fbHSplitter,
  7715. fbVSplitter,
  7716. fbVSplitterStyle,
  7717. fbPanel1,
  7718. fbPanel1Style,
  7719. fbPanel2,
  7720. fbPanel2Style,
  7721. fbConsole,
  7722. fbConsoleStyle,
  7723. fbHTML,
  7724. fbCommandLine,
  7725. fbLargeCommandLine,
  7726. fbLargeCommandButtons,
  7727. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7728. // Cached size values
  7729. topHeight,
  7730. topPartialHeight,
  7731. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7732. chromeRedrawSkipRate = isIE ? 75 : isOpera ? 80 : 75,
  7733. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7734. lastSelectedPanelName,
  7735. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7736. focusCommandLineState = 0,
  7737. lastFocusedPanelName,
  7738. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7739. lastHSplitterMouseMove = 0,
  7740. onHSplitterMouseMoveBuffer = null,
  7741. onHSplitterMouseMoveTimer = null,
  7742. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7743. lastVSplitterMouseMove = 0;
  7744. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7745. // ************************************************************************************************
  7746. // FirebugChrome
  7747. /**@namespace*/
  7748. FBL.FirebugChrome =
  7749. {
  7750. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7751. isOpen: false,
  7752. height: 250,
  7753. sidePanelWidth: 350,
  7754. selectedPanelName: "Console",
  7755. selectedHTMLElementId: null,
  7756. chromeMap: {},
  7757. htmlSelectionStack: [],
  7758. consoleMessageQueue: [],
  7759. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7760. create: function()
  7761. {
  7762. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.create", "creating chrome window");
  7763. createChromeWindow();
  7764. },
  7765. initialize: function()
  7766. {
  7767. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("FirebugChrome.initialize", "initializing chrome window");
  7768. if (Env.chrome.type == "frame" || Env.chrome.type == "div")
  7769. ChromeMini.create(Env.chrome);
  7770. var chrome = Firebug.chrome = new Chrome(Env.chrome);
  7771. FirebugChrome.chromeMap[chrome.type] = chrome;
  7772. addGlobalEvent("keydown", onGlobalKeyDown);
  7773. if (Env.Options.enablePersistent && chrome.type == "popup")
  7774. {
  7775. // TODO: xxxpedro persist - revise chrome synchronization when in persistent mode
  7776. var frame = FirebugChrome.chromeMap.frame;
  7777. if (frame)
  7778. frame.close();
  7779. //chrome.reattach(frame, chrome);
  7780. //TODO: xxxpedro persist synchronize?
  7781. chrome.initialize();
  7782. }
  7783. },
  7784. clone: function(FBChrome)
  7785. {
  7786. for (var name in FBChrome)
  7787. {
  7788. var prop = FBChrome[name];
  7789. if (FBChrome.hasOwnProperty(name) && !isFunction(prop))
  7790. {
  7791. this[name] = prop;
  7792. }
  7793. }
  7794. }
  7795. };
  7796. // ************************************************************************************************
  7797. // Chrome Window Creation
  7798. var createChromeWindow = function(options)
  7799. {
  7800. options = extend(WindowDefaultOptions, options || {});
  7801. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7802. // Locals
  7803. var chrome = {},
  7804. context = options.context || Env.browser,
  7805. type = chrome.type = Env.Options.enablePersistent ?
  7806. "popup" :
  7807. options.type,
  7808. isChromeFrame = type == "frame",
  7809. useLocalSkin = Env.useLocalSkin,
  7810. url = useLocalSkin ?
  7811. Env.Location.skin :
  7812. "about:blank",
  7813. // document.body not available in XML+XSL documents in Firefox
  7814. body = context.document.getElementsByTagName("body")[0],
  7815. formatNode = function(node)
  7816. {
  7817. if (!Env.isDebugMode)
  7818. {
  7819. node.firebugIgnore = true;
  7820. }
  7821. node.style.border = "0";
  7822. node.style.visibility = "hidden";
  7823. node.style.zIndex = "2147483647"; // MAX z-index = 2147483647
  7824. node.style.position = noFixedPosition ? "absolute" : "fixed";
  7825. node.style.width = "100%"; // "102%"; IE auto margin bug
  7826. node.style.left = "0";
  7827. node.style.bottom = noFixedPosition ? "-1px" : "0";
  7828. node.style.height = options.height + "px";
  7829. // avoid flickering during chrome rendering
  7830. if (isFirefox)
  7831. node.style.display = "none";
  7832. },
  7833. createChromeDiv = function()
  7834. {
  7835. //Firebug.Console.warn("Firebug Lite GUI is working in 'windowless mode'. It may behave slower and receive interferences from the page in which it is installed.");
  7836. var node = chrome.node = createGlobalElement("div"),
  7837. style = createGlobalElement("style"),
  7838. css = FirebugChrome.Skin.CSS
  7839. /*
  7840. .replace(/;/g, " !important;")
  7841. .replace(/!important\s!important/g, "!important")
  7842. .replace(/display\s*:\s*(\w+)\s*!important;/g, "display:$1;")*/,
  7843. // reset some styles to minimize interference from the main page's style
  7844. rules = ".fbBody *{margin:0;padding:0;font-size:11px;line-height:13px;color:inherit;}" +
  7845. // load the chrome styles
  7846. css +
  7847. // adjust some remaining styles
  7848. ".fbBody #fbHSplitter{position:absolute !important;} .fbBody #fbHTML span{line-height:14px;} .fbBody .lineNo div{line-height:inherit !important;}";
  7849. /*
  7850. if (isIE)
  7851. {
  7852. // IE7 CSS bug (FbChrome table bigger than its parent div)
  7853. rules += ".fbBody table.fbChrome{position: static !important;}";
  7854. }/**/
  7855. style.type = "text/css";
  7856. if (style.styleSheet)
  7857. style.styleSheet.cssText = rules;
  7858. else
  7859. style.appendChild(context.document.createTextNode(rules));
  7860. document.getElementsByTagName("head")[0].appendChild(style);
  7861. node.className = "fbBody";
  7862. node.style.overflow = "hidden";
  7863. node.innerHTML = getChromeDivTemplate();
  7864. if (isIE)
  7865. {
  7866. // IE7 CSS bug (FbChrome table bigger than its parent div)
  7867. setTimeout(function(){
  7868. node.firstChild.style.height = "1px";
  7869. node.firstChild.style.position = "static";
  7870. },0);
  7871. /**/
  7872. }
  7873. formatNode(node);
  7874. body.appendChild(node);
  7875. chrome.window = window;
  7876. chrome.document = document;
  7877. onChromeLoad(chrome);
  7878. };
  7879. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7880. try
  7881. {
  7882. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7883. // create the Chrome as a "div" (windowless mode)
  7884. if (type == "div")
  7885. {
  7886. createChromeDiv();
  7887. return;
  7888. }
  7889. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7890. // cretate the Chrome as an "iframe"
  7891. else if (isChromeFrame)
  7892. {
  7893. // Create the Chrome Frame
  7894. var node = chrome.node = createGlobalElement("iframe");
  7895. node.setAttribute("src", url);
  7896. node.setAttribute("frameBorder", "0");
  7897. formatNode(node);
  7898. body.appendChild(node);
  7899. // must set the id after appending to the document, otherwise will cause an
  7900. // strange error in IE, making the iframe load the page in which the bookmarklet
  7901. // was created (like getfirebug.com), before loading the injected UI HTML,
  7902. // generating an "Access Denied" error.
  7903. node.id = options.id;
  7904. }
  7905. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7906. // create the Chrome as a "popup"
  7907. else
  7908. {
  7909. var height = FirebugChrome.height || options.height,
  7910. options = [
  7911. "true,top=",
  7912. Math.max(screen.availHeight - height - 61 /* Google Chrome bug */, 0),
  7913. ",left=0,height=",
  7914. height,
  7915. ",width=",
  7916. screen.availWidth-10, // Opera opens popup in a new tab if it's too big!
  7917. ",resizable"
  7918. ].join(""),
  7919. node = chrome.node = context.window.open(
  7920. url,
  7921. "popup",
  7922. options
  7923. );
  7924. if (node)
  7925. {
  7926. try
  7927. {
  7928. node.focus();
  7929. }
  7930. catch(E)
  7931. {
  7932. alert("Firebug Error: Firebug popup was blocked.");
  7933. return;
  7934. }
  7935. }
  7936. else
  7937. {
  7938. alert("Firebug Error: Firebug popup was blocked.");
  7939. return;
  7940. }
  7941. }
  7942. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7943. // Inject the interface HTML if it is not using the local skin
  7944. if (!useLocalSkin)
  7945. {
  7946. var tpl = getChromeTemplate(!isChromeFrame),
  7947. doc = isChromeFrame ? node.contentWindow.document : node.document;
  7948. doc.write(tpl);
  7949. doc.close();
  7950. }
  7951. //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7952. // Wait the Window to be loaded
  7953. var win,
  7954. waitDelay = useLocalSkin ? isChromeFrame ? 200 : 300 : 100,
  7955. waitForWindow = function()
  7956. {
  7957. if ( // Frame loaded... OR
  7958. isChromeFrame && (win=node.contentWindow) &&
  7959. node.contentWindow.document.getElementById("fbCommandLine") ||
  7960. // Popup loaded
  7961. !isChromeFrame && (win=node.window) && node.document &&
  7962. node.document.getElementById("fbCommandLine") )
  7963. {
  7964. chrome.window = win.window;
  7965. chrome.document = win.document;
  7966. // Prevent getting the wrong chrome height in FF when opening a popup
  7967. setTimeout(function(){
  7968. onChromeLoad(chrome);
  7969. },0);
  7970. }
  7971. else
  7972. setTimeout(waitForWindow, waitDelay);
  7973. };
  7974. waitForWindow();
  7975. }
  7976. catch(e)
  7977. {
  7978. var msg = e.message || e;
  7979. if (/access/i.test(msg))
  7980. {
  7981. // Firebug Lite could not create a window for its Graphical User Interface due to
  7982. // a access restriction. This happens in some pages, when loading via bookmarklet.
  7983. // In such cases, the only way is to load the GUI in a "windowless mode".
  7984. if (isChromeFrame)
  7985. body.removeChild(node);
  7986. else if(type == "popup")
  7987. node.close();
  7988. // Load the GUI in a "windowless mode"
  7989. createChromeDiv();
  7990. }
  7991. else
  7992. {
  7993. alert("Firebug Error: Firebug GUI could not be created.");
  7994. }
  7995. }
  7996. };
  7997. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  7998. var onChromeLoad = function onChromeLoad(chrome)
  7999. {
  8000. Env.chrome = chrome;
  8001. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Chrome onChromeLoad", "chrome window loaded");
  8002. if (Env.Options.enablePersistent)
  8003. {
  8004. // TODO: xxxpedro persist - make better chrome synchronization when in persistent mode
  8005. Env.FirebugChrome = FirebugChrome;
  8006. chrome.window.Firebug = chrome.window.Firebug || {};
  8007. chrome.window.Firebug.SharedEnv = Env;
  8008. if (Env.isDevelopmentMode)
  8009. {
  8010. Env.browser.window.FBDev.loadChromeApplication(chrome);
  8011. }
  8012. else
  8013. {
  8014. var doc = chrome.document;
  8015. var script = doc.createElement("script");
  8016. script.src = Env.Location.app + "#remote,persist";
  8017. doc.getElementsByTagName("head")[0].appendChild(script);
  8018. }
  8019. }
  8020. else
  8021. {
  8022. if (chrome.type == "frame" || chrome.type == "div")
  8023. {
  8024. // initialize the chrome application
  8025. setTimeout(function(){
  8026. FBL.Firebug.initialize();
  8027. },0);
  8028. }
  8029. else if (chrome.type == "popup")
  8030. {
  8031. var oldChrome = FirebugChrome.chromeMap.frame;
  8032. var newChrome = new Chrome(chrome);
  8033. // TODO: xxxpedro sync detach reattach attach
  8034. dispatch(newChrome.panelMap, "detach", [oldChrome, newChrome]);
  8035. if (oldChrome)
  8036. oldChrome.close();
  8037. newChrome.reattach(oldChrome, newChrome);
  8038. }
  8039. }
  8040. };
  8041. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8042. var getChromeDivTemplate = function()
  8043. {
  8044. return FirebugChrome.Skin.HTML;
  8045. };
  8046. var getChromeTemplate = function(isPopup)
  8047. {
  8048. var tpl = FirebugChrome.Skin;
  8049. var r = [], i = -1;
  8050. r[++i] = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/DTD/strict.dtd">';
  8051. r[++i] = '<html><head><title>';
  8052. r[++i] = Firebug.version;
  8053. /*
  8054. r[++i] = '</title><link href="';
  8055. r[++i] = Env.Location.skinDir + 'firebug.css';
  8056. r[++i] = '" rel="stylesheet" type="text/css" />';
  8057. /**/
  8058. r[++i] = '</title><style>html,body{margin:0;padding:0;overflow:hidden;}';
  8059. r[++i] = tpl.CSS;
  8060. r[++i] = '</style>';
  8061. /**/
  8062. r[++i] = '</head><body class="fbBody' + (isPopup ? ' FirebugPopup' : '') + '">';
  8063. r[++i] = tpl.HTML;
  8064. r[++i] = '</body></html>';
  8065. return r.join("");
  8066. };
  8067. // ************************************************************************************************
  8068. // Chrome Class
  8069. /**@class*/
  8070. var Chrome = function Chrome(chrome)
  8071. {
  8072. var type = chrome.type;
  8073. var Base = type == "frame" || type == "div" ? ChromeFrameBase : ChromePopupBase;
  8074. append(this, Base); // inherit from base class (ChromeFrameBase or ChromePopupBase)
  8075. append(this, chrome); // inherit chrome window properties
  8076. append(this, new Context(chrome.window)); // inherit from Context class
  8077. FirebugChrome.chromeMap[type] = this;
  8078. Firebug.chrome = this;
  8079. Env.chrome = chrome.window;
  8080. this.commandLineVisible = false;
  8081. this.sidePanelVisible = false;
  8082. this.create();
  8083. return this;
  8084. };
  8085. // ************************************************************************************************
  8086. // ChromeBase
  8087. /**
  8088. * @namespace
  8089. * @extends FBL.Controller
  8090. * @extends FBL.PanelBar
  8091. **/
  8092. var ChromeBase = {};
  8093. append(ChromeBase, Controller);
  8094. append(ChromeBase, PanelBar);
  8095. append(ChromeBase,
  8096. /**@extend ns-chrome-ChromeBase*/
  8097. {
  8098. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8099. // inherited properties
  8100. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8101. // inherited from createChrome function
  8102. node: null,
  8103. type: null,
  8104. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8105. // inherited from Context.prototype
  8106. document: null,
  8107. window: null,
  8108. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8109. // value properties
  8110. sidePanelVisible: false,
  8111. commandLineVisible: false,
  8112. largeCommandLineVisible: false,
  8113. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8114. // object properties
  8115. inspectButton: null,
  8116. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8117. create: function()
  8118. {
  8119. PanelBar.create.call(this);
  8120. if (Firebug.Inspector)
  8121. this.inspectButton = new Button({
  8122. type: "toggle",
  8123. element: $("fbChrome_btInspect"),
  8124. owner: Firebug.Inspector,
  8125. onPress: Firebug.Inspector.startInspecting,
  8126. onUnpress: Firebug.Inspector.stopInspecting
  8127. });
  8128. },
  8129. destroy: function()
  8130. {
  8131. if(Firebug.Inspector)
  8132. this.inspectButton.destroy();
  8133. PanelBar.destroy.call(this);
  8134. this.shutdown();
  8135. },
  8136. testMenu: function()
  8137. {
  8138. var firebugMenu = new Menu(
  8139. {
  8140. id: "fbFirebugMenu",
  8141. items:
  8142. [
  8143. {
  8144. label: "Open Firebug",
  8145. type: "shortcut",
  8146. key: isFirefox ? "Shift+F12" : "F12",
  8147. checked: true,
  8148. command: "toggleChrome"
  8149. },
  8150. {
  8151. label: "Open Firebug in New Window",
  8152. type: "shortcut",
  8153. key: isFirefox ? "Ctrl+Shift+F12" : "Ctrl+F12",
  8154. command: "openPopup"
  8155. },
  8156. {
  8157. label: "Inspect Element",
  8158. type: "shortcut",
  8159. key: "Ctrl+Shift+C",
  8160. command: "toggleInspect"
  8161. },
  8162. {
  8163. label: "Command Line",
  8164. type: "shortcut",
  8165. key: "Ctrl+Shift+L",
  8166. command: "focusCommandLine"
  8167. },
  8168. "-",
  8169. {
  8170. label: "Options",
  8171. type: "group",
  8172. child: "fbFirebugOptionsMenu"
  8173. },
  8174. "-",
  8175. {
  8176. label: "Firebug Lite Website...",
  8177. command: "visitWebsite"
  8178. },
  8179. {
  8180. label: "Discussion Group...",
  8181. command: "visitDiscussionGroup"
  8182. },
  8183. {
  8184. label: "Issue Tracker...",
  8185. command: "visitIssueTracker"
  8186. }
  8187. ],
  8188. onHide: function()
  8189. {
  8190. iconButton.restore();
  8191. },
  8192. toggleChrome: function()
  8193. {
  8194. Firebug.chrome.toggle();
  8195. },
  8196. openPopup: function()
  8197. {
  8198. Firebug.chrome.toggle(true, true);
  8199. },
  8200. toggleInspect: function()
  8201. {
  8202. Firebug.Inspector.toggleInspect();
  8203. },
  8204. focusCommandLine: function()
  8205. {
  8206. Firebug.chrome.focusCommandLine();
  8207. },
  8208. visitWebsite: function()
  8209. {
  8210. this.visit("http://getfirebug.com/lite.html");
  8211. },
  8212. visitDiscussionGroup: function()
  8213. {
  8214. this.visit("http://groups.google.com/group/firebug");
  8215. },
  8216. visitIssueTracker: function()
  8217. {
  8218. this.visit("http://code.google.com/p/fbug/issues/list");
  8219. },
  8220. visit: function(url)
  8221. {
  8222. window.open(url);
  8223. }
  8224. });
  8225. /**@private*/
  8226. var firebugOptionsMenu =
  8227. {
  8228. id: "fbFirebugOptionsMenu",
  8229. getItems: function()
  8230. {
  8231. var cookiesDisabled = !Firebug.saveCookies;
  8232. return [
  8233. {
  8234. label: "Save Options in Cookies",
  8235. type: "checkbox",
  8236. value: "saveCookies",
  8237. checked: Firebug.saveCookies,
  8238. command: "saveOptions"
  8239. },
  8240. "-",
  8241. {
  8242. label: "Start Opened",
  8243. type: "checkbox",
  8244. value: "startOpened",
  8245. checked: Firebug.startOpened,
  8246. disabled: cookiesDisabled
  8247. },
  8248. {
  8249. label: "Start in New Window",
  8250. type: "checkbox",
  8251. value: "startInNewWindow",
  8252. checked: Firebug.startInNewWindow,
  8253. disabled: cookiesDisabled
  8254. },
  8255. {
  8256. label: "Show Icon When Hidden",
  8257. type: "checkbox",
  8258. value: "showIconWhenHidden",
  8259. checked: Firebug.showIconWhenHidden,
  8260. disabled: cookiesDisabled
  8261. },
  8262. {
  8263. label: "Override Console Object",
  8264. type: "checkbox",
  8265. value: "overrideConsole",
  8266. checked: Firebug.overrideConsole,
  8267. disabled: cookiesDisabled
  8268. },
  8269. {
  8270. label: "Ignore Firebug Elements",
  8271. type: "checkbox",
  8272. value: "ignoreFirebugElements",
  8273. checked: Firebug.ignoreFirebugElements,
  8274. disabled: cookiesDisabled
  8275. },
  8276. {
  8277. label: "Disable When Firebug Active",
  8278. type: "checkbox",
  8279. value: "disableWhenFirebugActive",
  8280. checked: Firebug.disableWhenFirebugActive,
  8281. disabled: cookiesDisabled
  8282. },
  8283. {
  8284. label: "Disable XHR Listener",
  8285. type: "checkbox",
  8286. value: "disableXHRListener",
  8287. checked: Firebug.disableXHRListener,
  8288. disabled: cookiesDisabled
  8289. },
  8290. {
  8291. label: "Enable Trace Mode",
  8292. type: "checkbox",
  8293. value: "enableTrace",
  8294. checked: Firebug.enableTrace,
  8295. disabled: cookiesDisabled
  8296. },
  8297. {
  8298. label: "Enable Persistent Mode (experimental)",
  8299. type: "checkbox",
  8300. value: "enablePersistent",
  8301. checked: Firebug.enablePersistent,
  8302. disabled: cookiesDisabled
  8303. },
  8304. "-",
  8305. {
  8306. label: "Reset All Firebug Options",
  8307. command: "restorePrefs",
  8308. disabled: cookiesDisabled
  8309. }
  8310. ];
  8311. },
  8312. onCheck: function(target, value, checked)
  8313. {
  8314. Firebug.setPref(value, checked);
  8315. },
  8316. saveOptions: function(target)
  8317. {
  8318. var saveEnabled = target.getAttribute("checked");
  8319. if (!saveEnabled) this.restorePrefs();
  8320. this.updateMenu(target);
  8321. return false;
  8322. },
  8323. restorePrefs: function(target)
  8324. {
  8325. Firebug.restorePrefs();
  8326. if(Firebug.saveCookies)
  8327. Firebug.savePrefs();
  8328. else
  8329. Firebug.erasePrefs();
  8330. if (target)
  8331. this.updateMenu(target);
  8332. return false;
  8333. },
  8334. updateMenu: function(target)
  8335. {
  8336. var options = getElementsByClass(target.parentNode, "fbMenuOption");
  8337. var firstOption = options[0];
  8338. var enabled = Firebug.saveCookies;
  8339. if (enabled)
  8340. Menu.check(firstOption);
  8341. else
  8342. Menu.uncheck(firstOption);
  8343. if (enabled)
  8344. Menu.check(options[0]);
  8345. else
  8346. Menu.uncheck(options[0]);
  8347. for (var i = 1, length = options.length; i < length; i++)
  8348. {
  8349. var option = options[i];
  8350. var value = option.getAttribute("value");
  8351. var pref = Firebug[value];
  8352. if (pref)
  8353. Menu.check(option);
  8354. else
  8355. Menu.uncheck(option);
  8356. if (enabled)
  8357. Menu.enable(option);
  8358. else
  8359. Menu.disable(option);
  8360. }
  8361. }
  8362. };
  8363. Menu.register(firebugOptionsMenu);
  8364. var menu = firebugMenu;
  8365. var testMenuClick = function(event)
  8366. {
  8367. //console.log("testMenuClick");
  8368. cancelEvent(event, true);
  8369. var target = event.target || event.srcElement;
  8370. if (menu.isVisible)
  8371. menu.hide();
  8372. else
  8373. {
  8374. var offsetLeft = isIE6 ? 1 : -4, // IE6 problem with fixed position
  8375. chrome = Firebug.chrome,
  8376. box = chrome.getElementBox(target),
  8377. offset = chrome.type == "div" ?
  8378. chrome.getElementPosition(chrome.node) :
  8379. {top: 0, left: 0};
  8380. menu.show(
  8381. box.left + offsetLeft - offset.left,
  8382. box.top + box.height -5 - offset.top
  8383. );
  8384. }
  8385. return false;
  8386. };
  8387. var iconButton = new IconButton({
  8388. type: "toggle",
  8389. element: $("fbFirebugButton"),
  8390. onClick: testMenuClick
  8391. });
  8392. iconButton.initialize();
  8393. //addEvent($("fbToolbarIcon"), "click", testMenuClick);
  8394. },
  8395. initialize: function()
  8396. {
  8397. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8398. if (Env.bookmarkletOutdated)
  8399. Firebug.Console.logFormatted([
  8400. "A new bookmarklet version is available. " +
  8401. "Please visit http://getfirebug.com/firebuglite#Install and update it."
  8402. ], Firebug.context, "warn");
  8403. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8404. if (Firebug.Console)
  8405. Firebug.Console.flush();
  8406. if (Firebug.Trace)
  8407. FBTrace.flush(Firebug.Trace);
  8408. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8409. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.chrome.initialize", "initializing chrome application");
  8410. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8411. // initialize inherited classes
  8412. Controller.initialize.call(this);
  8413. PanelBar.initialize.call(this);
  8414. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8415. // create the interface elements cache
  8416. fbTop = $("fbTop");
  8417. fbContent = $("fbContent");
  8418. fbContentStyle = fbContent.style;
  8419. fbBottom = $("fbBottom");
  8420. fbBtnInspect = $("fbBtnInspect");
  8421. fbToolbar = $("fbToolbar");
  8422. fbPanelBox1 = $("fbPanelBox1");
  8423. fbPanelBox1Style = fbPanelBox1.style;
  8424. fbPanelBox2 = $("fbPanelBox2");
  8425. fbPanelBox2Style = fbPanelBox2.style;
  8426. fbPanelBar2Box = $("fbPanelBar2Box");
  8427. fbPanelBar2BoxStyle = fbPanelBar2Box.style;
  8428. fbHSplitter = $("fbHSplitter");
  8429. fbVSplitter = $("fbVSplitter");
  8430. fbVSplitterStyle = fbVSplitter.style;
  8431. fbPanel1 = $("fbPanel1");
  8432. fbPanel1Style = fbPanel1.style;
  8433. fbPanel2 = $("fbPanel2");
  8434. fbPanel2Style = fbPanel2.style;
  8435. fbConsole = $("fbConsole");
  8436. fbConsoleStyle = fbConsole.style;
  8437. fbHTML = $("fbHTML");
  8438. fbCommandLine = $("fbCommandLine");
  8439. fbLargeCommandLine = $("fbLargeCommandLine");
  8440. fbLargeCommandButtons = $("fbLargeCommandButtons");
  8441. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8442. // static values cache
  8443. topHeight = fbTop.offsetHeight;
  8444. topPartialHeight = fbToolbar.offsetHeight;
  8445. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8446. disableTextSelection($("fbToolbar"));
  8447. disableTextSelection($("fbPanelBarBox"));
  8448. disableTextSelection($("fbPanelBar1"));
  8449. disableTextSelection($("fbPanelBar2"));
  8450. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8451. // Add the "javascript:void(0)" href attributes used to make the hover effect in IE6
  8452. if (isIE6 && Firebug.Selector)
  8453. {
  8454. // TODO: xxxpedro change to getElementsByClass
  8455. var as = $$(".fbHover");
  8456. for (var i=0, a; a=as[i]; i++)
  8457. {
  8458. a.setAttribute("href", "javascript:void(0)");
  8459. }
  8460. }
  8461. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8462. // initialize all panels
  8463. /*
  8464. var panelMap = Firebug.panelTypes;
  8465. for (var i=0, p; p=panelMap[i]; i++)
  8466. {
  8467. if (!p.parentPanel)
  8468. {
  8469. this.addPanel(p.prototype.name);
  8470. }
  8471. }
  8472. /**/
  8473. // ************************************************************************************************
  8474. // ************************************************************************************************
  8475. // ************************************************************************************************
  8476. // ************************************************************************************************
  8477. if(Firebug.Inspector)
  8478. this.inspectButton.initialize();
  8479. // ************************************************************************************************
  8480. // ************************************************************************************************
  8481. // ************************************************************************************************
  8482. // ************************************************************************************************
  8483. this.addController(
  8484. [$("fbLargeCommandLineIcon"), "click", this.showLargeCommandLine]
  8485. );
  8486. // ************************************************************************************************
  8487. // Select the first registered panel
  8488. // TODO: BUG IE7
  8489. var self = this;
  8490. setTimeout(function(){
  8491. self.selectPanel(FirebugChrome.selectedPanelName);
  8492. if (FirebugChrome.selectedPanelName == "Console" && Firebug.CommandLine)
  8493. Firebug.chrome.focusCommandLine();
  8494. },0);
  8495. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8496. //this.draw();
  8497. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8498. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8499. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8500. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8501. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8502. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8503. var onPanelMouseDown = function onPanelMouseDown(event)
  8504. {
  8505. //console.log("onPanelMouseDown", event.target || event.srcElement, event);
  8506. var target = event.target || event.srcElement;
  8507. if (FBL.isLeftClick(event))
  8508. {
  8509. var editable = FBL.getAncestorByClass(target, "editable");
  8510. // if an editable element has been clicked then start editing
  8511. if (editable)
  8512. {
  8513. Firebug.Editor.startEditing(editable);
  8514. FBL.cancelEvent(event);
  8515. }
  8516. // if any other element has been clicked then stop editing
  8517. else
  8518. {
  8519. if (!hasClass(target, "textEditorInner"))
  8520. Firebug.Editor.stopEditing();
  8521. }
  8522. }
  8523. else if (FBL.isMiddleClick(event) && Firebug.getRepNode(target))
  8524. {
  8525. // Prevent auto-scroll when middle-clicking a rep object
  8526. FBL.cancelEvent(event);
  8527. }
  8528. };
  8529. Firebug.getElementPanel = function(element)
  8530. {
  8531. var panelNode = getAncestorByClass(element, "fbPanel");
  8532. var id = panelNode.id.substr(2);
  8533. var panel = Firebug.chrome.panelMap[id];
  8534. if (!panel)
  8535. {
  8536. if (Firebug.chrome.selectedPanel.sidePanelBar)
  8537. panel = Firebug.chrome.selectedPanel.sidePanelBar.panelMap[id];
  8538. }
  8539. return panel;
  8540. };
  8541. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8542. // TODO: xxxpedro port to Firebug
  8543. // Improved window key code event listener. Only one "keydown" event will be attached
  8544. // to the window, and the onKeyCodeListen() function will delegate which listeners
  8545. // should be called according to the event.keyCode fired.
  8546. var onKeyCodeListenersMap = [];
  8547. var onKeyCodeListen = function(event)
  8548. {
  8549. for (var keyCode in onKeyCodeListenersMap)
  8550. {
  8551. var listeners = onKeyCodeListenersMap[keyCode];
  8552. for (var i = 0, listener; listener = listeners[i]; i++)
  8553. {
  8554. var filter = listener.filter || FBL.noKeyModifiers;
  8555. if (event.keyCode == keyCode && (!filter || filter(event)))
  8556. {
  8557. listener.listener();
  8558. FBL.cancelEvent(event, true);
  8559. return false;
  8560. }
  8561. }
  8562. }
  8563. };
  8564. addEvent(Firebug.chrome.document, "keydown", onKeyCodeListen);
  8565. /**
  8566. * @name keyCodeListen
  8567. * @memberOf FBL.FirebugChrome
  8568. */
  8569. Firebug.chrome.keyCodeListen = function(key, filter, listener, capture)
  8570. {
  8571. var keyCode = KeyEvent["DOM_VK_"+key];
  8572. if (!onKeyCodeListenersMap[keyCode])
  8573. onKeyCodeListenersMap[keyCode] = [];
  8574. onKeyCodeListenersMap[keyCode].push({
  8575. filter: filter,
  8576. listener: listener
  8577. });
  8578. return keyCode;
  8579. };
  8580. /**
  8581. * @name keyIgnore
  8582. * @memberOf FBL.FirebugChrome
  8583. */
  8584. Firebug.chrome.keyIgnore = function(keyCode)
  8585. {
  8586. onKeyCodeListenersMap[keyCode] = null;
  8587. delete onKeyCodeListenersMap[keyCode];
  8588. };
  8589. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8590. /**/
  8591. // move to shutdown
  8592. //removeEvent(Firebug.chrome.document, "keydown", listener[0]);
  8593. /*
  8594. Firebug.chrome.keyCodeListen = function(key, filter, listener, capture)
  8595. {
  8596. if (!filter)
  8597. filter = FBL.noKeyModifiers;
  8598. var keyCode = KeyEvent["DOM_VK_"+key];
  8599. var fn = function fn(event)
  8600. {
  8601. if (event.keyCode == keyCode && (!filter || filter(event)))
  8602. {
  8603. listener();
  8604. FBL.cancelEvent(event, true);
  8605. return false;
  8606. }
  8607. }
  8608. addEvent(Firebug.chrome.document, "keydown", fn);
  8609. return [fn, capture];
  8610. };
  8611. Firebug.chrome.keyIgnore = function(listener)
  8612. {
  8613. removeEvent(Firebug.chrome.document, "keydown", listener[0]);
  8614. };
  8615. /**/
  8616. this.addController(
  8617. [fbPanel1, "mousedown", onPanelMouseDown],
  8618. [fbPanel2, "mousedown", onPanelMouseDown]
  8619. );
  8620. /**/
  8621. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8622. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8623. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8624. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8625. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8626. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8627. // menus can be used without domplate
  8628. if (FBL.domplate)
  8629. this.testMenu();
  8630. /**/
  8631. //test XHR
  8632. /*
  8633. setTimeout(function(){
  8634. FBL.Ajax.request({url: "../content/firebug/boot.js"});
  8635. FBL.Ajax.request({url: "../content/firebug/boot.js.invalid"});
  8636. },1000);
  8637. /**/
  8638. },
  8639. shutdown: function()
  8640. {
  8641. // ************************************************************************************************
  8642. // ************************************************************************************************
  8643. // ************************************************************************************************
  8644. // ************************************************************************************************
  8645. if(Firebug.Inspector)
  8646. this.inspectButton.shutdown();
  8647. // ************************************************************************************************
  8648. // ************************************************************************************************
  8649. // ************************************************************************************************
  8650. // ************************************************************************************************
  8651. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8652. // remove disableTextSelection event handlers
  8653. restoreTextSelection($("fbToolbar"));
  8654. restoreTextSelection($("fbPanelBarBox"));
  8655. restoreTextSelection($("fbPanelBar1"));
  8656. restoreTextSelection($("fbPanelBar2"));
  8657. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8658. // shutdown inherited classes
  8659. Controller.shutdown.call(this);
  8660. PanelBar.shutdown.call(this);
  8661. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8662. // Remove the interface elements cache (this must happen after calling
  8663. // the shutdown method of all dependent components to avoid errors)
  8664. fbTop = null;
  8665. fbContent = null;
  8666. fbContentStyle = null;
  8667. fbBottom = null;
  8668. fbBtnInspect = null;
  8669. fbToolbar = null;
  8670. fbPanelBox1 = null;
  8671. fbPanelBox1Style = null;
  8672. fbPanelBox2 = null;
  8673. fbPanelBox2Style = null;
  8674. fbPanelBar2Box = null;
  8675. fbPanelBar2BoxStyle = null;
  8676. fbHSplitter = null;
  8677. fbVSplitter = null;
  8678. fbVSplitterStyle = null;
  8679. fbPanel1 = null;
  8680. fbPanel1Style = null;
  8681. fbPanel2 = null;
  8682. fbConsole = null;
  8683. fbConsoleStyle = null;
  8684. fbHTML = null;
  8685. fbCommandLine = null;
  8686. fbLargeCommandLine = null;
  8687. fbLargeCommandButtons = null;
  8688. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8689. // static values cache
  8690. topHeight = null;
  8691. topPartialHeight = null;
  8692. },
  8693. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8694. toggle: function(forceOpen, popup)
  8695. {
  8696. if(popup)
  8697. {
  8698. this.detach();
  8699. }
  8700. else
  8701. {
  8702. if (isOpera && Firebug.chrome.type == "popup" && Firebug.chrome.node.closed)
  8703. {
  8704. var frame = FirebugChrome.chromeMap.frame;
  8705. frame.reattach();
  8706. FirebugChrome.chromeMap.popup = null;
  8707. frame.open();
  8708. return;
  8709. }
  8710. // If the context is a popup, ignores the toggle process
  8711. if (Firebug.chrome.type == "popup") return;
  8712. var shouldOpen = forceOpen || !FirebugChrome.isOpen;
  8713. if(shouldOpen)
  8714. this.open();
  8715. else
  8716. this.close();
  8717. }
  8718. },
  8719. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8720. detach: function()
  8721. {
  8722. if(!FirebugChrome.chromeMap.popup)
  8723. {
  8724. createChromeWindow({type: "popup"});
  8725. }
  8726. },
  8727. reattach: function(oldChrome, newChrome)
  8728. {
  8729. Firebug.browser.window.Firebug = Firebug;
  8730. // chrome synchronization
  8731. var newPanelMap = newChrome.panelMap;
  8732. var oldPanelMap = oldChrome.panelMap;
  8733. var panel;
  8734. for(var name in newPanelMap)
  8735. {
  8736. // TODO: xxxpedro innerHTML
  8737. panel = newPanelMap[name];
  8738. if (panel.options.innerHTMLSync)
  8739. panel.panelNode.innerHTML = oldPanelMap[name].panelNode.innerHTML;
  8740. }
  8741. Firebug.chrome = newChrome;
  8742. // TODO: xxxpedro sync detach reattach attach
  8743. //dispatch(Firebug.chrome.panelMap, "detach", [oldChrome, newChrome]);
  8744. if (newChrome.type == "popup")
  8745. {
  8746. newChrome.initialize();
  8747. //dispatch(Firebug.modules, "initialize", []);
  8748. }
  8749. else
  8750. {
  8751. // TODO: xxxpedro only needed in persistent
  8752. // should use FirebugChrome.clone, but popup FBChrome
  8753. // isn't acessible
  8754. FirebugChrome.selectedPanelName = oldChrome.selectedPanel.name;
  8755. }
  8756. dispatch(newPanelMap, "reattach", [oldChrome, newChrome]);
  8757. },
  8758. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8759. draw: function()
  8760. {
  8761. var size = this.getSize();
  8762. // Height related values
  8763. var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0,
  8764. y = Math.max(size.height /* chrome height */, topHeight),
  8765. heightValue = Math.max(y - topHeight - commandLineHeight /* fixed height */, 0),
  8766. height = heightValue + "px",
  8767. // Width related values
  8768. sideWidthValue = Firebug.chrome.sidePanelVisible ? FirebugChrome.sidePanelWidth : 0,
  8769. width = Math.max(size.width /* chrome width */ - sideWidthValue, 0) + "px";
  8770. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8771. // Height related rendering
  8772. fbPanelBox1Style.height = height;
  8773. fbPanel1Style.height = height;
  8774. if (isIE || isOpera)
  8775. {
  8776. // Fix IE and Opera problems with auto resizing the verticall splitter
  8777. fbVSplitterStyle.height = Math.max(y - topPartialHeight - commandLineHeight, 0) + "px";
  8778. }
  8779. //xxxpedro FF2 only?
  8780. /*
  8781. else if (isFirefox)
  8782. {
  8783. // Fix Firefox problem with table rows with 100% height (fit height)
  8784. fbContentStyle.maxHeight = Math.max(y - fixedHeight, 0)+ "px";
  8785. }/**/
  8786. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8787. // Width related rendering
  8788. fbPanelBox1Style.width = width;
  8789. fbPanel1Style.width = width;
  8790. // SidePanel rendering
  8791. if (Firebug.chrome.sidePanelVisible)
  8792. {
  8793. sideWidthValue = Math.max(sideWidthValue - 6, 0);
  8794. var sideWidth = sideWidthValue + "px";
  8795. fbPanelBox2Style.width = sideWidth;
  8796. fbVSplitterStyle.right = sideWidth;
  8797. if (Firebug.chrome.largeCommandLineVisible)
  8798. {
  8799. fbLargeCommandLine = $("fbLargeCommandLine");
  8800. fbLargeCommandLine.style.height = heightValue - 4 + "px";
  8801. fbLargeCommandLine.style.width = sideWidthValue - 2 + "px";
  8802. fbLargeCommandButtons = $("fbLargeCommandButtons");
  8803. fbLargeCommandButtons.style.width = sideWidth;
  8804. }
  8805. else
  8806. {
  8807. fbPanel2Style.height = height;
  8808. fbPanel2Style.width = sideWidth;
  8809. fbPanelBar2BoxStyle.width = sideWidth;
  8810. }
  8811. }
  8812. },
  8813. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8814. getSize: function()
  8815. {
  8816. return this.type == "div" ?
  8817. {
  8818. height: this.node.offsetHeight,
  8819. width: this.node.offsetWidth
  8820. }
  8821. :
  8822. this.getWindowSize();
  8823. },
  8824. resize: function()
  8825. {
  8826. var self = this;
  8827. // avoid partial resize when maximizing window
  8828. setTimeout(function(){
  8829. self.draw();
  8830. if (noFixedPosition && (self.type == "frame" || self.type == "div"))
  8831. self.fixIEPosition();
  8832. }, 0);
  8833. },
  8834. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8835. layout: function(panel)
  8836. {
  8837. if (FBTrace.DBG_CHROME) FBTrace.sysout("Chrome.layout", "");
  8838. var options = panel.options;
  8839. changeCommandLineVisibility(options.hasCommandLine);
  8840. changeSidePanelVisibility(panel.hasSidePanel);
  8841. Firebug.chrome.draw();
  8842. },
  8843. showLargeCommandLine: function(hideToggleIcon)
  8844. {
  8845. var chrome = Firebug.chrome;
  8846. if (!chrome.largeCommandLineVisible)
  8847. {
  8848. chrome.largeCommandLineVisible = true;
  8849. if (chrome.selectedPanel.options.hasCommandLine)
  8850. {
  8851. if (Firebug.CommandLine)
  8852. Firebug.CommandLine.blur();
  8853. changeCommandLineVisibility(false);
  8854. }
  8855. changeSidePanelVisibility(true);
  8856. fbLargeCommandLine.style.display = "block";
  8857. fbLargeCommandButtons.style.display = "block";
  8858. fbPanel2Style.display = "none";
  8859. fbPanelBar2BoxStyle.display = "none";
  8860. chrome.draw();
  8861. fbLargeCommandLine.focus();
  8862. if (Firebug.CommandLine)
  8863. Firebug.CommandLine.setMultiLine(true);
  8864. }
  8865. },
  8866. hideLargeCommandLine: function()
  8867. {
  8868. if (Firebug.chrome.largeCommandLineVisible)
  8869. {
  8870. Firebug.chrome.largeCommandLineVisible = false;
  8871. if (Firebug.CommandLine)
  8872. Firebug.CommandLine.setMultiLine(false);
  8873. fbLargeCommandLine.blur();
  8874. fbPanel2Style.display = "block";
  8875. fbPanelBar2BoxStyle.display = "block";
  8876. fbLargeCommandLine.style.display = "none";
  8877. fbLargeCommandButtons.style.display = "none";
  8878. changeSidePanelVisibility(false);
  8879. if (Firebug.chrome.selectedPanel.options.hasCommandLine)
  8880. changeCommandLineVisibility(true);
  8881. Firebug.chrome.draw();
  8882. }
  8883. },
  8884. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  8885. focusCommandLine: function()
  8886. {
  8887. var selectedPanelName = this.selectedPanel.name, panelToSelect;
  8888. if (focusCommandLineState == 0 || selectedPanelName != "Console")
  8889. {
  8890. focusCommandLineState = 0;
  8891. lastFocusedPanelName = selectedPanelName;
  8892. panelToSelect = "Console";
  8893. }
  8894. if (focusCommandLineState == 1)
  8895. {
  8896. panelToSelect = lastFocusedPanelName;
  8897. }
  8898. this.selectPanel(panelToSelect);
  8899. try
  8900. {
  8901. if (Firebug.CommandLine)
  8902. {
  8903. if (panelToSelect == "Console")
  8904. Firebug.CommandLine.focus();
  8905. else
  8906. Firebug.CommandLine.blur();
  8907. }
  8908. }
  8909. catch(e)
  8910. {
  8911. //TODO: xxxpedro trace error
  8912. }
  8913. focusCommandLineState = ++focusCommandLineState % 2;
  8914. }
  8915. });
  8916. // ************************************************************************************************
  8917. // ChromeFrameBase
  8918. /**
  8919. * @namespace
  8920. * @extends ns-chrome-ChromeBase
  8921. */
  8922. var ChromeFrameBase = extend(ChromeBase,
  8923. /**@extend ns-chrome-ChromeFrameBase*/
  8924. {
  8925. create: function()
  8926. {
  8927. ChromeBase.create.call(this);
  8928. // restore display for the anti-flicker trick
  8929. if (isFirefox)
  8930. this.node.style.display = "block";
  8931. if (Env.Options.startInNewWindow)
  8932. {
  8933. this.close();
  8934. this.toggle(true, true);
  8935. return;
  8936. }
  8937. if (Env.Options.startOpened)
  8938. this.open();
  8939. else
  8940. this.close();
  8941. },
  8942. destroy: function()
  8943. {
  8944. removeGlobalEvent("keydown", onGlobalKeyDown);
  8945. ChromeBase.destroy.call(this);
  8946. this.document = null;
  8947. delete this.document;
  8948. this.window = null;
  8949. delete this.window;
  8950. this.node.parentNode.removeChild(this.node);
  8951. this.node = null;
  8952. delete this.node;
  8953. },
  8954. initialize: function()
  8955. {
  8956. //FBTrace.sysout("Frame", "initialize();")
  8957. ChromeBase.initialize.call(this);
  8958. this.addController(
  8959. [Firebug.browser.window, "resize", this.resize],
  8960. [$("fbWindow_btClose"), "click", this.close],
  8961. [$("fbWindow_btDetach"), "click", this.detach],
  8962. [$("fbWindow_btDeactivate"), "click", this.deactivate]
  8963. );
  8964. if (!Env.Options.enablePersistent)
  8965. this.addController([Firebug.browser.window, "unload", Firebug.shutdown]);
  8966. if (noFixedPosition)
  8967. {
  8968. this.addController(
  8969. [Firebug.browser.window, "scroll", this.fixIEPosition]
  8970. );
  8971. }
  8972. fbVSplitter.onmousedown = onVSplitterMouseDown;
  8973. fbHSplitter.onmousedown = onHSplitterMouseDown;
  8974. this.isInitialized = true;
  8975. },
  8976. shutdown: function()
  8977. {
  8978. fbVSplitter.onmousedown = null;
  8979. fbHSplitter.onmousedown = null;
  8980. ChromeBase.shutdown.apply(this);
  8981. this.isInitialized = false;
  8982. },
  8983. reattach: function()
  8984. {
  8985. var frame = FirebugChrome.chromeMap.frame;
  8986. ChromeBase.reattach(FirebugChrome.chromeMap.popup, this);
  8987. },
  8988. open: function()
  8989. {
  8990. if (!FirebugChrome.isOpen)
  8991. {
  8992. FirebugChrome.isOpen = true;
  8993. if (Env.isChromeExtension)
  8994. localStorage.setItem("Firebug", "1,1");
  8995. var node = this.node;
  8996. node.style.visibility = "hidden"; // Avoid flickering
  8997. if (Firebug.showIconWhenHidden)
  8998. {
  8999. if (ChromeMini.isInitialized)
  9000. {
  9001. ChromeMini.shutdown();
  9002. }
  9003. }
  9004. else
  9005. node.style.display = "block";
  9006. var main = $("fbChrome");
  9007. // IE6 throws an error when setting this property! why?
  9008. //main.style.display = "table";
  9009. main.style.display = "";
  9010. var self = this;
  9011. setTimeout(function(){
  9012. node.style.visibility = "visible";
  9013. //dispatch(Firebug.modules, "initialize", []);
  9014. self.initialize();
  9015. if (noFixedPosition)
  9016. self.fixIEPosition();
  9017. self.draw();
  9018. }, 10);
  9019. }
  9020. },
  9021. close: function()
  9022. {
  9023. if (FirebugChrome.isOpen || !this.isInitialized)
  9024. {
  9025. if (this.isInitialized)
  9026. {
  9027. //dispatch(Firebug.modules, "shutdown", []);
  9028. this.shutdown();
  9029. }
  9030. FirebugChrome.isOpen = false;
  9031. if (Env.isChromeExtension)
  9032. localStorage.setItem("Firebug", "1,0");
  9033. var node = this.node;
  9034. if (Firebug.showIconWhenHidden)
  9035. {
  9036. node.style.visibility = "hidden"; // Avoid flickering
  9037. // TODO: xxxpedro - persist IE fixed?
  9038. var main = $("fbChrome", FirebugChrome.chromeMap.frame.document);
  9039. main.style.display = "none";
  9040. ChromeMini.initialize();
  9041. node.style.visibility = "visible";
  9042. }
  9043. else
  9044. node.style.display = "none";
  9045. }
  9046. },
  9047. deactivate: function()
  9048. {
  9049. // if it is running as a Chrome extension, dispatch a message to the extension signaling
  9050. // that Firebug should be deactivated for the current tab
  9051. if (Env.isChromeExtension)
  9052. {
  9053. localStorage.removeItem("Firebug");
  9054. Firebug.GoogleChrome.dispatch("FB_deactivate");
  9055. // xxxpedro problem here regarding Chrome extension. We can't deactivate the whole
  9056. // app, otherwise it won't be able to be reactivated without reloading the page.
  9057. // but we need to stop listening global keys, otherwise the key activation won't work.
  9058. Firebug.chrome.close();
  9059. }
  9060. else
  9061. {
  9062. Firebug.shutdown();
  9063. }
  9064. },
  9065. fixIEPosition: function()
  9066. {
  9067. // fix IE problem with offset when not in fullscreen mode
  9068. var doc = this.document;
  9069. var offset = isIE ? doc.body.clientTop || doc.documentElement.clientTop: 0;
  9070. var size = Firebug.browser.getWindowSize();
  9071. var scroll = Firebug.browser.getWindowScrollPosition();
  9072. var maxHeight = size.height;
  9073. var height = this.node.offsetHeight;
  9074. var bodyStyle = doc.body.currentStyle;
  9075. this.node.style.top = maxHeight - height + scroll.top + "px";
  9076. if ((this.type == "frame" || this.type == "div") &&
  9077. (bodyStyle.marginLeft || bodyStyle.marginRight))
  9078. {
  9079. this.node.style.width = size.width + "px";
  9080. }
  9081. if (fbVSplitterStyle)
  9082. fbVSplitterStyle.right = FirebugChrome.sidePanelWidth + "px";
  9083. this.draw();
  9084. }
  9085. });
  9086. // ************************************************************************************************
  9087. // ChromeMini
  9088. /**
  9089. * @namespace
  9090. * @extends FBL.Controller
  9091. */
  9092. var ChromeMini = extend(Controller,
  9093. /**@extend ns-chrome-ChromeMini*/
  9094. {
  9095. create: function(chrome)
  9096. {
  9097. append(this, chrome);
  9098. this.type = "mini";
  9099. },
  9100. initialize: function()
  9101. {
  9102. Controller.initialize.apply(this);
  9103. var doc = FirebugChrome.chromeMap.frame.document;
  9104. var mini = $("fbMiniChrome", doc);
  9105. mini.style.display = "block";
  9106. var miniIcon = $("fbMiniIcon", doc);
  9107. var width = miniIcon.offsetWidth + 10;
  9108. miniIcon.title = "Open " + Firebug.version;
  9109. var errors = $("fbMiniErrors", doc);
  9110. if (errors.offsetWidth)
  9111. width += errors.offsetWidth + 10;
  9112. var node = this.node;
  9113. node.style.height = "27px";
  9114. node.style.width = width + "px";
  9115. node.style.left = "";
  9116. node.style.right = 0;
  9117. if (this.node.nodeName.toLowerCase() == "iframe")
  9118. {
  9119. node.setAttribute("allowTransparency", "true");
  9120. this.document.body.style.backgroundColor = "transparent";
  9121. }
  9122. else
  9123. node.style.background = "transparent";
  9124. if (noFixedPosition)
  9125. this.fixIEPosition();
  9126. this.addController(
  9127. [$("fbMiniIcon", doc), "click", onMiniIconClick]
  9128. );
  9129. if (noFixedPosition)
  9130. {
  9131. this.addController(
  9132. [Firebug.browser.window, "scroll", this.fixIEPosition]
  9133. );
  9134. }
  9135. this.isInitialized = true;
  9136. },
  9137. shutdown: function()
  9138. {
  9139. var node = this.node;
  9140. node.style.height = FirebugChrome.height + "px";
  9141. node.style.width = "100%";
  9142. node.style.left = 0;
  9143. node.style.right = "";
  9144. if (this.node.nodeName.toLowerCase() == "iframe")
  9145. {
  9146. node.setAttribute("allowTransparency", "false");
  9147. this.document.body.style.backgroundColor = "#fff";
  9148. }
  9149. else
  9150. node.style.background = "#fff";
  9151. if (noFixedPosition)
  9152. this.fixIEPosition();
  9153. var doc = FirebugChrome.chromeMap.frame.document;
  9154. var mini = $("fbMiniChrome", doc);
  9155. mini.style.display = "none";
  9156. Controller.shutdown.apply(this);
  9157. this.isInitialized = false;
  9158. },
  9159. draw: function()
  9160. {
  9161. },
  9162. fixIEPosition: ChromeFrameBase.fixIEPosition
  9163. });
  9164. // ************************************************************************************************
  9165. // ChromePopupBase
  9166. /**
  9167. * @namespace
  9168. * @extends ns-chrome-ChromeBase
  9169. */
  9170. var ChromePopupBase = extend(ChromeBase,
  9171. /**@extend ns-chrome-ChromePopupBase*/
  9172. {
  9173. initialize: function()
  9174. {
  9175. setClass(this.document.body, "FirebugPopup");
  9176. ChromeBase.initialize.call(this);
  9177. this.addController(
  9178. [Firebug.chrome.window, "resize", this.resize],
  9179. [Firebug.chrome.window, "unload", this.destroy]
  9180. );
  9181. if (Env.Options.enablePersistent)
  9182. {
  9183. this.persist = bind(this.persist, this);
  9184. addEvent(Firebug.browser.window, "unload", this.persist);
  9185. }
  9186. else
  9187. this.addController(
  9188. [Firebug.browser.window, "unload", this.close]
  9189. );
  9190. fbVSplitter.onmousedown = onVSplitterMouseDown;
  9191. },
  9192. destroy: function()
  9193. {
  9194. // TODO: xxxpedro sync detach reattach attach
  9195. var frame = FirebugChrome.chromeMap.frame;
  9196. if(frame)
  9197. {
  9198. dispatch(frame.panelMap, "detach", [this, frame]);
  9199. frame.reattach(this, frame);
  9200. }
  9201. if (Env.Options.enablePersistent)
  9202. {
  9203. removeEvent(Firebug.browser.window, "unload", this.persist);
  9204. }
  9205. ChromeBase.destroy.apply(this);
  9206. FirebugChrome.chromeMap.popup = null;
  9207. this.node.close();
  9208. },
  9209. persist: function()
  9210. {
  9211. persistTimeStart = new Date().getTime();
  9212. removeEvent(Firebug.browser.window, "unload", this.persist);
  9213. Firebug.Inspector.destroy();
  9214. Firebug.browser.window.FirebugOldBrowser = true;
  9215. var persistTimeStart = new Date().getTime();
  9216. var waitMainWindow = function()
  9217. {
  9218. var doc, head;
  9219. try
  9220. {
  9221. if (window.opener && !window.opener.FirebugOldBrowser && (doc = window.opener.document)/* &&
  9222. doc.documentElement && (head = doc.documentElement.firstChild)*/)
  9223. {
  9224. try
  9225. {
  9226. // exposes the FBL to the global namespace when in debug mode
  9227. if (Env.isDebugMode)
  9228. {
  9229. window.FBL = FBL;
  9230. }
  9231. window.Firebug = Firebug;
  9232. window.opener.Firebug = Firebug;
  9233. Env.browser = window.opener;
  9234. Firebug.browser = Firebug.context = new Context(Env.browser);
  9235. registerConsole();
  9236. // the delay time should be calculated right after registering the
  9237. // console, once right after the console registration, call log messages
  9238. // will be properly handled
  9239. var persistDelay = new Date().getTime() - persistTimeStart;
  9240. var chrome = Firebug.chrome;
  9241. addEvent(Firebug.browser.window, "unload", chrome.persist);
  9242. FBL.cacheDocument();
  9243. Firebug.Inspector.create();
  9244. var htmlPanel = chrome.getPanel("HTML");
  9245. htmlPanel.createUI();
  9246. Firebug.Console.logFormatted(
  9247. ["Firebug could not capture console calls during " +
  9248. persistDelay + "ms"],
  9249. Firebug.context,
  9250. "info"
  9251. );
  9252. }
  9253. catch(pE)
  9254. {
  9255. alert("persist error: " + (pE.message || pE));
  9256. }
  9257. }
  9258. else
  9259. {
  9260. window.setTimeout(waitMainWindow, 0);
  9261. }
  9262. } catch (E) {
  9263. window.close();
  9264. }
  9265. };
  9266. waitMainWindow();
  9267. },
  9268. close: function()
  9269. {
  9270. this.destroy();
  9271. }
  9272. });
  9273. //************************************************************************************************
  9274. // UI helpers
  9275. var changeCommandLineVisibility = function changeCommandLineVisibility(visibility)
  9276. {
  9277. var last = Firebug.chrome.commandLineVisible;
  9278. var visible = Firebug.chrome.commandLineVisible =
  9279. typeof visibility == "boolean" ? visibility : !Firebug.chrome.commandLineVisible;
  9280. if (visible != last)
  9281. {
  9282. if (visible)
  9283. {
  9284. fbBottom.className = "";
  9285. if (Firebug.CommandLine)
  9286. Firebug.CommandLine.activate();
  9287. }
  9288. else
  9289. {
  9290. if (Firebug.CommandLine)
  9291. Firebug.CommandLine.deactivate();
  9292. fbBottom.className = "hide";
  9293. }
  9294. }
  9295. };
  9296. var changeSidePanelVisibility = function changeSidePanelVisibility(visibility)
  9297. {
  9298. var last = Firebug.chrome.sidePanelVisible;
  9299. Firebug.chrome.sidePanelVisible =
  9300. typeof visibility == "boolean" ? visibility : !Firebug.chrome.sidePanelVisible;
  9301. if (Firebug.chrome.sidePanelVisible != last)
  9302. {
  9303. fbPanelBox2.className = Firebug.chrome.sidePanelVisible ? "" : "hide";
  9304. fbPanelBar2Box.className = Firebug.chrome.sidePanelVisible ? "" : "hide";
  9305. }
  9306. };
  9307. // ************************************************************************************************
  9308. // F12 Handler
  9309. var onGlobalKeyDown = function onGlobalKeyDown(event)
  9310. {
  9311. var keyCode = event.keyCode;
  9312. var shiftKey = event.shiftKey;
  9313. var ctrlKey = event.ctrlKey;
  9314. if (keyCode == 123 /* F12 */ && (!isFirefox && !shiftKey || shiftKey && isFirefox))
  9315. {
  9316. Firebug.chrome.toggle(false, ctrlKey);
  9317. cancelEvent(event, true);
  9318. // TODO: xxxpedro replace with a better solution. we're doing this
  9319. // to allow reactivating with the F12 key after being deactivated
  9320. if (Env.isChromeExtension)
  9321. {
  9322. Firebug.GoogleChrome.dispatch("FB_enableIcon");
  9323. }
  9324. }
  9325. else if (keyCode == 67 /* C */ && ctrlKey && shiftKey)
  9326. {
  9327. Firebug.Inspector.toggleInspect();
  9328. cancelEvent(event, true);
  9329. }
  9330. else if (keyCode == 76 /* L */ && ctrlKey && shiftKey)
  9331. {
  9332. Firebug.chrome.focusCommandLine();
  9333. cancelEvent(event, true);
  9334. }
  9335. };
  9336. var onMiniIconClick = function onMiniIconClick(event)
  9337. {
  9338. Firebug.chrome.toggle(false, event.ctrlKey);
  9339. cancelEvent(event, true);
  9340. };
  9341. // ************************************************************************************************
  9342. // Horizontal Splitter Handling
  9343. var onHSplitterMouseDown = function onHSplitterMouseDown(event)
  9344. {
  9345. addGlobalEvent("mousemove", onHSplitterMouseMove);
  9346. addGlobalEvent("mouseup", onHSplitterMouseUp);
  9347. if (isIE)
  9348. addEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp);
  9349. fbHSplitter.className = "fbOnMovingHSplitter";
  9350. return false;
  9351. };
  9352. var onHSplitterMouseMove = function onHSplitterMouseMove(event)
  9353. {
  9354. cancelEvent(event, true);
  9355. var clientY = event.clientY;
  9356. var win = isIE
  9357. ? event.srcElement.ownerDocument.parentWindow
  9358. : event.target.ownerDocument && event.target.ownerDocument.defaultView;
  9359. if (!win)
  9360. return;
  9361. if (win != win.parent)
  9362. {
  9363. var frameElement = win.frameElement;
  9364. if (frameElement)
  9365. {
  9366. var framePos = Firebug.browser.getElementPosition(frameElement).top;
  9367. clientY += framePos;
  9368. if (frameElement.style.position != "fixed")
  9369. clientY -= Firebug.browser.getWindowScrollPosition().top;
  9370. }
  9371. }
  9372. if (isOpera && isQuiksMode && win.frameElement.id == "FirebugUI")
  9373. {
  9374. clientY = Firebug.browser.getWindowSize().height - win.frameElement.offsetHeight + clientY;
  9375. }
  9376. /*
  9377. console.log(
  9378. typeof win.FBL != "undefined" ? "no-Chrome" : "Chrome",
  9379. //win.frameElement.id,
  9380. event.target,
  9381. clientY
  9382. );/**/
  9383. onHSplitterMouseMoveBuffer = clientY; // buffer
  9384. if (new Date().getTime() - lastHSplitterMouseMove > chromeRedrawSkipRate) // frame skipping
  9385. {
  9386. lastHSplitterMouseMove = new Date().getTime();
  9387. handleHSplitterMouseMove();
  9388. }
  9389. else
  9390. if (!onHSplitterMouseMoveTimer)
  9391. onHSplitterMouseMoveTimer = setTimeout(handleHSplitterMouseMove, chromeRedrawSkipRate);
  9392. // improving the resizing performance by canceling the mouse event.
  9393. // canceling events will prevent the page to receive such events, which would imply
  9394. // in more processing being expended.
  9395. cancelEvent(event, true);
  9396. return false;
  9397. };
  9398. var handleHSplitterMouseMove = function()
  9399. {
  9400. if (onHSplitterMouseMoveTimer)
  9401. {
  9402. clearTimeout(onHSplitterMouseMoveTimer);
  9403. onHSplitterMouseMoveTimer = null;
  9404. }
  9405. var clientY = onHSplitterMouseMoveBuffer;
  9406. var windowSize = Firebug.browser.getWindowSize();
  9407. var scrollSize = Firebug.browser.getWindowScrollSize();
  9408. // compute chrome fixed size (top bar and command line)
  9409. var commandLineHeight = Firebug.chrome.commandLineVisible ? fbCommandLine.offsetHeight : 0;
  9410. var fixedHeight = topHeight + commandLineHeight;
  9411. var chromeNode = Firebug.chrome.node;
  9412. var scrollbarSize = !isIE && (scrollSize.width > windowSize.width) ? 17 : 0;
  9413. //var height = !isOpera ? chromeNode.offsetTop + chromeNode.clientHeight : windowSize.height;
  9414. var height = windowSize.height;
  9415. // compute the min and max size of the chrome
  9416. var chromeHeight = Math.max(height - clientY + 5 - scrollbarSize, fixedHeight);
  9417. chromeHeight = Math.min(chromeHeight, windowSize.height - scrollbarSize);
  9418. FirebugChrome.height = chromeHeight;
  9419. chromeNode.style.height = chromeHeight + "px";
  9420. if (noFixedPosition)
  9421. Firebug.chrome.fixIEPosition();
  9422. Firebug.chrome.draw();
  9423. };
  9424. var onHSplitterMouseUp = function onHSplitterMouseUp(event)
  9425. {
  9426. removeGlobalEvent("mousemove", onHSplitterMouseMove);
  9427. removeGlobalEvent("mouseup", onHSplitterMouseUp);
  9428. if (isIE)
  9429. removeEvent(Firebug.browser.document.documentElement, "mouseleave", onHSplitterMouseUp);
  9430. fbHSplitter.className = "";
  9431. Firebug.chrome.draw();
  9432. // avoid text selection in IE when returning to the document
  9433. // after the mouse leaves the document during the resizing
  9434. return false;
  9435. };
  9436. // ************************************************************************************************
  9437. // Vertical Splitter Handling
  9438. var onVSplitterMouseDown = function onVSplitterMouseDown(event)
  9439. {
  9440. addGlobalEvent("mousemove", onVSplitterMouseMove);
  9441. addGlobalEvent("mouseup", onVSplitterMouseUp);
  9442. return false;
  9443. };
  9444. var onVSplitterMouseMove = function onVSplitterMouseMove(event)
  9445. {
  9446. if (new Date().getTime() - lastVSplitterMouseMove > chromeRedrawSkipRate) // frame skipping
  9447. {
  9448. var target = event.target || event.srcElement;
  9449. if (target && target.ownerDocument) // avoid error when cursor reaches out of the chrome
  9450. {
  9451. var clientX = event.clientX;
  9452. var win = document.all
  9453. ? event.srcElement.ownerDocument.parentWindow
  9454. : event.target.ownerDocument.defaultView;
  9455. if (win != win.parent)
  9456. clientX += win.frameElement ? win.frameElement.offsetLeft : 0;
  9457. var size = Firebug.chrome.getSize();
  9458. var x = Math.max(size.width - clientX + 3, 6);
  9459. FirebugChrome.sidePanelWidth = x;
  9460. Firebug.chrome.draw();
  9461. }
  9462. lastVSplitterMouseMove = new Date().getTime();
  9463. }
  9464. cancelEvent(event, true);
  9465. return false;
  9466. };
  9467. var onVSplitterMouseUp = function onVSplitterMouseUp(event)
  9468. {
  9469. removeGlobalEvent("mousemove", onVSplitterMouseMove);
  9470. removeGlobalEvent("mouseup", onVSplitterMouseUp);
  9471. Firebug.chrome.draw();
  9472. };
  9473. // ************************************************************************************************
  9474. }});
  9475. /* See license.txt for terms of usage */
  9476. FBL.ns(function() { with (FBL) {
  9477. // ************************************************************************************************
  9478. Firebug.Lite =
  9479. {
  9480. };
  9481. // ************************************************************************************************
  9482. }});
  9483. /* See license.txt for terms of usage */
  9484. FBL.ns(function() { with (FBL) {
  9485. // ************************************************************************************************
  9486. Firebug.Lite.Browser = function(window)
  9487. {
  9488. this.contentWindow = window;
  9489. this.contentDocument = window.document;
  9490. this.currentURI =
  9491. {
  9492. spec: window.location.href
  9493. };
  9494. };
  9495. Firebug.Lite.Browser.prototype =
  9496. {
  9497. toString: function()
  9498. {
  9499. return "Firebug.Lite.Browser";
  9500. }
  9501. };
  9502. // ************************************************************************************************
  9503. }});
  9504. /* See license.txt for terms of usage */
  9505. FBL.ns(function() { with (FBL) {
  9506. // ************************************************************************************************
  9507. Firebug.Lite.Cache =
  9508. {
  9509. ID: "firebug" + new Date().getTime()
  9510. };
  9511. // ************************************************************************************************
  9512. /**
  9513. * TODO: if a cached element is cloned, the expando property will be cloned too in IE
  9514. * which will result in a bug. Firebug Lite will think the new cloned node is the old
  9515. * one.
  9516. *
  9517. * TODO: Investigate a possibility of cache validation, to be customized by each
  9518. * kind of cache. For ElementCache it should validate if the element still is
  9519. * inserted at the DOM.
  9520. */
  9521. var cacheUID = 0;
  9522. var createCache = function()
  9523. {
  9524. var map = {};
  9525. var CID = Firebug.Lite.Cache.ID;
  9526. // better detection
  9527. var supportsDeleteExpando = !document.all;
  9528. var cacheFunction = function(element)
  9529. {
  9530. return cacheAPI.set(element);
  9531. };
  9532. var cacheAPI =
  9533. {
  9534. get: function(key)
  9535. {
  9536. return map.hasOwnProperty(key) ?
  9537. map[key] :
  9538. null;
  9539. },
  9540. set: function(element)
  9541. {
  9542. var id = element[CID];
  9543. if (!id)
  9544. {
  9545. id = ++cacheUID;
  9546. element[CID] = id;
  9547. }
  9548. if (!map.hasOwnProperty(id))
  9549. {
  9550. map[id] = element;
  9551. }
  9552. return id;
  9553. },
  9554. unset: function(element)
  9555. {
  9556. var id = element[CID];
  9557. if (supportsDeleteExpando)
  9558. {
  9559. delete element[CID];
  9560. }
  9561. else if (element.removeAttribute)
  9562. {
  9563. element.removeAttribute(CID);
  9564. }
  9565. delete map[id];
  9566. },
  9567. key: function(element)
  9568. {
  9569. return element[CID];
  9570. },
  9571. has: function(element)
  9572. {
  9573. return map.hasOwnProperty(element[CID]);
  9574. },
  9575. clear: function()
  9576. {
  9577. for (var id in map)
  9578. {
  9579. var element = map[id];
  9580. cacheAPI.unset(element);
  9581. }
  9582. }
  9583. };
  9584. FBL.append(cacheFunction, cacheAPI);
  9585. return cacheFunction;
  9586. };
  9587. // ************************************************************************************************
  9588. // TODO: xxxpedro : check if we need really this on FBL scope
  9589. Firebug.Lite.Cache.StyleSheet = createCache();
  9590. Firebug.Lite.Cache.Element = createCache();
  9591. // ************************************************************************************************
  9592. }});
  9593. /* See license.txt for terms of usage */
  9594. FBL.ns(function() { with (FBL) {
  9595. // ************************************************************************************************
  9596. Firebug.Lite.Proxy =
  9597. {
  9598. // jsonp callbacks
  9599. _callbacks: {},
  9600. /**
  9601. * Load a resource, either locally (directly) or externally (via proxy) using
  9602. * synchronous XHR calls. Loading external resources requires the proxy plugin to
  9603. * be installed and configured (see /plugin/proxy/proxy.php).
  9604. */
  9605. load: function(url)
  9606. {
  9607. var resourceDomain = getDomain(url);
  9608. var isLocalResource =
  9609. // empty domain means local URL
  9610. !resourceDomain ||
  9611. // same domain means local too
  9612. resourceDomain == Firebug.context.window.location.host; // TODO: xxxpedro context
  9613. return isLocalResource ? fetchResource(url) : fetchProxyResource(url);
  9614. },
  9615. /**
  9616. * Load a resource using JSONP technique.
  9617. */
  9618. loadJSONP: function(url, callback)
  9619. {
  9620. var script = createGlobalElement("script"),
  9621. doc = Firebug.context.document,
  9622. uid = "" + new Date().getTime(),
  9623. callbackName = "callback=Firebug.Lite.Proxy._callbacks." + uid,
  9624. jsonpURL = url.indexOf("?") != -1 ?
  9625. url + "&" + callbackName :
  9626. url + "?" + callbackName;
  9627. Firebug.Lite.Proxy._callbacks[uid] = function(data)
  9628. {
  9629. if (callback)
  9630. callback(data);
  9631. script.parentNode.removeChild(script);
  9632. delete Firebug.Lite.Proxy._callbacks[uid];
  9633. };
  9634. script.src = jsonpURL;
  9635. if (doc.documentElement)
  9636. doc.documentElement.appendChild(script);
  9637. },
  9638. /**
  9639. * Load a resource using YQL (not reliable).
  9640. */
  9641. YQL: function(url, callback)
  9642. {
  9643. var yql = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22" +
  9644. encodeURIComponent(url) + "%22&format=xml";
  9645. this.loadJSONP(yql, function(data)
  9646. {
  9647. var source = data.results[0];
  9648. // clean up YQL bogus elements
  9649. var match = /<body>\s+<p>([\s\S]+)<\/p>\s+<\/body>$/.exec(source);
  9650. if (match)
  9651. source = match[1];
  9652. console.log(source);
  9653. });
  9654. }
  9655. };
  9656. // ************************************************************************************************
  9657. var fetchResource = function(url)
  9658. {
  9659. var xhr = FBL.Ajax.getXHRObject();
  9660. xhr.open("get", url, false);
  9661. xhr.send();
  9662. return xhr.responseText;
  9663. };
  9664. var fetchProxyResource = function(url)
  9665. {
  9666. var proxyURL = Env.Location.baseDir + "plugin/proxy/proxy.php?url=" + encodeURIComponent(url);
  9667. var response = fetchResource(proxyURL);
  9668. try
  9669. {
  9670. var data = eval("(" + response + ")");
  9671. }
  9672. catch(E)
  9673. {
  9674. return "ERROR: Firebug Lite Proxy plugin returned an invalid response.";
  9675. }
  9676. return data ? data.contents : "";
  9677. };
  9678. // ************************************************************************************************
  9679. }});
  9680. /* See license.txt for terms of usage */
  9681. FBL.ns(function() { with (FBL) {
  9682. // ************************************************************************************************
  9683. Firebug.Lite.Script = function(window)
  9684. {
  9685. this.fileName = null;
  9686. this.isValid = null;
  9687. this.baseLineNumber = null;
  9688. this.lineExtent = null;
  9689. this.tag = null;
  9690. this.functionName = null;
  9691. this.functionSource = null;
  9692. };
  9693. Firebug.Lite.Script.prototype =
  9694. {
  9695. isLineExecutable: function(){},
  9696. pcToLine: function(){},
  9697. lineToPc: function(){},
  9698. toString: function()
  9699. {
  9700. return "Firebug.Lite.Script";
  9701. }
  9702. };
  9703. // ************************************************************************************************
  9704. }});
  9705. /* See license.txt for terms of usage */
  9706. FBL.ns(function() { with (FBL) {
  9707. // ************************************************************************************************
  9708. Firebug.Lite.Style =
  9709. {
  9710. };
  9711. // ************************************************************************************************
  9712. }});
  9713. /* See license.txt for terms of usage */
  9714. FBL.ns( /**@scope ns-selector*/ function() { with (FBL) {
  9715. // ************************************************************************************************
  9716. /*
  9717. * Sizzle CSS Selector Engine - v1.0
  9718. * Copyright 2009, The Dojo Foundation
  9719. * Released under the MIT, BSD, and GPL Licenses.
  9720. * More information: http://sizzlejs.com/
  9721. */
  9722. var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
  9723. done = 0,
  9724. toString = Object.prototype.toString,
  9725. hasDuplicate = false,
  9726. baseHasDuplicate = true;
  9727. // Here we check if the JavaScript engine is using some sort of
  9728. // optimization where it does not always call our comparision
  9729. // function. If that is the case, discard the hasDuplicate value.
  9730. // Thus far that includes Google Chrome.
  9731. [0, 0].sort(function(){
  9732. baseHasDuplicate = false;
  9733. return 0;
  9734. });
  9735. /**
  9736. * @name Firebug.Selector
  9737. * @namespace
  9738. */
  9739. /**
  9740. * @exports Sizzle as Firebug.Selector
  9741. */
  9742. var Sizzle = function(selector, context, results, seed) {
  9743. results = results || [];
  9744. var origContext = context = context || document;
  9745. if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
  9746. return [];
  9747. }
  9748. if ( !selector || typeof selector !== "string" ) {
  9749. return results;
  9750. }
  9751. var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context),
  9752. soFar = selector;
  9753. // Reset the position of the chunker regexp (start from head)
  9754. while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
  9755. soFar = m[3];
  9756. parts.push( m[1] );
  9757. if ( m[2] ) {
  9758. extra = m[3];
  9759. break;
  9760. }
  9761. }
  9762. if ( parts.length > 1 && origPOS.exec( selector ) ) {
  9763. if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
  9764. set = posProcess( parts[0] + parts[1], context );
  9765. } else {
  9766. set = Expr.relative[ parts[0] ] ?
  9767. [ context ] :
  9768. Sizzle( parts.shift(), context );
  9769. while ( parts.length ) {
  9770. selector = parts.shift();
  9771. if ( Expr.relative[ selector ] )
  9772. selector += parts.shift();
  9773. set = posProcess( selector, set );
  9774. }
  9775. }
  9776. } else {
  9777. // Take a shortcut and set the context if the root selector is an ID
  9778. // (but not if it'll be faster if the inner selector is an ID)
  9779. if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
  9780. Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
  9781. var ret = Sizzle.find( parts.shift(), context, contextXML );
  9782. context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
  9783. }
  9784. if ( context ) {
  9785. var ret = seed ?
  9786. { expr: parts.pop(), set: makeArray(seed) } :
  9787. Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
  9788. set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
  9789. if ( parts.length > 0 ) {
  9790. checkSet = makeArray(set);
  9791. } else {
  9792. prune = false;
  9793. }
  9794. while ( parts.length ) {
  9795. var cur = parts.pop(), pop = cur;
  9796. if ( !Expr.relative[ cur ] ) {
  9797. cur = "";
  9798. } else {
  9799. pop = parts.pop();
  9800. }
  9801. if ( pop == null ) {
  9802. pop = context;
  9803. }
  9804. Expr.relative[ cur ]( checkSet, pop, contextXML );
  9805. }
  9806. } else {
  9807. checkSet = parts = [];
  9808. }
  9809. }
  9810. if ( !checkSet ) {
  9811. checkSet = set;
  9812. }
  9813. if ( !checkSet ) {
  9814. throw "Syntax error, unrecognized expression: " + (cur || selector);
  9815. }
  9816. if ( toString.call(checkSet) === "[object Array]" ) {
  9817. if ( !prune ) {
  9818. results.push.apply( results, checkSet );
  9819. } else if ( context && context.nodeType === 1 ) {
  9820. for ( var i = 0; checkSet[i] != null; i++ ) {
  9821. if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
  9822. results.push( set[i] );
  9823. }
  9824. }
  9825. } else {
  9826. for ( var i = 0; checkSet[i] != null; i++ ) {
  9827. if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
  9828. results.push( set[i] );
  9829. }
  9830. }
  9831. }
  9832. } else {
  9833. makeArray( checkSet, results );
  9834. }
  9835. if ( extra ) {
  9836. Sizzle( extra, origContext, results, seed );
  9837. Sizzle.uniqueSort( results );
  9838. }
  9839. return results;
  9840. };
  9841. Sizzle.uniqueSort = function(results){
  9842. if ( sortOrder ) {
  9843. hasDuplicate = baseHasDuplicate;
  9844. results.sort(sortOrder);
  9845. if ( hasDuplicate ) {
  9846. for ( var i = 1; i < results.length; i++ ) {
  9847. if ( results[i] === results[i-1] ) {
  9848. results.splice(i--, 1);
  9849. }
  9850. }
  9851. }
  9852. }
  9853. return results;
  9854. };
  9855. Sizzle.matches = function(expr, set){
  9856. return Sizzle(expr, null, null, set);
  9857. };
  9858. Sizzle.find = function(expr, context, isXML){
  9859. var set, match;
  9860. if ( !expr ) {
  9861. return [];
  9862. }
  9863. for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
  9864. var type = Expr.order[i], match;
  9865. if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
  9866. var left = match[1];
  9867. match.splice(1,1);
  9868. if ( left.substr( left.length - 1 ) !== "\\" ) {
  9869. match[1] = (match[1] || "").replace(/\\/g, "");
  9870. set = Expr.find[ type ]( match, context, isXML );
  9871. if ( set != null ) {
  9872. expr = expr.replace( Expr.match[ type ], "" );
  9873. break;
  9874. }
  9875. }
  9876. }
  9877. }
  9878. if ( !set ) {
  9879. set = context.getElementsByTagName("*");
  9880. }
  9881. return {set: set, expr: expr};
  9882. };
  9883. Sizzle.filter = function(expr, set, inplace, not){
  9884. var old = expr, result = [], curLoop = set, match, anyFound,
  9885. isXMLFilter = set && set[0] && isXML(set[0]);
  9886. while ( expr && set.length ) {
  9887. for ( var type in Expr.filter ) {
  9888. if ( (match = Expr.match[ type ].exec( expr )) != null ) {
  9889. var filter = Expr.filter[ type ], found, item;
  9890. anyFound = false;
  9891. if ( curLoop == result ) {
  9892. result = [];
  9893. }
  9894. if ( Expr.preFilter[ type ] ) {
  9895. match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
  9896. if ( !match ) {
  9897. anyFound = found = true;
  9898. } else if ( match === true ) {
  9899. continue;
  9900. }
  9901. }
  9902. if ( match ) {
  9903. for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
  9904. if ( item ) {
  9905. found = filter( item, match, i, curLoop );
  9906. var pass = not ^ !!found;
  9907. if ( inplace && found != null ) {
  9908. if ( pass ) {
  9909. anyFound = true;
  9910. } else {
  9911. curLoop[i] = false;
  9912. }
  9913. } else if ( pass ) {
  9914. result.push( item );
  9915. anyFound = true;
  9916. }
  9917. }
  9918. }
  9919. }
  9920. if ( found !== undefined ) {
  9921. if ( !inplace ) {
  9922. curLoop = result;
  9923. }
  9924. expr = expr.replace( Expr.match[ type ], "" );
  9925. if ( !anyFound ) {
  9926. return [];
  9927. }
  9928. break;
  9929. }
  9930. }
  9931. }
  9932. // Improper expression
  9933. if ( expr == old ) {
  9934. if ( anyFound == null ) {
  9935. throw "Syntax error, unrecognized expression: " + expr;
  9936. } else {
  9937. break;
  9938. }
  9939. }
  9940. old = expr;
  9941. }
  9942. return curLoop;
  9943. };
  9944. /**#@+ @ignore */
  9945. var Expr = Sizzle.selectors = {
  9946. order: [ "ID", "NAME", "TAG" ],
  9947. match: {
  9948. ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
  9949. CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
  9950. NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
  9951. ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
  9952. TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
  9953. CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
  9954. POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
  9955. PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
  9956. },
  9957. leftMatch: {},
  9958. attrMap: {
  9959. "class": "className",
  9960. "for": "htmlFor"
  9961. },
  9962. attrHandle: {
  9963. href: function(elem){
  9964. return elem.getAttribute("href");
  9965. }
  9966. },
  9967. relative: {
  9968. "+": function(checkSet, part, isXML){
  9969. var isPartStr = typeof part === "string",
  9970. isTag = isPartStr && !/\W/.test(part),
  9971. isPartStrNotTag = isPartStr && !isTag;
  9972. if ( isTag && !isXML ) {
  9973. part = part.toUpperCase();
  9974. }
  9975. for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
  9976. if ( (elem = checkSet[i]) ) {
  9977. while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
  9978. checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ?
  9979. elem || false :
  9980. elem === part;
  9981. }
  9982. }
  9983. if ( isPartStrNotTag ) {
  9984. Sizzle.filter( part, checkSet, true );
  9985. }
  9986. },
  9987. ">": function(checkSet, part, isXML){
  9988. var isPartStr = typeof part === "string";
  9989. if ( isPartStr && !/\W/.test(part) ) {
  9990. part = isXML ? part : part.toUpperCase();
  9991. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  9992. var elem = checkSet[i];
  9993. if ( elem ) {
  9994. var parent = elem.parentNode;
  9995. checkSet[i] = parent.nodeName === part ? parent : false;
  9996. }
  9997. }
  9998. } else {
  9999. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  10000. var elem = checkSet[i];
  10001. if ( elem ) {
  10002. checkSet[i] = isPartStr ?
  10003. elem.parentNode :
  10004. elem.parentNode === part;
  10005. }
  10006. }
  10007. if ( isPartStr ) {
  10008. Sizzle.filter( part, checkSet, true );
  10009. }
  10010. }
  10011. },
  10012. "": function(checkSet, part, isXML){
  10013. var doneName = done++, checkFn = dirCheck;
  10014. if ( !/\W/.test(part) ) {
  10015. var nodeCheck = part = isXML ? part : part.toUpperCase();
  10016. checkFn = dirNodeCheck;
  10017. }
  10018. checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
  10019. },
  10020. "~": function(checkSet, part, isXML){
  10021. var doneName = done++, checkFn = dirCheck;
  10022. if ( typeof part === "string" && !/\W/.test(part) ) {
  10023. var nodeCheck = part = isXML ? part : part.toUpperCase();
  10024. checkFn = dirNodeCheck;
  10025. }
  10026. checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
  10027. }
  10028. },
  10029. find: {
  10030. ID: function(match, context, isXML){
  10031. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  10032. var m = context.getElementById(match[1]);
  10033. return m ? [m] : [];
  10034. }
  10035. },
  10036. NAME: function(match, context, isXML){
  10037. if ( typeof context.getElementsByName !== "undefined" ) {
  10038. var ret = [], results = context.getElementsByName(match[1]);
  10039. for ( var i = 0, l = results.length; i < l; i++ ) {
  10040. if ( results[i].getAttribute("name") === match[1] ) {
  10041. ret.push( results[i] );
  10042. }
  10043. }
  10044. return ret.length === 0 ? null : ret;
  10045. }
  10046. },
  10047. TAG: function(match, context){
  10048. return context.getElementsByTagName(match[1]);
  10049. }
  10050. },
  10051. preFilter: {
  10052. CLASS: function(match, curLoop, inplace, result, not, isXML){
  10053. match = " " + match[1].replace(/\\/g, "") + " ";
  10054. if ( isXML ) {
  10055. return match;
  10056. }
  10057. for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
  10058. if ( elem ) {
  10059. if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) {
  10060. if ( !inplace )
  10061. result.push( elem );
  10062. } else if ( inplace ) {
  10063. curLoop[i] = false;
  10064. }
  10065. }
  10066. }
  10067. return false;
  10068. },
  10069. ID: function(match){
  10070. return match[1].replace(/\\/g, "");
  10071. },
  10072. TAG: function(match, curLoop){
  10073. for ( var i = 0; curLoop[i] === false; i++ ){}
  10074. return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
  10075. },
  10076. CHILD: function(match){
  10077. if ( match[1] == "nth" ) {
  10078. // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
  10079. var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
  10080. match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
  10081. !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
  10082. // calculate the numbers (first)n+(last) including if they are negative
  10083. match[2] = (test[1] + (test[2] || 1)) - 0;
  10084. match[3] = test[3] - 0;
  10085. }
  10086. // TODO: Move to normal caching system
  10087. match[0] = done++;
  10088. return match;
  10089. },
  10090. ATTR: function(match, curLoop, inplace, result, not, isXML){
  10091. var name = match[1].replace(/\\/g, "");
  10092. if ( !isXML && Expr.attrMap[name] ) {
  10093. match[1] = Expr.attrMap[name];
  10094. }
  10095. if ( match[2] === "~=" ) {
  10096. match[4] = " " + match[4] + " ";
  10097. }
  10098. return match;
  10099. },
  10100. PSEUDO: function(match, curLoop, inplace, result, not){
  10101. if ( match[1] === "not" ) {
  10102. // If we're dealing with a complex expression, or a simple one
  10103. if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
  10104. match[3] = Sizzle(match[3], null, null, curLoop);
  10105. } else {
  10106. var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
  10107. if ( !inplace ) {
  10108. result.push.apply( result, ret );
  10109. }
  10110. return false;
  10111. }
  10112. } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
  10113. return true;
  10114. }
  10115. return match;
  10116. },
  10117. POS: function(match){
  10118. match.unshift( true );
  10119. return match;
  10120. }
  10121. },
  10122. filters: {
  10123. enabled: function(elem){
  10124. return elem.disabled === false && elem.type !== "hidden";
  10125. },
  10126. disabled: function(elem){
  10127. return elem.disabled === true;
  10128. },
  10129. checked: function(elem){
  10130. return elem.checked === true;
  10131. },
  10132. selected: function(elem){
  10133. // Accessing this property makes selected-by-default
  10134. // options in Safari work properly
  10135. elem.parentNode.selectedIndex;
  10136. return elem.selected === true;
  10137. },
  10138. parent: function(elem){
  10139. return !!elem.firstChild;
  10140. },
  10141. empty: function(elem){
  10142. return !elem.firstChild;
  10143. },
  10144. has: function(elem, i, match){
  10145. return !!Sizzle( match[3], elem ).length;
  10146. },
  10147. header: function(elem){
  10148. return /h\d/i.test( elem.nodeName );
  10149. },
  10150. text: function(elem){
  10151. return "text" === elem.type;
  10152. },
  10153. radio: function(elem){
  10154. return "radio" === elem.type;
  10155. },
  10156. checkbox: function(elem){
  10157. return "checkbox" === elem.type;
  10158. },
  10159. file: function(elem){
  10160. return "file" === elem.type;
  10161. },
  10162. password: function(elem){
  10163. return "password" === elem.type;
  10164. },
  10165. submit: function(elem){
  10166. return "submit" === elem.type;
  10167. },
  10168. image: function(elem){
  10169. return "image" === elem.type;
  10170. },
  10171. reset: function(elem){
  10172. return "reset" === elem.type;
  10173. },
  10174. button: function(elem){
  10175. return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
  10176. },
  10177. input: function(elem){
  10178. return /input|select|textarea|button/i.test(elem.nodeName);
  10179. }
  10180. },
  10181. setFilters: {
  10182. first: function(elem, i){
  10183. return i === 0;
  10184. },
  10185. last: function(elem, i, match, array){
  10186. return i === array.length - 1;
  10187. },
  10188. even: function(elem, i){
  10189. return i % 2 === 0;
  10190. },
  10191. odd: function(elem, i){
  10192. return i % 2 === 1;
  10193. },
  10194. lt: function(elem, i, match){
  10195. return i < match[3] - 0;
  10196. },
  10197. gt: function(elem, i, match){
  10198. return i > match[3] - 0;
  10199. },
  10200. nth: function(elem, i, match){
  10201. return match[3] - 0 == i;
  10202. },
  10203. eq: function(elem, i, match){
  10204. return match[3] - 0 == i;
  10205. }
  10206. },
  10207. filter: {
  10208. PSEUDO: function(elem, match, i, array){
  10209. var name = match[1], filter = Expr.filters[ name ];
  10210. if ( filter ) {
  10211. return filter( elem, i, match, array );
  10212. } else if ( name === "contains" ) {
  10213. return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
  10214. } else if ( name === "not" ) {
  10215. var not = match[3];
  10216. for ( var i = 0, l = not.length; i < l; i++ ) {
  10217. if ( not[i] === elem ) {
  10218. return false;
  10219. }
  10220. }
  10221. return true;
  10222. }
  10223. },
  10224. CHILD: function(elem, match){
  10225. var type = match[1], node = elem;
  10226. switch (type) {
  10227. case 'only':
  10228. case 'first':
  10229. while ( (node = node.previousSibling) ) {
  10230. if ( node.nodeType === 1 ) return false;
  10231. }
  10232. if ( type == 'first') return true;
  10233. node = elem;
  10234. case 'last':
  10235. while ( (node = node.nextSibling) ) {
  10236. if ( node.nodeType === 1 ) return false;
  10237. }
  10238. return true;
  10239. case 'nth':
  10240. var first = match[2], last = match[3];
  10241. if ( first == 1 && last == 0 ) {
  10242. return true;
  10243. }
  10244. var doneName = match[0],
  10245. parent = elem.parentNode;
  10246. if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
  10247. var count = 0;
  10248. for ( node = parent.firstChild; node; node = node.nextSibling ) {
  10249. if ( node.nodeType === 1 ) {
  10250. node.nodeIndex = ++count;
  10251. }
  10252. }
  10253. parent.sizcache = doneName;
  10254. }
  10255. var diff = elem.nodeIndex - last;
  10256. if ( first == 0 ) {
  10257. return diff == 0;
  10258. } else {
  10259. return ( diff % first == 0 && diff / first >= 0 );
  10260. }
  10261. }
  10262. },
  10263. ID: function(elem, match){
  10264. return elem.nodeType === 1 && elem.getAttribute("id") === match;
  10265. },
  10266. TAG: function(elem, match){
  10267. return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
  10268. },
  10269. CLASS: function(elem, match){
  10270. return (" " + (elem.className || elem.getAttribute("class")) + " ")
  10271. .indexOf( match ) > -1;
  10272. },
  10273. ATTR: function(elem, match){
  10274. var name = match[1],
  10275. result = Expr.attrHandle[ name ] ?
  10276. Expr.attrHandle[ name ]( elem ) :
  10277. elem[ name ] != null ?
  10278. elem[ name ] :
  10279. elem.getAttribute( name ),
  10280. value = result + "",
  10281. type = match[2],
  10282. check = match[4];
  10283. return result == null ?
  10284. type === "!=" :
  10285. type === "=" ?
  10286. value === check :
  10287. type === "*=" ?
  10288. value.indexOf(check) >= 0 :
  10289. type === "~=" ?
  10290. (" " + value + " ").indexOf(check) >= 0 :
  10291. !check ?
  10292. value && result !== false :
  10293. type === "!=" ?
  10294. value != check :
  10295. type === "^=" ?
  10296. value.indexOf(check) === 0 :
  10297. type === "$=" ?
  10298. value.substr(value.length - check.length) === check :
  10299. type === "|=" ?
  10300. value === check || value.substr(0, check.length + 1) === check + "-" :
  10301. false;
  10302. },
  10303. POS: function(elem, match, i, array){
  10304. var name = match[2], filter = Expr.setFilters[ name ];
  10305. if ( filter ) {
  10306. return filter( elem, i, match, array );
  10307. }
  10308. }
  10309. }
  10310. };
  10311. var origPOS = Expr.match.POS;
  10312. for ( var type in Expr.match ) {
  10313. Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
  10314. Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source );
  10315. }
  10316. var makeArray = function(array, results) {
  10317. array = Array.prototype.slice.call( array, 0 );
  10318. if ( results ) {
  10319. results.push.apply( results, array );
  10320. return results;
  10321. }
  10322. return array;
  10323. };
  10324. // Perform a simple check to determine if the browser is capable of
  10325. // converting a NodeList to an array using builtin methods.
  10326. try {
  10327. Array.prototype.slice.call( document.documentElement.childNodes, 0 );
  10328. // Provide a fallback method if it does not work
  10329. } catch(e){
  10330. makeArray = function(array, results) {
  10331. var ret = results || [];
  10332. if ( toString.call(array) === "[object Array]" ) {
  10333. Array.prototype.push.apply( ret, array );
  10334. } else {
  10335. if ( typeof array.length === "number" ) {
  10336. for ( var i = 0, l = array.length; i < l; i++ ) {
  10337. ret.push( array[i] );
  10338. }
  10339. } else {
  10340. for ( var i = 0; array[i]; i++ ) {
  10341. ret.push( array[i] );
  10342. }
  10343. }
  10344. }
  10345. return ret;
  10346. };
  10347. }
  10348. var sortOrder;
  10349. if ( document.documentElement.compareDocumentPosition ) {
  10350. sortOrder = function( a, b ) {
  10351. if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
  10352. if ( a == b ) {
  10353. hasDuplicate = true;
  10354. }
  10355. return 0;
  10356. }
  10357. var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
  10358. if ( ret === 0 ) {
  10359. hasDuplicate = true;
  10360. }
  10361. return ret;
  10362. };
  10363. } else if ( "sourceIndex" in document.documentElement ) {
  10364. sortOrder = function( a, b ) {
  10365. if ( !a.sourceIndex || !b.sourceIndex ) {
  10366. if ( a == b ) {
  10367. hasDuplicate = true;
  10368. }
  10369. return 0;
  10370. }
  10371. var ret = a.sourceIndex - b.sourceIndex;
  10372. if ( ret === 0 ) {
  10373. hasDuplicate = true;
  10374. }
  10375. return ret;
  10376. };
  10377. } else if ( document.createRange ) {
  10378. sortOrder = function( a, b ) {
  10379. if ( !a.ownerDocument || !b.ownerDocument ) {
  10380. if ( a == b ) {
  10381. hasDuplicate = true;
  10382. }
  10383. return 0;
  10384. }
  10385. var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
  10386. aRange.setStart(a, 0);
  10387. aRange.setEnd(a, 0);
  10388. bRange.setStart(b, 0);
  10389. bRange.setEnd(b, 0);
  10390. var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
  10391. if ( ret === 0 ) {
  10392. hasDuplicate = true;
  10393. }
  10394. return ret;
  10395. };
  10396. }
  10397. // Check to see if the browser returns elements by name when
  10398. // querying by getElementById (and provide a workaround)
  10399. (function(){
  10400. // We're going to inject a fake input element with a specified name
  10401. var form = document.createElement("div"),
  10402. id = "script" + (new Date).getTime();
  10403. form.innerHTML = "<a name='" + id + "'/>";
  10404. // Inject it into the root element, check its status, and remove it quickly
  10405. var root = document.documentElement;
  10406. root.insertBefore( form, root.firstChild );
  10407. // The workaround has to do additional checks after a getElementById
  10408. // Which slows things down for other browsers (hence the branching)
  10409. if ( !!document.getElementById( id ) ) {
  10410. Expr.find.ID = function(match, context, isXML){
  10411. if ( typeof context.getElementById !== "undefined" && !isXML ) {
  10412. var m = context.getElementById(match[1]);
  10413. return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
  10414. }
  10415. };
  10416. Expr.filter.ID = function(elem, match){
  10417. var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
  10418. return elem.nodeType === 1 && node && node.nodeValue === match;
  10419. };
  10420. }
  10421. root.removeChild( form );
  10422. root = form = null; // release memory in IE
  10423. })();
  10424. (function(){
  10425. // Check to see if the browser returns only elements
  10426. // when doing getElementsByTagName("*")
  10427. // Create a fake element
  10428. var div = document.createElement("div");
  10429. div.appendChild( document.createComment("") );
  10430. // Make sure no comments are found
  10431. if ( div.getElementsByTagName("*").length > 0 ) {
  10432. Expr.find.TAG = function(match, context){
  10433. var results = context.getElementsByTagName(match[1]);
  10434. // Filter out possible comments
  10435. if ( match[1] === "*" ) {
  10436. var tmp = [];
  10437. for ( var i = 0; results[i]; i++ ) {
  10438. if ( results[i].nodeType === 1 ) {
  10439. tmp.push( results[i] );
  10440. }
  10441. }
  10442. results = tmp;
  10443. }
  10444. return results;
  10445. };
  10446. }
  10447. // Check to see if an attribute returns normalized href attributes
  10448. div.innerHTML = "<a href='#'></a>";
  10449. if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
  10450. div.firstChild.getAttribute("href") !== "#" ) {
  10451. Expr.attrHandle.href = function(elem){
  10452. return elem.getAttribute("href", 2);
  10453. };
  10454. }
  10455. div = null; // release memory in IE
  10456. })();
  10457. if ( document.querySelectorAll ) (function(){
  10458. var oldSizzle = Sizzle, div = document.createElement("div");
  10459. div.innerHTML = "<p class='TEST'></p>";
  10460. // Safari can't handle uppercase or unicode characters when
  10461. // in quirks mode.
  10462. if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
  10463. return;
  10464. }
  10465. Sizzle = function(query, context, extra, seed){
  10466. context = context || document;
  10467. // Only use querySelectorAll on non-XML documents
  10468. // (ID selectors don't work in non-HTML documents)
  10469. if ( !seed && context.nodeType === 9 && !isXML(context) ) {
  10470. try {
  10471. return makeArray( context.querySelectorAll(query), extra );
  10472. } catch(e){}
  10473. }
  10474. return oldSizzle(query, context, extra, seed);
  10475. };
  10476. for ( var prop in oldSizzle ) {
  10477. Sizzle[ prop ] = oldSizzle[ prop ];
  10478. }
  10479. div = null; // release memory in IE
  10480. })();
  10481. if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){
  10482. var div = document.createElement("div");
  10483. div.innerHTML = "<div class='test e'></div><div class='test'></div>";
  10484. // Opera can't find a second classname (in 9.6)
  10485. if ( div.getElementsByClassName("e").length === 0 )
  10486. return;
  10487. // Safari caches class attributes, doesn't catch changes (in 3.2)
  10488. div.lastChild.className = "e";
  10489. if ( div.getElementsByClassName("e").length === 1 )
  10490. return;
  10491. Expr.order.splice(1, 0, "CLASS");
  10492. Expr.find.CLASS = function(match, context, isXML) {
  10493. if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
  10494. return context.getElementsByClassName(match[1]);
  10495. }
  10496. };
  10497. div = null; // release memory in IE
  10498. })();
  10499. function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  10500. var sibDir = dir == "previousSibling" && !isXML;
  10501. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  10502. var elem = checkSet[i];
  10503. if ( elem ) {
  10504. if ( sibDir && elem.nodeType === 1 ){
  10505. elem.sizcache = doneName;
  10506. elem.sizset = i;
  10507. }
  10508. elem = elem[dir];
  10509. var match = false;
  10510. while ( elem ) {
  10511. if ( elem.sizcache === doneName ) {
  10512. match = checkSet[elem.sizset];
  10513. break;
  10514. }
  10515. if ( elem.nodeType === 1 && !isXML ){
  10516. elem.sizcache = doneName;
  10517. elem.sizset = i;
  10518. }
  10519. if ( elem.nodeName === cur ) {
  10520. match = elem;
  10521. break;
  10522. }
  10523. elem = elem[dir];
  10524. }
  10525. checkSet[i] = match;
  10526. }
  10527. }
  10528. }
  10529. function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
  10530. var sibDir = dir == "previousSibling" && !isXML;
  10531. for ( var i = 0, l = checkSet.length; i < l; i++ ) {
  10532. var elem = checkSet[i];
  10533. if ( elem ) {
  10534. if ( sibDir && elem.nodeType === 1 ) {
  10535. elem.sizcache = doneName;
  10536. elem.sizset = i;
  10537. }
  10538. elem = elem[dir];
  10539. var match = false;
  10540. while ( elem ) {
  10541. if ( elem.sizcache === doneName ) {
  10542. match = checkSet[elem.sizset];
  10543. break;
  10544. }
  10545. if ( elem.nodeType === 1 ) {
  10546. if ( !isXML ) {
  10547. elem.sizcache = doneName;
  10548. elem.sizset = i;
  10549. }
  10550. if ( typeof cur !== "string" ) {
  10551. if ( elem === cur ) {
  10552. match = true;
  10553. break;
  10554. }
  10555. } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
  10556. match = elem;
  10557. break;
  10558. }
  10559. }
  10560. elem = elem[dir];
  10561. }
  10562. checkSet[i] = match;
  10563. }
  10564. }
  10565. }
  10566. var contains = document.compareDocumentPosition ? function(a, b){
  10567. return a.compareDocumentPosition(b) & 16;
  10568. } : function(a, b){
  10569. return a !== b && (a.contains ? a.contains(b) : true);
  10570. };
  10571. var isXML = function(elem){
  10572. return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
  10573. !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
  10574. };
  10575. var posProcess = function(selector, context){
  10576. var tmpSet = [], later = "", match,
  10577. root = context.nodeType ? [context] : context;
  10578. // Position selectors must be done after the filter
  10579. // And so must :not(positional) so we move all PSEUDOs to the end
  10580. while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
  10581. later += match[0];
  10582. selector = selector.replace( Expr.match.PSEUDO, "" );
  10583. }
  10584. selector = Expr.relative[selector] ? selector + "*" : selector;
  10585. for ( var i = 0, l = root.length; i < l; i++ ) {
  10586. Sizzle( selector, root[i], tmpSet );
  10587. }
  10588. return Sizzle.filter( later, tmpSet );
  10589. };
  10590. // EXPOSE
  10591. Firebug.Selector = Sizzle;
  10592. /**#@-*/
  10593. // ************************************************************************************************
  10594. }});
  10595. // Problems in IE
  10596. // FIXED - eval return
  10597. // FIXED - addEventListener problem in IE
  10598. // FIXED doc.createRange?
  10599. //
  10600. // class reserved word
  10601. // test all honza examples in IE6 and IE7
  10602. /* See license.txt for terms of usage */
  10603. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  10604. function DomplateTag(tagName)
  10605. {
  10606. this.tagName = tagName;
  10607. }
  10608. function DomplateEmbed()
  10609. {
  10610. }
  10611. function DomplateLoop()
  10612. {
  10613. }
  10614. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  10615. ( /** @scope ns-domplate */ function() {
  10616. var womb = null;
  10617. var domplate = FBL.domplate = function()
  10618. {
  10619. var lastSubject;
  10620. for (var i = 0; i < arguments.length; ++i)
  10621. lastSubject = lastSubject ? copyObject(lastSubject, arguments[i]) : arguments[i];
  10622. for (var name in lastSubject)
  10623. {
  10624. var val = lastSubject[name];
  10625. if (isTag(val))
  10626. val.tag.subject = lastSubject;
  10627. }
  10628. return lastSubject;
  10629. };
  10630. domplate.context = function(context, fn)
  10631. {
  10632. var lastContext = domplate.lastContext;
  10633. domplate.topContext = context;
  10634. fn.apply(context);
  10635. domplate.topContext = lastContext;
  10636. };
  10637. FBL.TAG = function()
  10638. {
  10639. var embed = new DomplateEmbed();
  10640. return embed.merge(arguments);
  10641. };
  10642. FBL.FOR = function()
  10643. {
  10644. var loop = new DomplateLoop();
  10645. return loop.merge(arguments);
  10646. };
  10647. DomplateTag.prototype =
  10648. {
  10649. merge: function(args, oldTag)
  10650. {
  10651. if (oldTag)
  10652. this.tagName = oldTag.tagName;
  10653. this.context = oldTag ? oldTag.context : null;
  10654. this.subject = oldTag ? oldTag.subject : null;
  10655. this.attrs = oldTag ? copyObject(oldTag.attrs) : {};
  10656. this.classes = oldTag ? copyObject(oldTag.classes) : {};
  10657. this.props = oldTag ? copyObject(oldTag.props) : null;
  10658. this.listeners = oldTag ? copyArray(oldTag.listeners) : null;
  10659. this.children = oldTag ? copyArray(oldTag.children) : [];
  10660. this.vars = oldTag ? copyArray(oldTag.vars) : [];
  10661. var attrs = args.length ? args[0] : null;
  10662. var hasAttrs = typeof(attrs) == "object" && !isTag(attrs);
  10663. this.children = [];
  10664. if (domplate.topContext)
  10665. this.context = domplate.topContext;
  10666. if (args.length)
  10667. parseChildren(args, hasAttrs ? 1 : 0, this.vars, this.children);
  10668. if (hasAttrs)
  10669. this.parseAttrs(attrs);
  10670. return creator(this, DomplateTag);
  10671. },
  10672. parseAttrs: function(args)
  10673. {
  10674. for (var name in args)
  10675. {
  10676. var val = parseValue(args[name]);
  10677. readPartNames(val, this.vars);
  10678. if (name.indexOf("on") == 0)
  10679. {
  10680. var eventName = name.substr(2);
  10681. if (!this.listeners)
  10682. this.listeners = [];
  10683. this.listeners.push(eventName, val);
  10684. }
  10685. else if (name.indexOf("_") == 0)
  10686. {
  10687. var propName = name.substr(1);
  10688. if (!this.props)
  10689. this.props = {};
  10690. this.props[propName] = val;
  10691. }
  10692. else if (name.indexOf("$") == 0)
  10693. {
  10694. var className = name.substr(1);
  10695. if (!this.classes)
  10696. this.classes = {};
  10697. this.classes[className] = val;
  10698. }
  10699. else
  10700. {
  10701. if (name == "class" && this.attrs.hasOwnProperty(name) )
  10702. this.attrs[name] += " " + val;
  10703. else
  10704. this.attrs[name] = val;
  10705. }
  10706. }
  10707. },
  10708. compile: function()
  10709. {
  10710. if (this.renderMarkup)
  10711. return;
  10712. this.compileMarkup();
  10713. this.compileDOM();
  10714. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderMarkup: ", this.renderMarkup);
  10715. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate renderDOM:", this.renderDOM);
  10716. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate domArgs:", this.domArgs);
  10717. },
  10718. compileMarkup: function()
  10719. {
  10720. this.markupArgs = [];
  10721. var topBlock = [], topOuts = [], blocks = [], info = {args: this.markupArgs, argIndex: 0};
  10722. this.generateMarkup(topBlock, topOuts, blocks, info);
  10723. this.addCode(topBlock, topOuts, blocks);
  10724. var fnBlock = ['r=(function (__code__, __context__, __in__, __out__'];
  10725. for (var i = 0; i < info.argIndex; ++i)
  10726. fnBlock.push(', s', i);
  10727. fnBlock.push(') {');
  10728. if (this.subject)
  10729. fnBlock.push('with (this) {');
  10730. if (this.context)
  10731. fnBlock.push('with (__context__) {');
  10732. fnBlock.push('with (__in__) {');
  10733. fnBlock.push.apply(fnBlock, blocks);
  10734. if (this.subject)
  10735. fnBlock.push('}');
  10736. if (this.context)
  10737. fnBlock.push('}');
  10738. fnBlock.push('}})');
  10739. function __link__(tag, code, outputs, args)
  10740. {
  10741. if (!tag || !tag.tag)
  10742. return;
  10743. tag.tag.compile();
  10744. var tagOutputs = [];
  10745. var markupArgs = [code, tag.tag.context, args, tagOutputs];
  10746. markupArgs.push.apply(markupArgs, tag.tag.markupArgs);
  10747. tag.tag.renderMarkup.apply(tag.tag.subject, markupArgs);
  10748. outputs.push(tag);
  10749. outputs.push(tagOutputs);
  10750. }
  10751. function __escape__(value)
  10752. {
  10753. function replaceChars(ch)
  10754. {
  10755. switch (ch)
  10756. {
  10757. case "<":
  10758. return "&lt;";
  10759. case ">":
  10760. return "&gt;";
  10761. case "&":
  10762. return "&amp;";
  10763. case "'":
  10764. return "&#39;";
  10765. case '"':
  10766. return "&quot;";
  10767. }
  10768. return "?";
  10769. };
  10770. return String(value).replace(/[<>&"']/g, replaceChars);
  10771. }
  10772. function __loop__(iter, outputs, fn)
  10773. {
  10774. var iterOuts = [];
  10775. outputs.push(iterOuts);
  10776. if (iter instanceof Array)
  10777. iter = new ArrayIterator(iter);
  10778. try
  10779. {
  10780. while (1)
  10781. {
  10782. var value = iter.next();
  10783. var itemOuts = [0,0];
  10784. iterOuts.push(itemOuts);
  10785. fn.apply(this, [value, itemOuts]);
  10786. }
  10787. }
  10788. catch (exc)
  10789. {
  10790. if (exc != StopIteration)
  10791. throw exc;
  10792. }
  10793. }
  10794. var js = fnBlock.join("");
  10795. var r = null;
  10796. eval(js);
  10797. this.renderMarkup = r;
  10798. },
  10799. getVarNames: function(args)
  10800. {
  10801. if (this.vars)
  10802. args.push.apply(args, this.vars);
  10803. for (var i = 0; i < this.children.length; ++i)
  10804. {
  10805. var child = this.children[i];
  10806. if (isTag(child))
  10807. child.tag.getVarNames(args);
  10808. else if (child instanceof Parts)
  10809. {
  10810. for (var i = 0; i < child.parts.length; ++i)
  10811. {
  10812. if (child.parts[i] instanceof Variable)
  10813. {
  10814. var name = child.parts[i].name;
  10815. var names = name.split(".");
  10816. args.push(names[0]);
  10817. }
  10818. }
  10819. }
  10820. }
  10821. },
  10822. generateMarkup: function(topBlock, topOuts, blocks, info)
  10823. {
  10824. topBlock.push(',"<', this.tagName, '"');
  10825. for (var name in this.attrs)
  10826. {
  10827. if (name != "class")
  10828. {
  10829. var val = this.attrs[name];
  10830. topBlock.push(', " ', name, '=\\""');
  10831. addParts(val, ',', topBlock, info, true);
  10832. topBlock.push(', "\\""');
  10833. }
  10834. }
  10835. if (this.listeners)
  10836. {
  10837. for (var i = 0; i < this.listeners.length; i += 2)
  10838. readPartNames(this.listeners[i+1], topOuts);
  10839. }
  10840. if (this.props)
  10841. {
  10842. for (var name in this.props)
  10843. readPartNames(this.props[name], topOuts);
  10844. }
  10845. if ( this.attrs.hasOwnProperty("class") || this.classes)
  10846. {
  10847. topBlock.push(', " class=\\""');
  10848. if (this.attrs.hasOwnProperty("class"))
  10849. addParts(this.attrs["class"], ',', topBlock, info, true);
  10850. topBlock.push(', " "');
  10851. for (var name in this.classes)
  10852. {
  10853. topBlock.push(', (');
  10854. addParts(this.classes[name], '', topBlock, info);
  10855. topBlock.push(' ? "', name, '" + " " : "")');
  10856. }
  10857. topBlock.push(', "\\""');
  10858. }
  10859. topBlock.push(',">"');
  10860. this.generateChildMarkup(topBlock, topOuts, blocks, info);
  10861. topBlock.push(',"</', this.tagName, '>"');
  10862. },
  10863. generateChildMarkup: function(topBlock, topOuts, blocks, info)
  10864. {
  10865. for (var i = 0; i < this.children.length; ++i)
  10866. {
  10867. var child = this.children[i];
  10868. if (isTag(child))
  10869. child.tag.generateMarkup(topBlock, topOuts, blocks, info);
  10870. else
  10871. addParts(child, ',', topBlock, info, true);
  10872. }
  10873. },
  10874. addCode: function(topBlock, topOuts, blocks)
  10875. {
  10876. if (topBlock.length)
  10877. blocks.push('__code__.push(""', topBlock.join(""), ');');
  10878. if (topOuts.length)
  10879. blocks.push('__out__.push(', topOuts.join(","), ');');
  10880. topBlock.splice(0, topBlock.length);
  10881. topOuts.splice(0, topOuts.length);
  10882. },
  10883. addLocals: function(blocks)
  10884. {
  10885. var varNames = [];
  10886. this.getVarNames(varNames);
  10887. var map = {};
  10888. for (var i = 0; i < varNames.length; ++i)
  10889. {
  10890. var name = varNames[i];
  10891. if ( map.hasOwnProperty(name) )
  10892. continue;
  10893. map[name] = 1;
  10894. var names = name.split(".");
  10895. blocks.push('var ', names[0] + ' = ' + '__in__.' + names[0] + ';');
  10896. }
  10897. },
  10898. compileDOM: function()
  10899. {
  10900. var path = [];
  10901. var blocks = [];
  10902. this.domArgs = [];
  10903. path.embedIndex = 0;
  10904. path.loopIndex = 0;
  10905. path.staticIndex = 0;
  10906. path.renderIndex = 0;
  10907. var nodeCount = this.generateDOM(path, blocks, this.domArgs);
  10908. var fnBlock = ['r=(function (root, context, o'];
  10909. for (var i = 0; i < path.staticIndex; ++i)
  10910. fnBlock.push(', ', 's'+i);
  10911. for (var i = 0; i < path.renderIndex; ++i)
  10912. fnBlock.push(', ', 'd'+i);
  10913. fnBlock.push(') {');
  10914. for (var i = 0; i < path.loopIndex; ++i)
  10915. fnBlock.push('var l', i, ' = 0;');
  10916. for (var i = 0; i < path.embedIndex; ++i)
  10917. fnBlock.push('var e', i, ' = 0;');
  10918. if (this.subject)
  10919. fnBlock.push('with (this) {');
  10920. if (this.context)
  10921. fnBlock.push('with (context) {');
  10922. fnBlock.push(blocks.join(""));
  10923. if (this.subject)
  10924. fnBlock.push('}');
  10925. if (this.context)
  10926. fnBlock.push('}');
  10927. fnBlock.push('return ', nodeCount, ';');
  10928. fnBlock.push('})');
  10929. function __bind__(object, fn)
  10930. {
  10931. return function(event) { return fn.apply(object, [event]); };
  10932. }
  10933. function __link__(node, tag, args)
  10934. {
  10935. if (!tag || !tag.tag)
  10936. return;
  10937. tag.tag.compile();
  10938. var domArgs = [node, tag.tag.context, 0];
  10939. domArgs.push.apply(domArgs, tag.tag.domArgs);
  10940. domArgs.push.apply(domArgs, args);
  10941. //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate__link__ domArgs:", domArgs);
  10942. return tag.tag.renderDOM.apply(tag.tag.subject, domArgs);
  10943. }
  10944. var self = this;
  10945. function __loop__(iter, fn)
  10946. {
  10947. var nodeCount = 0;
  10948. for (var i = 0; i < iter.length; ++i)
  10949. {
  10950. iter[i][0] = i;
  10951. iter[i][1] = nodeCount;
  10952. nodeCount += fn.apply(this, iter[i]);
  10953. //if (FBTrace.DBG_DOM) FBTrace.sysout("nodeCount", nodeCount);
  10954. }
  10955. return nodeCount;
  10956. }
  10957. function __path__(parent, offset)
  10958. {
  10959. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate __path__ offset: "+ offset+"\n");
  10960. var root = parent;
  10961. for (var i = 2; i < arguments.length; ++i)
  10962. {
  10963. var index = arguments[i];
  10964. if (i == 3)
  10965. index += offset;
  10966. if (index == -1)
  10967. parent = parent.parentNode;
  10968. else
  10969. parent = parent.childNodes[index];
  10970. }
  10971. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate: "+arguments[2]+", root: "+ root+", parent: "+ parent+"\n");
  10972. return parent;
  10973. }
  10974. var js = fnBlock.join("");
  10975. //if (FBTrace.DBG_DOM) FBTrace.sysout(js.replace(/(\;|\{)/g, "$1\n"));
  10976. var r = null;
  10977. eval(js);
  10978. this.renderDOM = r;
  10979. },
  10980. generateDOM: function(path, blocks, args)
  10981. {
  10982. if (this.listeners || this.props)
  10983. this.generateNodePath(path, blocks);
  10984. if (this.listeners)
  10985. {
  10986. for (var i = 0; i < this.listeners.length; i += 2)
  10987. {
  10988. var val = this.listeners[i+1];
  10989. var arg = generateArg(val, path, args);
  10990. //blocks.push('node.addEventListener("', this.listeners[i], '", __bind__(this, ', arg, '), false);');
  10991. blocks.push('addEvent(node, "', this.listeners[i], '", __bind__(this, ', arg, '), false);');
  10992. }
  10993. }
  10994. if (this.props)
  10995. {
  10996. for (var name in this.props)
  10997. {
  10998. var val = this.props[name];
  10999. var arg = generateArg(val, path, args);
  11000. blocks.push('node.', name, ' = ', arg, ';');
  11001. }
  11002. }
  11003. this.generateChildDOM(path, blocks, args);
  11004. return 1;
  11005. },
  11006. generateNodePath: function(path, blocks)
  11007. {
  11008. blocks.push("var node = __path__(root, o");
  11009. for (var i = 0; i < path.length; ++i)
  11010. blocks.push(",", path[i]);
  11011. blocks.push(");");
  11012. },
  11013. generateChildDOM: function(path, blocks, args)
  11014. {
  11015. path.push(0);
  11016. for (var i = 0; i < this.children.length; ++i)
  11017. {
  11018. var child = this.children[i];
  11019. if (isTag(child))
  11020. path[path.length-1] += '+' + child.tag.generateDOM(path, blocks, args);
  11021. else
  11022. path[path.length-1] += '+1';
  11023. }
  11024. path.pop();
  11025. }
  11026. };
  11027. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11028. DomplateEmbed.prototype = copyObject(DomplateTag.prototype,
  11029. {
  11030. merge: function(args, oldTag)
  11031. {
  11032. this.value = oldTag ? oldTag.value : parseValue(args[0]);
  11033. this.attrs = oldTag ? oldTag.attrs : {};
  11034. this.vars = oldTag ? copyArray(oldTag.vars) : [];
  11035. var attrs = args[1];
  11036. for (var name in attrs)
  11037. {
  11038. var val = parseValue(attrs[name]);
  11039. this.attrs[name] = val;
  11040. readPartNames(val, this.vars);
  11041. }
  11042. return creator(this, DomplateEmbed);
  11043. },
  11044. getVarNames: function(names)
  11045. {
  11046. if (this.value instanceof Parts)
  11047. names.push(this.value.parts[0].name);
  11048. if (this.vars)
  11049. names.push.apply(names, this.vars);
  11050. },
  11051. generateMarkup: function(topBlock, topOuts, blocks, info)
  11052. {
  11053. this.addCode(topBlock, topOuts, blocks);
  11054. blocks.push('__link__(');
  11055. addParts(this.value, '', blocks, info);
  11056. blocks.push(', __code__, __out__, {');
  11057. var lastName = null;
  11058. for (var name in this.attrs)
  11059. {
  11060. if (lastName)
  11061. blocks.push(',');
  11062. lastName = name;
  11063. var val = this.attrs[name];
  11064. blocks.push('"', name, '":');
  11065. addParts(val, '', blocks, info);
  11066. }
  11067. blocks.push('});');
  11068. //this.generateChildMarkup(topBlock, topOuts, blocks, info);
  11069. },
  11070. generateDOM: function(path, blocks, args)
  11071. {
  11072. var embedName = 'e'+path.embedIndex++;
  11073. this.generateNodePath(path, blocks);
  11074. var valueName = 'd' + path.renderIndex++;
  11075. var argsName = 'd' + path.renderIndex++;
  11076. blocks.push(embedName + ' = __link__(node, ', valueName, ', ', argsName, ');');
  11077. return embedName;
  11078. }
  11079. });
  11080. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11081. DomplateLoop.prototype = copyObject(DomplateTag.prototype,
  11082. {
  11083. merge: function(args, oldTag)
  11084. {
  11085. this.varName = oldTag ? oldTag.varName : args[0];
  11086. this.iter = oldTag ? oldTag.iter : parseValue(args[1]);
  11087. this.vars = [];
  11088. this.children = oldTag ? copyArray(oldTag.children) : [];
  11089. var offset = Math.min(args.length, 2);
  11090. parseChildren(args, offset, this.vars, this.children);
  11091. return creator(this, DomplateLoop);
  11092. },
  11093. getVarNames: function(names)
  11094. {
  11095. if (this.iter instanceof Parts)
  11096. names.push(this.iter.parts[0].name);
  11097. DomplateTag.prototype.getVarNames.apply(this, [names]);
  11098. },
  11099. generateMarkup: function(topBlock, topOuts, blocks, info)
  11100. {
  11101. this.addCode(topBlock, topOuts, blocks);
  11102. var iterName;
  11103. if (this.iter instanceof Parts)
  11104. {
  11105. var part = this.iter.parts[0];
  11106. iterName = part.name;
  11107. if (part.format)
  11108. {
  11109. for (var i = 0; i < part.format.length; ++i)
  11110. iterName = part.format[i] + "(" + iterName + ")";
  11111. }
  11112. }
  11113. else
  11114. iterName = this.iter;
  11115. blocks.push('__loop__.apply(this, [', iterName, ', __out__, function(', this.varName, ', __out__) {');
  11116. this.generateChildMarkup(topBlock, topOuts, blocks, info);
  11117. this.addCode(topBlock, topOuts, blocks);
  11118. blocks.push('}]);');
  11119. },
  11120. generateDOM: function(path, blocks, args)
  11121. {
  11122. var iterName = 'd'+path.renderIndex++;
  11123. var counterName = 'i'+path.loopIndex;
  11124. var loopName = 'l'+path.loopIndex++;
  11125. if (!path.length)
  11126. path.push(-1, 0);
  11127. var preIndex = path.renderIndex;
  11128. path.renderIndex = 0;
  11129. var nodeCount = 0;
  11130. var subBlocks = [];
  11131. var basePath = path[path.length-1];
  11132. for (var i = 0; i < this.children.length; ++i)
  11133. {
  11134. path[path.length-1] = basePath+'+'+loopName+'+'+nodeCount;
  11135. var child = this.children[i];
  11136. if (isTag(child))
  11137. nodeCount += '+' + child.tag.generateDOM(path, subBlocks, args);
  11138. else
  11139. nodeCount += '+1';
  11140. }
  11141. path[path.length-1] = basePath+'+'+loopName;
  11142. blocks.push(loopName,' = __loop__.apply(this, [', iterName, ', function(', counterName,',',loopName);
  11143. for (var i = 0; i < path.renderIndex; ++i)
  11144. blocks.push(',d'+i);
  11145. blocks.push(') {');
  11146. blocks.push(subBlocks.join(""));
  11147. blocks.push('return ', nodeCount, ';');
  11148. blocks.push('}]);');
  11149. path.renderIndex = preIndex;
  11150. return loopName;
  11151. }
  11152. });
  11153. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11154. function Variable(name, format)
  11155. {
  11156. this.name = name;
  11157. this.format = format;
  11158. }
  11159. function Parts(parts)
  11160. {
  11161. this.parts = parts;
  11162. }
  11163. // ************************************************************************************************
  11164. function parseParts(str)
  11165. {
  11166. var re = /\$([_A-Za-z][_A-Za-z0-9.|]*)/g;
  11167. var index = 0;
  11168. var parts = [];
  11169. var m;
  11170. while (m = re.exec(str))
  11171. {
  11172. var pre = str.substr(index, (re.lastIndex-m[0].length)-index);
  11173. if (pre)
  11174. parts.push(pre);
  11175. var expr = m[1].split("|");
  11176. parts.push(new Variable(expr[0], expr.slice(1)));
  11177. index = re.lastIndex;
  11178. }
  11179. if (!index)
  11180. return str;
  11181. var post = str.substr(index);
  11182. if (post)
  11183. parts.push(post);
  11184. return new Parts(parts);
  11185. }
  11186. function parseValue(val)
  11187. {
  11188. return typeof(val) == 'string' ? parseParts(val) : val;
  11189. }
  11190. function parseChildren(args, offset, vars, children)
  11191. {
  11192. for (var i = offset; i < args.length; ++i)
  11193. {
  11194. var val = parseValue(args[i]);
  11195. children.push(val);
  11196. readPartNames(val, vars);
  11197. }
  11198. }
  11199. function readPartNames(val, vars)
  11200. {
  11201. if (val instanceof Parts)
  11202. {
  11203. for (var i = 0; i < val.parts.length; ++i)
  11204. {
  11205. var part = val.parts[i];
  11206. if (part instanceof Variable)
  11207. vars.push(part.name);
  11208. }
  11209. }
  11210. }
  11211. function generateArg(val, path, args)
  11212. {
  11213. if (val instanceof Parts)
  11214. {
  11215. var vals = [];
  11216. for (var i = 0; i < val.parts.length; ++i)
  11217. {
  11218. var part = val.parts[i];
  11219. if (part instanceof Variable)
  11220. {
  11221. var varName = 'd'+path.renderIndex++;
  11222. if (part.format)
  11223. {
  11224. for (var j = 0; j < part.format.length; ++j)
  11225. varName = part.format[j] + '(' + varName + ')';
  11226. }
  11227. vals.push(varName);
  11228. }
  11229. else
  11230. vals.push('"'+part.replace(/"/g, '\\"')+'"');
  11231. }
  11232. return vals.join('+');
  11233. }
  11234. else
  11235. {
  11236. args.push(val);
  11237. return 's' + path.staticIndex++;
  11238. }
  11239. }
  11240. function addParts(val, delim, block, info, escapeIt)
  11241. {
  11242. var vals = [];
  11243. if (val instanceof Parts)
  11244. {
  11245. for (var i = 0; i < val.parts.length; ++i)
  11246. {
  11247. var part = val.parts[i];
  11248. if (part instanceof Variable)
  11249. {
  11250. var partName = part.name;
  11251. if (part.format)
  11252. {
  11253. for (var j = 0; j < part.format.length; ++j)
  11254. partName = part.format[j] + "(" + partName + ")";
  11255. }
  11256. if (escapeIt)
  11257. vals.push("__escape__(" + partName + ")");
  11258. else
  11259. vals.push(partName);
  11260. }
  11261. else
  11262. vals.push('"'+ part + '"');
  11263. }
  11264. }
  11265. else if (isTag(val))
  11266. {
  11267. info.args.push(val);
  11268. vals.push('s'+info.argIndex++);
  11269. }
  11270. else
  11271. vals.push('"'+ val + '"');
  11272. var parts = vals.join(delim);
  11273. if (parts)
  11274. block.push(delim, parts);
  11275. }
  11276. function isTag(obj)
  11277. {
  11278. return (typeof(obj) == "function" || obj instanceof Function) && !!obj.tag;
  11279. }
  11280. function creator(tag, cons)
  11281. {
  11282. var fn = new Function(
  11283. "var tag = arguments.callee.tag;" +
  11284. "var cons = arguments.callee.cons;" +
  11285. "var newTag = new cons();" +
  11286. "return newTag.merge(arguments, tag);");
  11287. fn.tag = tag;
  11288. fn.cons = cons;
  11289. extend(fn, Renderer);
  11290. return fn;
  11291. }
  11292. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11293. function copyArray(oldArray)
  11294. {
  11295. var ary = [];
  11296. if (oldArray)
  11297. for (var i = 0; i < oldArray.length; ++i)
  11298. ary.push(oldArray[i]);
  11299. return ary;
  11300. }
  11301. function copyObject(l, r)
  11302. {
  11303. var m = {};
  11304. extend(m, l);
  11305. extend(m, r);
  11306. return m;
  11307. }
  11308. function extend(l, r)
  11309. {
  11310. for (var n in r)
  11311. l[n] = r[n];
  11312. }
  11313. function addEvent(object, name, handler)
  11314. {
  11315. if (document.all)
  11316. object.attachEvent("on"+name, handler);
  11317. else
  11318. object.addEventListener(name, handler, false);
  11319. }
  11320. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11321. function ArrayIterator(array)
  11322. {
  11323. var index = -1;
  11324. this.next = function()
  11325. {
  11326. if (++index >= array.length)
  11327. throw StopIteration;
  11328. return array[index];
  11329. };
  11330. }
  11331. function StopIteration() {}
  11332. FBL.$break = function()
  11333. {
  11334. throw StopIteration;
  11335. };
  11336. // ************************************************************************************************
  11337. var Renderer =
  11338. {
  11339. renderHTML: function(args, outputs, self)
  11340. {
  11341. var code = [];
  11342. var markupArgs = [code, this.tag.context, args, outputs];
  11343. markupArgs.push.apply(markupArgs, this.tag.markupArgs);
  11344. this.tag.renderMarkup.apply(self ? self : this.tag.subject, markupArgs);
  11345. return code.join("");
  11346. },
  11347. insertRows: function(args, before, self)
  11348. {
  11349. this.tag.compile();
  11350. var outputs = [];
  11351. var html = this.renderHTML(args, outputs, self);
  11352. var doc = before.ownerDocument;
  11353. var div = doc.createElement("div");
  11354. div.innerHTML = "<table><tbody>"+html+"</tbody></table>";
  11355. var tbody = div.firstChild.firstChild;
  11356. var parent = before.tagName == "TR" ? before.parentNode : before;
  11357. var after = before.tagName == "TR" ? before.nextSibling : null;
  11358. var firstRow = tbody.firstChild, lastRow;
  11359. while (tbody.firstChild)
  11360. {
  11361. lastRow = tbody.firstChild;
  11362. if (after)
  11363. parent.insertBefore(lastRow, after);
  11364. else
  11365. parent.appendChild(lastRow);
  11366. }
  11367. var offset = 0;
  11368. if (before.tagName == "TR")
  11369. {
  11370. var node = firstRow.parentNode.firstChild;
  11371. for (; node && node != firstRow; node = node.nextSibling)
  11372. ++offset;
  11373. }
  11374. var domArgs = [firstRow, this.tag.context, offset];
  11375. domArgs.push.apply(domArgs, this.tag.domArgs);
  11376. domArgs.push.apply(domArgs, outputs);
  11377. this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
  11378. return [firstRow, lastRow];
  11379. },
  11380. insertBefore: function(args, before, self)
  11381. {
  11382. return this.insertNode(args, before.ownerDocument, before, false, self);
  11383. },
  11384. insertAfter: function(args, after, self)
  11385. {
  11386. return this.insertNode(args, after.ownerDocument, after, true, self);
  11387. },
  11388. insertNode: function(args, doc, element, isAfter, self)
  11389. {
  11390. if (!args)
  11391. args = {};
  11392. this.tag.compile();
  11393. var outputs = [];
  11394. var html = this.renderHTML(args, outputs, self);
  11395. //if (FBTrace.DBG_DOM)
  11396. // FBTrace.sysout("domplate.insertNode html: "+html+"\n");
  11397. var doc = element.ownerDocument;
  11398. if (!womb || womb.ownerDocument != doc)
  11399. womb = doc.createElement("div");
  11400. womb.innerHTML = html;
  11401. var root = womb.firstChild;
  11402. if (isAfter)
  11403. {
  11404. while (womb.firstChild)
  11405. if (element.nextSibling)
  11406. element.parentNode.insertBefore(womb.firstChild, element.nextSibling);
  11407. else
  11408. element.parentNode.appendChild(womb.firstChild);
  11409. }
  11410. else
  11411. {
  11412. while (womb.lastChild)
  11413. element.parentNode.insertBefore(womb.lastChild, element);
  11414. }
  11415. var domArgs = [root, this.tag.context, 0];
  11416. domArgs.push.apply(domArgs, this.tag.domArgs);
  11417. domArgs.push.apply(domArgs, outputs);
  11418. //if (FBTrace.DBG_DOM)
  11419. // FBTrace.sysout("domplate.insertNode domArgs:", domArgs);
  11420. this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
  11421. return root;
  11422. },
  11423. /**/
  11424. /*
  11425. insertAfter: function(args, before, self)
  11426. {
  11427. this.tag.compile();
  11428. var outputs = [];
  11429. var html = this.renderHTML(args, outputs, self);
  11430. var doc = before.ownerDocument;
  11431. if (!womb || womb.ownerDocument != doc)
  11432. womb = doc.createElement("div");
  11433. womb.innerHTML = html;
  11434. var root = womb.firstChild;
  11435. while (womb.firstChild)
  11436. if (before.nextSibling)
  11437. before.parentNode.insertBefore(womb.firstChild, before.nextSibling);
  11438. else
  11439. before.parentNode.appendChild(womb.firstChild);
  11440. var domArgs = [root, this.tag.context, 0];
  11441. domArgs.push.apply(domArgs, this.tag.domArgs);
  11442. domArgs.push.apply(domArgs, outputs);
  11443. this.tag.renderDOM.apply(self ? self : (this.tag.subject ? this.tag.subject : null),
  11444. domArgs);
  11445. return root;
  11446. },
  11447. /**/
  11448. replace: function(args, parent, self)
  11449. {
  11450. this.tag.compile();
  11451. var outputs = [];
  11452. var html = this.renderHTML(args, outputs, self);
  11453. var root;
  11454. if (parent.nodeType == 1)
  11455. {
  11456. parent.innerHTML = html;
  11457. root = parent.firstChild;
  11458. }
  11459. else
  11460. {
  11461. if (!parent || parent.nodeType != 9)
  11462. parent = document;
  11463. if (!womb || womb.ownerDocument != parent)
  11464. womb = parent.createElement("div");
  11465. womb.innerHTML = html;
  11466. root = womb.firstChild;
  11467. //womb.removeChild(root);
  11468. }
  11469. var domArgs = [root, this.tag.context, 0];
  11470. domArgs.push.apply(domArgs, this.tag.domArgs);
  11471. domArgs.push.apply(domArgs, outputs);
  11472. this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
  11473. return root;
  11474. },
  11475. append: function(args, parent, self)
  11476. {
  11477. this.tag.compile();
  11478. var outputs = [];
  11479. var html = this.renderHTML(args, outputs, self);
  11480. //if (FBTrace.DBG_DOM) FBTrace.sysout("domplate.append html: "+html+"\n");
  11481. if (!womb || womb.ownerDocument != parent.ownerDocument)
  11482. womb = parent.ownerDocument.createElement("div");
  11483. womb.innerHTML = html;
  11484. // TODO: xxxpedro domplate port to Firebug
  11485. var root = womb.firstChild;
  11486. while (womb.firstChild)
  11487. parent.appendChild(womb.firstChild);
  11488. // clearing element reference to avoid reference error in IE8 when switching contexts
  11489. womb = null;
  11490. var domArgs = [root, this.tag.context, 0];
  11491. domArgs.push.apply(domArgs, this.tag.domArgs);
  11492. domArgs.push.apply(domArgs, outputs);
  11493. //if (FBTrace.DBG_DOM) FBTrace.dumpProperties("domplate append domArgs:", domArgs);
  11494. this.tag.renderDOM.apply(self ? self : this.tag.subject, domArgs);
  11495. return root;
  11496. }
  11497. };
  11498. // ************************************************************************************************
  11499. function defineTags()
  11500. {
  11501. for (var i = 0; i < arguments.length; ++i)
  11502. {
  11503. var tagName = arguments[i];
  11504. var fn = new Function("var newTag = new arguments.callee.DomplateTag('"+tagName+"'); return newTag.merge(arguments);");
  11505. fn.DomplateTag = DomplateTag;
  11506. var fnName = tagName.toUpperCase();
  11507. FBL[fnName] = fn;
  11508. }
  11509. }
  11510. defineTags(
  11511. "a", "button", "br", "canvas", "code", "col", "colgroup", "div", "fieldset", "form", "h1", "h2", "h3", "hr",
  11512. "img", "input", "label", "legend", "li", "ol", "optgroup", "option", "p", "pre", "select",
  11513. "span", "strong", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "tr", "tt", "ul", "iframe"
  11514. );
  11515. })();
  11516. /* See license.txt for terms of usage */
  11517. var FirebugReps = FBL.ns(function() { with (FBL) {
  11518. // ************************************************************************************************
  11519. // Common Tags
  11520. var OBJECTBOX = this.OBJECTBOX =
  11521. SPAN({"class": "objectBox objectBox-$className"});
  11522. var OBJECTBLOCK = this.OBJECTBLOCK =
  11523. DIV({"class": "objectBox objectBox-$className"});
  11524. var OBJECTLINK = this.OBJECTLINK = isIE6 ? // IE6 object link representation
  11525. A({
  11526. "class": "objectLink objectLink-$className a11yFocus",
  11527. href: "javascript:void(0)",
  11528. _repObject: "$object"
  11529. })
  11530. : // Other browsers
  11531. A({
  11532. "class": "objectLink objectLink-$className a11yFocus",
  11533. _repObject: "$object"
  11534. });
  11535. // ************************************************************************************************
  11536. this.Undefined = domplate(Firebug.Rep,
  11537. {
  11538. tag: OBJECTBOX("undefined"),
  11539. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11540. className: "undefined",
  11541. supportsObject: function(object, type)
  11542. {
  11543. return type == "undefined";
  11544. }
  11545. });
  11546. // ************************************************************************************************
  11547. this.Null = domplate(Firebug.Rep,
  11548. {
  11549. tag: OBJECTBOX("null"),
  11550. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11551. className: "null",
  11552. supportsObject: function(object, type)
  11553. {
  11554. return object == null;
  11555. }
  11556. });
  11557. // ************************************************************************************************
  11558. this.Nada = domplate(Firebug.Rep,
  11559. {
  11560. tag: SPAN(""),
  11561. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11562. className: "nada"
  11563. });
  11564. // ************************************************************************************************
  11565. this.Number = domplate(Firebug.Rep,
  11566. {
  11567. tag: OBJECTBOX("$object"),
  11568. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11569. className: "number",
  11570. supportsObject: function(object, type)
  11571. {
  11572. return type == "boolean" || type == "number";
  11573. }
  11574. });
  11575. // ************************************************************************************************
  11576. this.String = domplate(Firebug.Rep,
  11577. {
  11578. tag: OBJECTBOX("&quot;$object&quot;"),
  11579. shortTag: OBJECTBOX("&quot;$object|cropString&quot;"),
  11580. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11581. className: "string",
  11582. supportsObject: function(object, type)
  11583. {
  11584. return type == "string";
  11585. }
  11586. });
  11587. // ************************************************************************************************
  11588. this.Text = domplate(Firebug.Rep,
  11589. {
  11590. tag: OBJECTBOX("$object"),
  11591. shortTag: OBJECTBOX("$object|cropString"),
  11592. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11593. className: "text"
  11594. });
  11595. // ************************************************************************************************
  11596. this.Caption = domplate(Firebug.Rep,
  11597. {
  11598. tag: SPAN({"class": "caption"}, "$object")
  11599. });
  11600. // ************************************************************************************************
  11601. this.Warning = domplate(Firebug.Rep,
  11602. {
  11603. tag: DIV({"class": "warning focusRow", role : 'listitem'}, "$object|STR")
  11604. });
  11605. // ************************************************************************************************
  11606. this.Func = domplate(Firebug.Rep,
  11607. {
  11608. tag:
  11609. OBJECTLINK("$object|summarizeFunction"),
  11610. summarizeFunction: function(fn)
  11611. {
  11612. var fnRegex = /function ([^(]+\([^)]*\)) \{/;
  11613. var fnText = safeToString(fn);
  11614. var m = fnRegex.exec(fnText);
  11615. return m ? m[1] : "function()";
  11616. },
  11617. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11618. copySource: function(fn)
  11619. {
  11620. copyToClipboard(safeToString(fn));
  11621. },
  11622. monitor: function(fn, script, monitored)
  11623. {
  11624. if (monitored)
  11625. Firebug.Debugger.unmonitorScript(fn, script, "monitor");
  11626. else
  11627. Firebug.Debugger.monitorScript(fn, script, "monitor");
  11628. },
  11629. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11630. className: "function",
  11631. supportsObject: function(object, type)
  11632. {
  11633. return isFunction(object);
  11634. },
  11635. inspectObject: function(fn, context)
  11636. {
  11637. var sourceLink = findSourceForFunction(fn, context);
  11638. if (sourceLink)
  11639. Firebug.chrome.select(sourceLink);
  11640. if (FBTrace.DBG_FUNCTION_NAME)
  11641. FBTrace.sysout("reps.function.inspectObject selected sourceLink is ", sourceLink);
  11642. },
  11643. getTooltip: function(fn, context)
  11644. {
  11645. var script = findScriptForFunctionInContext(context, fn);
  11646. if (script)
  11647. return $STRF("Line", [normalizeURL(script.fileName), script.baseLineNumber]);
  11648. else
  11649. if (fn.toString)
  11650. return fn.toString();
  11651. },
  11652. getTitle: function(fn, context)
  11653. {
  11654. var name = fn.name ? fn.name : "function";
  11655. return name + "()";
  11656. },
  11657. getContextMenuItems: function(fn, target, context, script)
  11658. {
  11659. if (!script)
  11660. script = findScriptForFunctionInContext(context, fn);
  11661. if (!script)
  11662. return;
  11663. var scriptInfo = getSourceFileAndLineByScript(context, script);
  11664. var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
  11665. var name = script ? getFunctionName(script, context) : fn.name;
  11666. return [
  11667. {label: "CopySource", command: bindFixed(this.copySource, this, fn) },
  11668. "-",
  11669. {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
  11670. type: "checkbox", checked: monitored,
  11671. command: bindFixed(this.monitor, this, fn, script, monitored) }
  11672. ];
  11673. }
  11674. });
  11675. // ************************************************************************************************
  11676. /*
  11677. this.jsdScript = domplate(Firebug.Rep,
  11678. {
  11679. copySource: function(script)
  11680. {
  11681. var fn = script.functionObject.getWrappedValue();
  11682. return FirebugReps.Func.copySource(fn);
  11683. },
  11684. monitor: function(fn, script, monitored)
  11685. {
  11686. fn = script.functionObject.getWrappedValue();
  11687. return FirebugReps.Func.monitor(fn, script, monitored);
  11688. },
  11689. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11690. className: "jsdScript",
  11691. inspectable: false,
  11692. supportsObject: function(object, type)
  11693. {
  11694. return object instanceof jsdIScript;
  11695. },
  11696. inspectObject: function(script, context)
  11697. {
  11698. var sourceLink = getSourceLinkForScript(script, context);
  11699. if (sourceLink)
  11700. Firebug.chrome.select(sourceLink);
  11701. },
  11702. getRealObject: function(script, context)
  11703. {
  11704. return script;
  11705. },
  11706. getTooltip: function(script)
  11707. {
  11708. return $STRF("jsdIScript", [script.tag]);
  11709. },
  11710. getTitle: function(script, context)
  11711. {
  11712. var fn = script.functionObject.getWrappedValue();
  11713. return FirebugReps.Func.getTitle(fn, context);
  11714. },
  11715. getContextMenuItems: function(script, target, context)
  11716. {
  11717. var fn = script.functionObject.getWrappedValue();
  11718. var scriptInfo = getSourceFileAndLineByScript(context, script);
  11719. var monitored = scriptInfo ? fbs.isMonitored(scriptInfo.sourceFile.href, scriptInfo.lineNo) : false;
  11720. var name = getFunctionName(script, context);
  11721. return [
  11722. {label: "CopySource", command: bindFixed(this.copySource, this, script) },
  11723. "-",
  11724. {label: $STRF("ShowCallsInConsole", [name]), nol10n: true,
  11725. type: "checkbox", checked: monitored,
  11726. command: bindFixed(this.monitor, this, fn, script, monitored) }
  11727. ];
  11728. }
  11729. });
  11730. /**/
  11731. //************************************************************************************************
  11732. this.Obj = domplate(Firebug.Rep,
  11733. {
  11734. tag:
  11735. OBJECTLINK(
  11736. SPAN({"class": "objectTitle"}, "$object|getTitle "),
  11737. SPAN({"class": "objectProps"},
  11738. SPAN({"class": "objectLeftBrace", role: "presentation"}, "{"),
  11739. FOR("prop", "$object|propIterator",
  11740. SPAN({"class": "objectPropName", role: "presentation"}, "$prop.name"),
  11741. SPAN({"class": "objectEqual", role: "presentation"}, "$prop.equal"),
  11742. TAG("$prop.tag", {object: "$prop.object"}),
  11743. SPAN({"class": "objectComma", role: "presentation"}, "$prop.delim")
  11744. ),
  11745. SPAN({"class": "objectRightBrace"}, "}")
  11746. )
  11747. ),
  11748. propNumberTag:
  11749. SPAN({"class": "objectProp-number"}, "$object"),
  11750. propStringTag:
  11751. SPAN({"class": "objectProp-string"}, "&quot;$object&quot;"),
  11752. propObjectTag:
  11753. SPAN({"class": "objectProp-object"}, "$object"),
  11754. propIterator: function (object)
  11755. {
  11756. ///Firebug.ObjectShortIteratorMax;
  11757. var maxLength = 55; // default max length for long representation
  11758. if (!object)
  11759. return [];
  11760. var props = [];
  11761. var length = 0;
  11762. var numProperties = 0;
  11763. var numPropertiesShown = 0;
  11764. var maxLengthReached = false;
  11765. var lib = this;
  11766. var propRepsMap =
  11767. {
  11768. "boolean": this.propNumberTag,
  11769. "number": this.propNumberTag,
  11770. "string": this.propStringTag,
  11771. "object": this.propObjectTag
  11772. };
  11773. try
  11774. {
  11775. var title = Firebug.Rep.getTitle(object);
  11776. length += title.length;
  11777. for (var name in object)
  11778. {
  11779. var value;
  11780. try
  11781. {
  11782. value = object[name];
  11783. }
  11784. catch (exc)
  11785. {
  11786. continue;
  11787. }
  11788. var type = typeof(value);
  11789. if (type == "boolean" ||
  11790. type == "number" ||
  11791. (type == "string" && value) ||
  11792. (type == "object" && value && value.toString))
  11793. {
  11794. var tag = propRepsMap[type];
  11795. var value = (type == "object") ?
  11796. Firebug.getRep(value).getTitle(value) :
  11797. value + "";
  11798. length += name.length + value.length + 4;
  11799. if (length <= maxLength)
  11800. {
  11801. props.push({
  11802. tag: tag,
  11803. name: name,
  11804. object: value,
  11805. equal: "=",
  11806. delim: ", "
  11807. });
  11808. numPropertiesShown++;
  11809. }
  11810. else
  11811. maxLengthReached = true;
  11812. }
  11813. numProperties++;
  11814. if (maxLengthReached && numProperties > numPropertiesShown)
  11815. break;
  11816. }
  11817. if (numProperties > numPropertiesShown)
  11818. {
  11819. props.push({
  11820. object: "...", //xxxHonza localization
  11821. tag: FirebugReps.Caption.tag,
  11822. name: "",
  11823. equal:"",
  11824. delim:""
  11825. });
  11826. }
  11827. else if (props.length > 0)
  11828. {
  11829. props[props.length-1].delim = '';
  11830. }
  11831. }
  11832. catch (exc)
  11833. {
  11834. // Sometimes we get exceptions when trying to read from certain objects, like
  11835. // StorageList, but don't let that gum up the works
  11836. // XXXjjb also History.previous fails because object is a web-page object which does not have
  11837. // permission to read the history
  11838. }
  11839. return props;
  11840. },
  11841. fb_1_6_propIterator: function (object, max)
  11842. {
  11843. max = max || 3;
  11844. if (!object)
  11845. return [];
  11846. var props = [];
  11847. var len = 0, count = 0;
  11848. try
  11849. {
  11850. for (var name in object)
  11851. {
  11852. var value;
  11853. try
  11854. {
  11855. value = object[name];
  11856. }
  11857. catch (exc)
  11858. {
  11859. continue;
  11860. }
  11861. var t = typeof(value);
  11862. if (t == "boolean" || t == "number" || (t == "string" && value)
  11863. || (t == "object" && value && value.toString))
  11864. {
  11865. var rep = Firebug.getRep(value);
  11866. var tag = rep.shortTag || rep.tag;
  11867. if (t == "object")
  11868. {
  11869. value = rep.getTitle(value);
  11870. tag = rep.titleTag;
  11871. }
  11872. count++;
  11873. if (count <= max)
  11874. props.push({tag: tag, name: name, object: value, equal: "=", delim: ", "});
  11875. else
  11876. break;
  11877. }
  11878. }
  11879. if (count > max)
  11880. {
  11881. props[Math.max(1,max-1)] = {
  11882. object: "more...", //xxxHonza localization
  11883. tag: FirebugReps.Caption.tag,
  11884. name: "",
  11885. equal:"",
  11886. delim:""
  11887. };
  11888. }
  11889. else if (props.length > 0)
  11890. {
  11891. props[props.length-1].delim = '';
  11892. }
  11893. }
  11894. catch (exc)
  11895. {
  11896. // Sometimes we get exceptions when trying to read from certain objects, like
  11897. // StorageList, but don't let that gum up the works
  11898. // XXXjjb also History.previous fails because object is a web-page object which does not have
  11899. // permission to read the history
  11900. }
  11901. return props;
  11902. },
  11903. /*
  11904. propIterator: function (object)
  11905. {
  11906. if (!object)
  11907. return [];
  11908. var props = [];
  11909. var len = 0;
  11910. try
  11911. {
  11912. for (var name in object)
  11913. {
  11914. var val;
  11915. try
  11916. {
  11917. val = object[name];
  11918. }
  11919. catch (exc)
  11920. {
  11921. continue;
  11922. }
  11923. var t = typeof val;
  11924. if (t == "boolean" || t == "number" || (t == "string" && val)
  11925. || (t == "object" && !isFunction(val) && val && val.toString))
  11926. {
  11927. var title = (t == "object")
  11928. ? Firebug.getRep(val).getTitle(val)
  11929. : val+"";
  11930. len += name.length + title.length + 1;
  11931. if (len < 50)
  11932. props.push({name: name, value: title});
  11933. else
  11934. break;
  11935. }
  11936. }
  11937. }
  11938. catch (exc)
  11939. {
  11940. // Sometimes we get exceptions when trying to read from certain objects, like
  11941. // StorageList, but don't let that gum up the works
  11942. // XXXjjb also History.previous fails because object is a web-page object which does not have
  11943. // permission to read the history
  11944. }
  11945. return props;
  11946. },
  11947. /**/
  11948. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  11949. className: "object",
  11950. supportsObject: function(object, type)
  11951. {
  11952. return true;
  11953. }
  11954. });
  11955. // ************************************************************************************************
  11956. this.Arr = domplate(Firebug.Rep,
  11957. {
  11958. tag:
  11959. OBJECTBOX({_repObject: "$object"},
  11960. SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["),
  11961. FOR("item", "$object|arrayIterator",
  11962. TAG("$item.tag", {object: "$item.object"}),
  11963. SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim")
  11964. ),
  11965. SPAN({"class": "arrayRightBracket", role : "presentation"}, "]")
  11966. ),
  11967. shortTag:
  11968. OBJECTBOX({_repObject: "$object"},
  11969. SPAN({"class": "arrayLeftBracket", role : "presentation"}, "["),
  11970. FOR("item", "$object|shortArrayIterator",
  11971. TAG("$item.tag", {object: "$item.object"}),
  11972. SPAN({"class": "arrayComma", role : "presentation"}, "$item.delim")
  11973. ),
  11974. // TODO: xxxpedro - confirm this on Firebug
  11975. //FOR("prop", "$object|shortPropIterator",
  11976. // " $prop.name=",
  11977. // SPAN({"class": "objectPropValue"}, "$prop.value|cropString")
  11978. //),
  11979. SPAN({"class": "arrayRightBracket"}, "]")
  11980. ),
  11981. arrayIterator: function(array)
  11982. {
  11983. var items = [];
  11984. for (var i = 0; i < array.length; ++i)
  11985. {
  11986. var value = array[i];
  11987. var rep = Firebug.getRep(value);
  11988. var tag = rep.shortTag ? rep.shortTag : rep.tag;
  11989. var delim = (i == array.length-1 ? "" : ", ");
  11990. items.push({object: value, tag: tag, delim: delim});
  11991. }
  11992. return items;
  11993. },
  11994. shortArrayIterator: function(array)
  11995. {
  11996. var items = [];
  11997. for (var i = 0; i < array.length && i < 3; ++i)
  11998. {
  11999. var value = array[i];
  12000. var rep = Firebug.getRep(value);
  12001. var tag = rep.shortTag ? rep.shortTag : rep.tag;
  12002. var delim = (i == array.length-1 ? "" : ", ");
  12003. items.push({object: value, tag: tag, delim: delim});
  12004. }
  12005. if (array.length > 3)
  12006. items.push({object: (array.length-3) + " more...", tag: FirebugReps.Caption.tag, delim: ""});
  12007. return items;
  12008. },
  12009. shortPropIterator: this.Obj.propIterator,
  12010. getItemIndex: function(child)
  12011. {
  12012. var arrayIndex = 0;
  12013. for (child = child.previousSibling; child; child = child.previousSibling)
  12014. {
  12015. if (child.repObject)
  12016. ++arrayIndex;
  12017. }
  12018. return arrayIndex;
  12019. },
  12020. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12021. className: "array",
  12022. supportsObject: function(object)
  12023. {
  12024. return this.isArray(object);
  12025. },
  12026. // http://code.google.com/p/fbug/issues/detail?id=874
  12027. // BEGIN Yahoo BSD Source (modified here) YAHOO.lang.isArray, YUI 2.2.2 June 2007
  12028. isArray: function(obj) {
  12029. try {
  12030. if (!obj)
  12031. return false;
  12032. else if (isIE && !isFunction(obj) && typeof obj == "object" && isFinite(obj.length) && obj.nodeType != 8)
  12033. return true;
  12034. else if (isFinite(obj.length) && isFunction(obj.splice))
  12035. return true;
  12036. else if (isFinite(obj.length) && isFunction(obj.callee)) // arguments
  12037. return true;
  12038. else if (instanceOf(obj, "HTMLCollection"))
  12039. return true;
  12040. else if (instanceOf(obj, "NodeList"))
  12041. return true;
  12042. else
  12043. return false;
  12044. }
  12045. catch(exc)
  12046. {
  12047. if (FBTrace.DBG_ERRORS)
  12048. {
  12049. FBTrace.sysout("isArray FAILS:", exc); /* Something weird: without the try/catch, OOM, with no exception?? */
  12050. FBTrace.sysout("isArray Fails on obj", obj);
  12051. }
  12052. }
  12053. return false;
  12054. },
  12055. // END Yahoo BSD SOURCE See license below.
  12056. getTitle: function(object, context)
  12057. {
  12058. return "[" + object.length + "]";
  12059. }
  12060. });
  12061. // ************************************************************************************************
  12062. this.Property = domplate(Firebug.Rep,
  12063. {
  12064. supportsObject: function(object)
  12065. {
  12066. return object instanceof Property;
  12067. },
  12068. getRealObject: function(prop, context)
  12069. {
  12070. return prop.object[prop.name];
  12071. },
  12072. getTitle: function(prop, context)
  12073. {
  12074. return prop.name;
  12075. }
  12076. });
  12077. // ************************************************************************************************
  12078. this.NetFile = domplate(this.Obj,
  12079. {
  12080. supportsObject: function(object)
  12081. {
  12082. return object instanceof Firebug.NetFile;
  12083. },
  12084. browseObject: function(file, context)
  12085. {
  12086. openNewTab(file.href);
  12087. return true;
  12088. },
  12089. getRealObject: function(file, context)
  12090. {
  12091. return null;
  12092. }
  12093. });
  12094. // ************************************************************************************************
  12095. this.Except = domplate(Firebug.Rep,
  12096. {
  12097. tag:
  12098. OBJECTBOX({_repObject: "$object"}, "$object.message"),
  12099. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12100. className: "exception",
  12101. supportsObject: function(object)
  12102. {
  12103. return object instanceof ErrorCopy;
  12104. }
  12105. });
  12106. // ************************************************************************************************
  12107. this.Element = domplate(Firebug.Rep,
  12108. {
  12109. tag:
  12110. OBJECTLINK(
  12111. "&lt;",
  12112. SPAN({"class": "nodeTag"}, "$object.nodeName|toLowerCase"),
  12113. FOR("attr", "$object|attrIterator",
  12114. "&nbsp;$attr.nodeName=&quot;", SPAN({"class": "nodeValue"}, "$attr.nodeValue"), "&quot;"
  12115. ),
  12116. "&gt;"
  12117. ),
  12118. shortTag:
  12119. OBJECTLINK(
  12120. SPAN({"class": "$object|getVisible"},
  12121. SPAN({"class": "selectorTag"}, "$object|getSelectorTag"),
  12122. SPAN({"class": "selectorId"}, "$object|getSelectorId"),
  12123. SPAN({"class": "selectorClass"}, "$object|getSelectorClass"),
  12124. SPAN({"class": "selectorValue"}, "$object|getValue")
  12125. )
  12126. ),
  12127. getVisible: function(elt)
  12128. {
  12129. return isVisible(elt) ? "" : "selectorHidden";
  12130. },
  12131. getSelectorTag: function(elt)
  12132. {
  12133. return elt.nodeName.toLowerCase();
  12134. },
  12135. getSelectorId: function(elt)
  12136. {
  12137. return elt.id ? "#" + elt.id : "";
  12138. },
  12139. getSelectorClass: function(elt)
  12140. {
  12141. return elt.className ? "." + elt.className.split(" ")[0] : "";
  12142. },
  12143. getValue: function(elt)
  12144. {
  12145. // TODO: xxxpedro
  12146. return "";
  12147. var value;
  12148. if (elt instanceof HTMLImageElement)
  12149. value = getFileName(elt.src);
  12150. else if (elt instanceof HTMLAnchorElement)
  12151. value = getFileName(elt.href);
  12152. else if (elt instanceof HTMLInputElement)
  12153. value = elt.value;
  12154. else if (elt instanceof HTMLFormElement)
  12155. value = getFileName(elt.action);
  12156. else if (elt instanceof HTMLScriptElement)
  12157. value = getFileName(elt.src);
  12158. return value ? " " + cropString(value, 20) : "";
  12159. },
  12160. attrIterator: function(elt)
  12161. {
  12162. var attrs = [];
  12163. var idAttr, classAttr;
  12164. if (elt.attributes)
  12165. {
  12166. for (var i = 0; i < elt.attributes.length; ++i)
  12167. {
  12168. var attr = elt.attributes[i];
  12169. if (attr.nodeName && attr.nodeName.indexOf("firebug-") != -1)
  12170. continue;
  12171. else if (attr.nodeName == "id")
  12172. idAttr = attr;
  12173. else if (attr.nodeName == "class")
  12174. classAttr = attr;
  12175. else
  12176. attrs.push(attr);
  12177. }
  12178. }
  12179. if (classAttr)
  12180. attrs.splice(0, 0, classAttr);
  12181. if (idAttr)
  12182. attrs.splice(0, 0, idAttr);
  12183. return attrs;
  12184. },
  12185. shortAttrIterator: function(elt)
  12186. {
  12187. var attrs = [];
  12188. if (elt.attributes)
  12189. {
  12190. for (var i = 0; i < elt.attributes.length; ++i)
  12191. {
  12192. var attr = elt.attributes[i];
  12193. if (attr.nodeName == "id" || attr.nodeName == "class")
  12194. attrs.push(attr);
  12195. }
  12196. }
  12197. return attrs;
  12198. },
  12199. getHidden: function(elt)
  12200. {
  12201. return isVisible(elt) ? "" : "nodeHidden";
  12202. },
  12203. getXPath: function(elt)
  12204. {
  12205. return getElementTreeXPath(elt);
  12206. },
  12207. // TODO: xxxpedro remove this?
  12208. getNodeText: function(element)
  12209. {
  12210. var text = element.textContent;
  12211. if (Firebug.showFullTextNodes)
  12212. return text;
  12213. else
  12214. return cropString(text, 50);
  12215. },
  12216. /**/
  12217. getNodeTextGroups: function(element)
  12218. {
  12219. var text = element.textContent;
  12220. if (!Firebug.showFullTextNodes)
  12221. {
  12222. text=cropString(text,50);
  12223. }
  12224. var escapeGroups=[];
  12225. if (Firebug.showTextNodesWithWhitespace)
  12226. escapeGroups.push({
  12227. 'group': 'whitespace',
  12228. 'class': 'nodeWhiteSpace',
  12229. 'extra': {
  12230. '\t': '_Tab',
  12231. '\n': '_Para',
  12232. ' ' : '_Space'
  12233. }
  12234. });
  12235. if (Firebug.showTextNodesWithEntities)
  12236. escapeGroups.push({
  12237. 'group':'text',
  12238. 'class':'nodeTextEntity',
  12239. 'extra':{}
  12240. });
  12241. if (escapeGroups.length)
  12242. return escapeGroupsForEntities(text, escapeGroups);
  12243. else
  12244. return [{str:text,'class':'',extra:''}];
  12245. },
  12246. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12247. copyHTML: function(elt)
  12248. {
  12249. var html = getElementXML(elt);
  12250. copyToClipboard(html);
  12251. },
  12252. copyInnerHTML: function(elt)
  12253. {
  12254. copyToClipboard(elt.innerHTML);
  12255. },
  12256. copyXPath: function(elt)
  12257. {
  12258. var xpath = getElementXPath(elt);
  12259. copyToClipboard(xpath);
  12260. },
  12261. persistor: function(context, xpath)
  12262. {
  12263. var elts = xpath
  12264. ? getElementsByXPath(context.window.document, xpath)
  12265. : null;
  12266. return elts && elts.length ? elts[0] : null;
  12267. },
  12268. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12269. className: "element",
  12270. supportsObject: function(object)
  12271. {
  12272. //return object instanceof Element || object.nodeType == 1 && typeof object.nodeName == "string";
  12273. return instanceOf(object, "Element");
  12274. },
  12275. browseObject: function(elt, context)
  12276. {
  12277. var tag = elt.nodeName.toLowerCase();
  12278. if (tag == "script")
  12279. openNewTab(elt.src);
  12280. else if (tag == "link")
  12281. openNewTab(elt.href);
  12282. else if (tag == "a")
  12283. openNewTab(elt.href);
  12284. else if (tag == "img")
  12285. openNewTab(elt.src);
  12286. return true;
  12287. },
  12288. persistObject: function(elt, context)
  12289. {
  12290. var xpath = getElementXPath(elt);
  12291. return bind(this.persistor, top, xpath);
  12292. },
  12293. getTitle: function(element, context)
  12294. {
  12295. return getElementCSSSelector(element);
  12296. },
  12297. getTooltip: function(elt)
  12298. {
  12299. return this.getXPath(elt);
  12300. },
  12301. getContextMenuItems: function(elt, target, context)
  12302. {
  12303. var monitored = areEventsMonitored(elt, null, context);
  12304. return [
  12305. {label: "CopyHTML", command: bindFixed(this.copyHTML, this, elt) },
  12306. {label: "CopyInnerHTML", command: bindFixed(this.copyInnerHTML, this, elt) },
  12307. {label: "CopyXPath", command: bindFixed(this.copyXPath, this, elt) },
  12308. "-",
  12309. {label: "ShowEventsInConsole", type: "checkbox", checked: monitored,
  12310. command: bindFixed(toggleMonitorEvents, FBL, elt, null, monitored, context) },
  12311. "-",
  12312. {label: "ScrollIntoView", command: bindFixed(elt.scrollIntoView, elt) }
  12313. ];
  12314. }
  12315. });
  12316. // ************************************************************************************************
  12317. this.TextNode = domplate(Firebug.Rep,
  12318. {
  12319. tag:
  12320. OBJECTLINK(
  12321. "&lt;",
  12322. SPAN({"class": "nodeTag"}, "TextNode"),
  12323. "&nbsp;textContent=&quot;", SPAN({"class": "nodeValue"}, "$object.textContent|cropString"), "&quot;",
  12324. "&gt;"
  12325. ),
  12326. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12327. className: "textNode",
  12328. supportsObject: function(object)
  12329. {
  12330. return object instanceof Text;
  12331. }
  12332. });
  12333. // ************************************************************************************************
  12334. this.Document = domplate(Firebug.Rep,
  12335. {
  12336. tag:
  12337. OBJECTLINK("Document ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  12338. getLocation: function(doc)
  12339. {
  12340. return doc.location ? getFileName(doc.location.href) : "";
  12341. },
  12342. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12343. className: "object",
  12344. supportsObject: function(object)
  12345. {
  12346. //return object instanceof Document || object instanceof XMLDocument;
  12347. return instanceOf(object, "Document");
  12348. },
  12349. browseObject: function(doc, context)
  12350. {
  12351. openNewTab(doc.location.href);
  12352. return true;
  12353. },
  12354. persistObject: function(doc, context)
  12355. {
  12356. return this.persistor;
  12357. },
  12358. persistor: function(context)
  12359. {
  12360. return context.window.document;
  12361. },
  12362. getTitle: function(win, context)
  12363. {
  12364. return "document";
  12365. },
  12366. getTooltip: function(doc)
  12367. {
  12368. return doc.location.href;
  12369. }
  12370. });
  12371. // ************************************************************************************************
  12372. this.StyleSheet = domplate(Firebug.Rep,
  12373. {
  12374. tag:
  12375. OBJECTLINK("StyleSheet ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  12376. getLocation: function(styleSheet)
  12377. {
  12378. return getFileName(styleSheet.href);
  12379. },
  12380. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12381. copyURL: function(styleSheet)
  12382. {
  12383. copyToClipboard(styleSheet.href);
  12384. },
  12385. openInTab: function(styleSheet)
  12386. {
  12387. openNewTab(styleSheet.href);
  12388. },
  12389. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12390. className: "object",
  12391. supportsObject: function(object)
  12392. {
  12393. //return object instanceof CSSStyleSheet;
  12394. return instanceOf(object, "CSSStyleSheet");
  12395. },
  12396. browseObject: function(styleSheet, context)
  12397. {
  12398. openNewTab(styleSheet.href);
  12399. return true;
  12400. },
  12401. persistObject: function(styleSheet, context)
  12402. {
  12403. return bind(this.persistor, top, styleSheet.href);
  12404. },
  12405. getTooltip: function(styleSheet)
  12406. {
  12407. return styleSheet.href;
  12408. },
  12409. getContextMenuItems: function(styleSheet, target, context)
  12410. {
  12411. return [
  12412. {label: "CopyLocation", command: bindFixed(this.copyURL, this, styleSheet) },
  12413. "-",
  12414. {label: "OpenInTab", command: bindFixed(this.openInTab, this, styleSheet) }
  12415. ];
  12416. },
  12417. persistor: function(context, href)
  12418. {
  12419. return getStyleSheetByHref(href, context);
  12420. }
  12421. });
  12422. // ************************************************************************************************
  12423. this.Window = domplate(Firebug.Rep,
  12424. {
  12425. tag:
  12426. OBJECTLINK("Window ", SPAN({"class": "objectPropValue"}, "$object|getLocation")),
  12427. getLocation: function(win)
  12428. {
  12429. try
  12430. {
  12431. return (win && win.location && !win.closed) ? getFileName(win.location.href) : "";
  12432. }
  12433. catch (exc)
  12434. {
  12435. if (FBTrace.DBG_ERRORS)
  12436. FBTrace.sysout("reps.Window window closed?");
  12437. }
  12438. },
  12439. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12440. className: "object",
  12441. supportsObject: function(object)
  12442. {
  12443. return instanceOf(object, "Window");
  12444. },
  12445. browseObject: function(win, context)
  12446. {
  12447. openNewTab(win.location.href);
  12448. return true;
  12449. },
  12450. persistObject: function(win, context)
  12451. {
  12452. return this.persistor;
  12453. },
  12454. persistor: function(context)
  12455. {
  12456. return context.window;
  12457. },
  12458. getTitle: function(win, context)
  12459. {
  12460. return "window";
  12461. },
  12462. getTooltip: function(win)
  12463. {
  12464. if (win && !win.closed)
  12465. return win.location.href;
  12466. }
  12467. });
  12468. // ************************************************************************************************
  12469. this.Event = domplate(Firebug.Rep,
  12470. {
  12471. tag: TAG("$copyEventTag", {object: "$object|copyEvent"}),
  12472. copyEventTag:
  12473. OBJECTLINK("$object|summarizeEvent"),
  12474. summarizeEvent: function(event)
  12475. {
  12476. var info = [event.type, ' '];
  12477. var eventFamily = getEventFamily(event.type);
  12478. if (eventFamily == "mouse")
  12479. info.push("clientX=", event.clientX, ", clientY=", event.clientY);
  12480. else if (eventFamily == "key")
  12481. info.push("charCode=", event.charCode, ", keyCode=", event.keyCode);
  12482. return info.join("");
  12483. },
  12484. copyEvent: function(event)
  12485. {
  12486. return new EventCopy(event);
  12487. },
  12488. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12489. className: "object",
  12490. supportsObject: function(object)
  12491. {
  12492. //return object instanceof Event || object instanceof EventCopy;
  12493. return instanceOf(object, "Event") || instanceOf(object, "EventCopy");
  12494. },
  12495. getTitle: function(event, context)
  12496. {
  12497. return "Event " + event.type;
  12498. }
  12499. });
  12500. // ************************************************************************************************
  12501. this.SourceLink = domplate(Firebug.Rep,
  12502. {
  12503. tag:
  12504. OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
  12505. hideSourceLink: function(sourceLink)
  12506. {
  12507. return sourceLink ? sourceLink.href.indexOf("XPCSafeJSObjectWrapper") != -1 : true;
  12508. },
  12509. getSourceLinkTitle: function(sourceLink)
  12510. {
  12511. if (!sourceLink)
  12512. return "";
  12513. try
  12514. {
  12515. var fileName = getFileName(sourceLink.href);
  12516. fileName = decodeURIComponent(fileName);
  12517. fileName = cropString(fileName, 17);
  12518. }
  12519. catch(exc)
  12520. {
  12521. if (FBTrace.DBG_ERRORS)
  12522. FBTrace.sysout("reps.getSourceLinkTitle decodeURIComponent fails for \'"+fileName+"\': "+exc, exc);
  12523. }
  12524. return typeof sourceLink.line == "number" ?
  12525. fileName + " (line " + sourceLink.line + ")" :
  12526. fileName;
  12527. // TODO: xxxpedro
  12528. //return $STRF("Line", [fileName, sourceLink.line]);
  12529. },
  12530. copyLink: function(sourceLink)
  12531. {
  12532. copyToClipboard(sourceLink.href);
  12533. },
  12534. openInTab: function(sourceLink)
  12535. {
  12536. openNewTab(sourceLink.href);
  12537. },
  12538. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12539. className: "sourceLink",
  12540. supportsObject: function(object)
  12541. {
  12542. return object instanceof SourceLink;
  12543. },
  12544. getTooltip: function(sourceLink)
  12545. {
  12546. return decodeURI(sourceLink.href);
  12547. },
  12548. inspectObject: function(sourceLink, context)
  12549. {
  12550. if (sourceLink.type == "js")
  12551. {
  12552. var scriptFile = getSourceFileByHref(sourceLink.href, context);
  12553. if (scriptFile)
  12554. return Firebug.chrome.select(sourceLink);
  12555. }
  12556. else if (sourceLink.type == "css")
  12557. {
  12558. // If an object is defined, treat it as the highest priority for
  12559. // inspect actions
  12560. if (sourceLink.object) {
  12561. Firebug.chrome.select(sourceLink.object);
  12562. return;
  12563. }
  12564. var stylesheet = getStyleSheetByHref(sourceLink.href, context);
  12565. if (stylesheet)
  12566. {
  12567. var ownerNode = stylesheet.ownerNode;
  12568. if (ownerNode)
  12569. {
  12570. Firebug.chrome.select(sourceLink, "html");
  12571. return;
  12572. }
  12573. var panel = context.getPanel("stylesheet");
  12574. if (panel && panel.getRuleByLine(stylesheet, sourceLink.line))
  12575. return Firebug.chrome.select(sourceLink);
  12576. }
  12577. }
  12578. // Fallback is to just open the view-source window on the file
  12579. viewSource(sourceLink.href, sourceLink.line);
  12580. },
  12581. browseObject: function(sourceLink, context)
  12582. {
  12583. openNewTab(sourceLink.href);
  12584. return true;
  12585. },
  12586. getContextMenuItems: function(sourceLink, target, context)
  12587. {
  12588. return [
  12589. {label: "CopyLocation", command: bindFixed(this.copyLink, this, sourceLink) },
  12590. "-",
  12591. {label: "OpenInTab", command: bindFixed(this.openInTab, this, sourceLink) }
  12592. ];
  12593. }
  12594. });
  12595. // ************************************************************************************************
  12596. this.SourceFile = domplate(this.SourceLink,
  12597. {
  12598. tag:
  12599. OBJECTLINK({$collapsed: "$object|hideSourceLink"}, "$object|getSourceLinkTitle"),
  12600. persistor: function(context, href)
  12601. {
  12602. return getSourceFileByHref(href, context);
  12603. },
  12604. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12605. className: "sourceFile",
  12606. supportsObject: function(object)
  12607. {
  12608. return object instanceof SourceFile;
  12609. },
  12610. persistObject: function(sourceFile)
  12611. {
  12612. return bind(this.persistor, top, sourceFile.href);
  12613. },
  12614. browseObject: function(sourceLink, context)
  12615. {
  12616. },
  12617. getTooltip: function(sourceFile)
  12618. {
  12619. return sourceFile.href;
  12620. }
  12621. });
  12622. // ************************************************************************************************
  12623. this.StackFrame = domplate(Firebug.Rep, // XXXjjb Since the repObject is fn the stack does not have correct line numbers
  12624. {
  12625. tag:
  12626. OBJECTBLOCK(
  12627. A({"class": "objectLink objectLink-function focusRow a11yFocus", _repObject: "$object.fn"}, "$object|getCallName"),
  12628. " ( ",
  12629. FOR("arg", "$object|argIterator",
  12630. TAG("$arg.tag", {object: "$arg.value"}),
  12631. SPAN({"class": "arrayComma"}, "$arg.delim")
  12632. ),
  12633. " )",
  12634. SPAN({"class": "objectLink-sourceLink objectLink"}, "$object|getSourceLinkTitle")
  12635. ),
  12636. getCallName: function(frame)
  12637. {
  12638. //TODO: xxxpedro reps StackFrame
  12639. return frame.name || "anonymous";
  12640. //return getFunctionName(frame.script, frame.context);
  12641. },
  12642. getSourceLinkTitle: function(frame)
  12643. {
  12644. //TODO: xxxpedro reps StackFrame
  12645. var fileName = cropString(getFileName(frame.href), 20);
  12646. return fileName + (frame.lineNo ? " (line " + frame.lineNo + ")" : "");
  12647. var fileName = cropString(getFileName(frame.href), 17);
  12648. return $STRF("Line", [fileName, frame.lineNo]);
  12649. },
  12650. argIterator: function(frame)
  12651. {
  12652. if (!frame.args)
  12653. return [];
  12654. var items = [];
  12655. for (var i = 0; i < frame.args.length; ++i)
  12656. {
  12657. var arg = frame.args[i];
  12658. if (!arg)
  12659. break;
  12660. var rep = Firebug.getRep(arg.value);
  12661. var tag = rep.shortTag ? rep.shortTag : rep.tag;
  12662. var delim = (i == frame.args.length-1 ? "" : ", ");
  12663. items.push({name: arg.name, value: arg.value, tag: tag, delim: delim});
  12664. }
  12665. return items;
  12666. },
  12667. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12668. className: "stackFrame",
  12669. supportsObject: function(object)
  12670. {
  12671. return object instanceof StackFrame;
  12672. },
  12673. inspectObject: function(stackFrame, context)
  12674. {
  12675. var sourceLink = new SourceLink(stackFrame.href, stackFrame.lineNo, "js");
  12676. Firebug.chrome.select(sourceLink);
  12677. },
  12678. getTooltip: function(stackFrame, context)
  12679. {
  12680. return $STRF("Line", [stackFrame.href, stackFrame.lineNo]);
  12681. }
  12682. });
  12683. // ************************************************************************************************
  12684. this.StackTrace = domplate(Firebug.Rep,
  12685. {
  12686. tag:
  12687. FOR("frame", "$object.frames focusRow",
  12688. TAG(this.StackFrame.tag, {object: "$frame"})
  12689. ),
  12690. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12691. className: "stackTrace",
  12692. supportsObject: function(object)
  12693. {
  12694. return object instanceof StackTrace;
  12695. }
  12696. });
  12697. // ************************************************************************************************
  12698. this.jsdStackFrame = domplate(Firebug.Rep,
  12699. {
  12700. inspectable: false,
  12701. supportsObject: function(object)
  12702. {
  12703. return (object instanceof jsdIStackFrame) && (object.isValid);
  12704. },
  12705. getTitle: function(frame, context)
  12706. {
  12707. if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null
  12708. return getFunctionName(frame.script, context);
  12709. },
  12710. getTooltip: function(frame, context)
  12711. {
  12712. if (!frame.isValid) return "(invalid frame)"; // XXXjjb avoid frame.script == null
  12713. var sourceInfo = FBL.getSourceFileAndLineByScript(context, frame.script, frame);
  12714. if (sourceInfo)
  12715. return $STRF("Line", [sourceInfo.sourceFile.href, sourceInfo.lineNo]);
  12716. else
  12717. return $STRF("Line", [frame.script.fileName, frame.line]);
  12718. },
  12719. getContextMenuItems: function(frame, target, context)
  12720. {
  12721. var fn = frame.script.functionObject.getWrappedValue();
  12722. return FirebugReps.Func.getContextMenuItems(fn, target, context, frame.script);
  12723. }
  12724. });
  12725. // ************************************************************************************************
  12726. this.ErrorMessage = domplate(Firebug.Rep,
  12727. {
  12728. tag:
  12729. OBJECTBOX({
  12730. $hasTwisty: "$object|hasStackTrace",
  12731. $hasBreakSwitch: "$object|hasBreakSwitch",
  12732. $breakForError: "$object|hasErrorBreak",
  12733. _repObject: "$object",
  12734. _stackTrace: "$object|getLastErrorStackTrace",
  12735. onclick: "$onToggleError"},
  12736. DIV({"class": "errorTitle a11yFocus", role : 'checkbox', 'aria-checked' : 'false'},
  12737. "$object.message|getMessage"
  12738. ),
  12739. DIV({"class": "errorTrace"}),
  12740. DIV({"class": "errorSourceBox errorSource-$object|getSourceType"},
  12741. IMG({"class": "errorBreak a11yFocus", src:"blank.gif", role : 'checkbox', 'aria-checked':'false', title: "Break on this error"}),
  12742. A({"class": "errorSource a11yFocus"}, "$object|getLine")
  12743. ),
  12744. TAG(this.SourceLink.tag, {object: "$object|getSourceLink"})
  12745. ),
  12746. getLastErrorStackTrace: function(error)
  12747. {
  12748. return error.trace;
  12749. },
  12750. hasStackTrace: function(error)
  12751. {
  12752. var url = error.href.toString();
  12753. var fromCommandLine = (url.indexOf("XPCSafeJSObjectWrapper") != -1);
  12754. return !fromCommandLine && error.trace;
  12755. },
  12756. hasBreakSwitch: function(error)
  12757. {
  12758. return error.href && error.lineNo > 0;
  12759. },
  12760. hasErrorBreak: function(error)
  12761. {
  12762. return fbs.hasErrorBreakpoint(error.href, error.lineNo);
  12763. },
  12764. getMessage: function(message)
  12765. {
  12766. var re = /\[Exception... "(.*?)" nsresult:/;
  12767. var m = re.exec(message);
  12768. return m ? m[1] : message;
  12769. },
  12770. getLine: function(error)
  12771. {
  12772. if (error.category == "js")
  12773. {
  12774. if (error.source)
  12775. return cropString(error.source, 80);
  12776. else if (error.href && error.href.indexOf("XPCSafeJSObjectWrapper") == -1)
  12777. return cropString(error.getSourceLine(), 80);
  12778. }
  12779. },
  12780. getSourceLink: function(error)
  12781. {
  12782. var ext = error.category == "css" ? "css" : "js";
  12783. return error.lineNo ? new SourceLink(error.href, error.lineNo, ext) : null;
  12784. },
  12785. getSourceType: function(error)
  12786. {
  12787. // Errors occurring inside of HTML event handlers look like "foo.html (line 1)"
  12788. // so let's try to skip those
  12789. if (error.source)
  12790. return "syntax";
  12791. else if (error.lineNo == 1 && getFileExtension(error.href) != "js")
  12792. return "none";
  12793. else if (error.category == "css")
  12794. return "none";
  12795. else if (!error.href || !error.lineNo)
  12796. return "none";
  12797. else
  12798. return "exec";
  12799. },
  12800. onToggleError: function(event)
  12801. {
  12802. var target = event.currentTarget;
  12803. if (hasClass(event.target, "errorBreak"))
  12804. {
  12805. this.breakOnThisError(target.repObject);
  12806. }
  12807. else if (hasClass(event.target, "errorSource"))
  12808. {
  12809. var panel = Firebug.getElementPanel(event.target);
  12810. this.inspectObject(target.repObject, panel.context);
  12811. }
  12812. else if (hasClass(event.target, "errorTitle"))
  12813. {
  12814. var traceBox = target.childNodes[1];
  12815. toggleClass(target, "opened");
  12816. event.target.setAttribute('aria-checked', hasClass(target, "opened"));
  12817. if (hasClass(target, "opened"))
  12818. {
  12819. if (target.stackTrace)
  12820. var node = FirebugReps.StackTrace.tag.append({object: target.stackTrace}, traceBox);
  12821. if (Firebug.A11yModel.enabled)
  12822. {
  12823. var panel = Firebug.getElementPanel(event.target);
  12824. dispatch([Firebug.A11yModel], "onLogRowContentCreated", [panel , traceBox]);
  12825. }
  12826. }
  12827. else
  12828. clearNode(traceBox);
  12829. }
  12830. },
  12831. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12832. copyError: function(error)
  12833. {
  12834. var message = [
  12835. this.getMessage(error.message),
  12836. error.href,
  12837. "Line " + error.lineNo
  12838. ];
  12839. copyToClipboard(message.join("\n"));
  12840. },
  12841. breakOnThisError: function(error)
  12842. {
  12843. if (this.hasErrorBreak(error))
  12844. Firebug.Debugger.clearErrorBreakpoint(error.href, error.lineNo);
  12845. else
  12846. Firebug.Debugger.setErrorBreakpoint(error.href, error.lineNo);
  12847. },
  12848. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12849. className: "errorMessage",
  12850. inspectable: false,
  12851. supportsObject: function(object)
  12852. {
  12853. return object instanceof ErrorMessage;
  12854. },
  12855. inspectObject: function(error, context)
  12856. {
  12857. var sourceLink = this.getSourceLink(error);
  12858. FirebugReps.SourceLink.inspectObject(sourceLink, context);
  12859. },
  12860. getContextMenuItems: function(error, target, context)
  12861. {
  12862. var breakOnThisError = this.hasErrorBreak(error);
  12863. var items = [
  12864. {label: "CopyError", command: bindFixed(this.copyError, this, error) }
  12865. ];
  12866. if (error.category == "css")
  12867. {
  12868. items.push(
  12869. "-",
  12870. {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
  12871. command: bindFixed(this.breakOnThisError, this, error) },
  12872. optionMenu("BreakOnAllErrors", "breakOnErrors")
  12873. );
  12874. }
  12875. return items;
  12876. }
  12877. });
  12878. // ************************************************************************************************
  12879. this.Assert = domplate(Firebug.Rep,
  12880. {
  12881. tag:
  12882. DIV(
  12883. DIV({"class": "errorTitle"}),
  12884. DIV({"class": "assertDescription"})
  12885. ),
  12886. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12887. className: "assert",
  12888. inspectObject: function(error, context)
  12889. {
  12890. var sourceLink = this.getSourceLink(error);
  12891. Firebug.chrome.select(sourceLink);
  12892. },
  12893. getContextMenuItems: function(error, target, context)
  12894. {
  12895. var breakOnThisError = this.hasErrorBreak(error);
  12896. return [
  12897. {label: "CopyError", command: bindFixed(this.copyError, this, error) },
  12898. "-",
  12899. {label: "BreakOnThisError", type: "checkbox", checked: breakOnThisError,
  12900. command: bindFixed(this.breakOnThisError, this, error) },
  12901. {label: "BreakOnAllErrors", type: "checkbox", checked: Firebug.breakOnErrors,
  12902. command: bindFixed(this.breakOnAllErrors, this, error) }
  12903. ];
  12904. }
  12905. });
  12906. // ************************************************************************************************
  12907. this.SourceText = domplate(Firebug.Rep,
  12908. {
  12909. tag:
  12910. DIV(
  12911. FOR("line", "$object|lineIterator",
  12912. DIV({"class": "sourceRow", role : "presentation"},
  12913. SPAN({"class": "sourceLine", role : "presentation"}, "$line.lineNo"),
  12914. SPAN({"class": "sourceRowText", role : "presentation"}, "$line.text")
  12915. )
  12916. )
  12917. ),
  12918. lineIterator: function(sourceText)
  12919. {
  12920. var maxLineNoChars = (sourceText.lines.length + "").length;
  12921. var list = [];
  12922. for (var i = 0; i < sourceText.lines.length; ++i)
  12923. {
  12924. // Make sure all line numbers are the same width (with a fixed-width font)
  12925. var lineNo = (i+1) + "";
  12926. while (lineNo.length < maxLineNoChars)
  12927. lineNo = " " + lineNo;
  12928. list.push({lineNo: lineNo, text: sourceText.lines[i]});
  12929. }
  12930. return list;
  12931. },
  12932. getHTML: function(sourceText)
  12933. {
  12934. return getSourceLineRange(sourceText, 1, sourceText.lines.length);
  12935. }
  12936. });
  12937. //************************************************************************************************
  12938. this.nsIDOMHistory = domplate(Firebug.Rep,
  12939. {
  12940. tag:OBJECTBOX({onclick: "$showHistory"},
  12941. OBJECTLINK("$object|summarizeHistory")
  12942. ),
  12943. className: "nsIDOMHistory",
  12944. summarizeHistory: function(history)
  12945. {
  12946. try
  12947. {
  12948. var items = history.length;
  12949. return items + " history entries";
  12950. }
  12951. catch(exc)
  12952. {
  12953. return "object does not support history (nsIDOMHistory)";
  12954. }
  12955. },
  12956. showHistory: function(history)
  12957. {
  12958. try
  12959. {
  12960. var items = history.length; // if this throws, then unsupported
  12961. Firebug.chrome.select(history);
  12962. }
  12963. catch (exc)
  12964. {
  12965. }
  12966. },
  12967. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12968. supportsObject: function(object, type)
  12969. {
  12970. return (object instanceof Ci.nsIDOMHistory);
  12971. }
  12972. });
  12973. // ************************************************************************************************
  12974. this.ApplicationCache = domplate(Firebug.Rep,
  12975. {
  12976. tag:OBJECTBOX({onclick: "$showApplicationCache"},
  12977. OBJECTLINK("$object|summarizeCache")
  12978. ),
  12979. summarizeCache: function(applicationCache)
  12980. {
  12981. try
  12982. {
  12983. return applicationCache.length + " items in offline cache";
  12984. }
  12985. catch(exc)
  12986. {
  12987. return "https://bugzilla.mozilla.org/show_bug.cgi?id=422264";
  12988. }
  12989. },
  12990. showApplicationCache: function(event)
  12991. {
  12992. openNewTab("https://bugzilla.mozilla.org/show_bug.cgi?id=422264");
  12993. },
  12994. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  12995. className: "applicationCache",
  12996. supportsObject: function(object, type)
  12997. {
  12998. if (Ci.nsIDOMOfflineResourceList)
  12999. return (object instanceof Ci.nsIDOMOfflineResourceList);
  13000. }
  13001. });
  13002. this.Storage = domplate(Firebug.Rep,
  13003. {
  13004. tag: OBJECTBOX({onclick: "$show"}, OBJECTLINK("$object|summarize")),
  13005. summarize: function(storage)
  13006. {
  13007. return storage.length +" items in Storage";
  13008. },
  13009. show: function(storage)
  13010. {
  13011. openNewTab("http://dev.w3.org/html5/webstorage/#storage-0");
  13012. },
  13013. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13014. className: "Storage",
  13015. supportsObject: function(object, type)
  13016. {
  13017. return (object instanceof Storage);
  13018. }
  13019. });
  13020. // ************************************************************************************************
  13021. Firebug.registerRep(
  13022. //this.nsIDOMHistory, // make this early to avoid exceptions
  13023. this.Undefined,
  13024. this.Null,
  13025. this.Number,
  13026. this.String,
  13027. this.Window,
  13028. //this.ApplicationCache, // must come before Arr (array) else exceptions.
  13029. //this.ErrorMessage,
  13030. this.Element,
  13031. //this.TextNode,
  13032. this.Document,
  13033. this.StyleSheet,
  13034. this.Event,
  13035. //this.SourceLink,
  13036. //this.SourceFile,
  13037. //this.StackTrace,
  13038. //this.StackFrame,
  13039. //this.jsdStackFrame,
  13040. //this.jsdScript,
  13041. //this.NetFile,
  13042. this.Property,
  13043. this.Except,
  13044. this.Arr
  13045. );
  13046. Firebug.setDefaultReps(this.Func, this.Obj);
  13047. }});
  13048. // ************************************************************************************************
  13049. /*
  13050. * The following is http://developer.yahoo.com/yui/license.txt and applies to only code labeled "Yahoo BSD Source"
  13051. * in only this file reps.js. John J. Barton June 2007.
  13052. *
  13053. Software License Agreement (BSD License)
  13054. Copyright (c) 2006, Yahoo! Inc.
  13055. All rights reserved.
  13056. Redistribution and use of this software in source and binary forms, with or without modification, are
  13057. permitted provided that the following conditions are met:
  13058. * Redistributions of source code must retain the above
  13059. copyright notice, this list of conditions and the
  13060. following disclaimer.
  13061. * Redistributions in binary form must reproduce the above
  13062. copyright notice, this list of conditions and the
  13063. following disclaimer in the documentation and/or other
  13064. materials provided with the distribution.
  13065. * Neither the name of Yahoo! Inc. nor the names of its
  13066. contributors may be used to endorse or promote products
  13067. derived from this software without specific prior
  13068. written permission of Yahoo! Inc.
  13069. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
  13070. WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  13071. PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  13072. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  13073. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13074. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  13075. TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  13076. ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  13077. * /
  13078. */
  13079. /* See license.txt for terms of usage */
  13080. FBL.ns(function() { with (FBL) {
  13081. // ************************************************************************************************
  13082. // Constants
  13083. var saveTimeout = 400;
  13084. var pageAmount = 10;
  13085. // ************************************************************************************************
  13086. // Globals
  13087. var currentTarget = null;
  13088. var currentGroup = null;
  13089. var currentPanel = null;
  13090. var currentEditor = null;
  13091. var defaultEditor = null;
  13092. var originalClassName = null;
  13093. var originalValue = null;
  13094. var defaultValue = null;
  13095. var previousValue = null;
  13096. var invalidEditor = false;
  13097. var ignoreNextInput = false;
  13098. // ************************************************************************************************
  13099. Firebug.Editor = extend(Firebug.Module,
  13100. {
  13101. supportsStopEvent: true,
  13102. dispatchName: "editor",
  13103. tabCharacter: " ",
  13104. startEditing: function(target, value, editor)
  13105. {
  13106. this.stopEditing();
  13107. if (hasClass(target, "insertBefore") || hasClass(target, "insertAfter"))
  13108. return;
  13109. var panel = Firebug.getElementPanel(target);
  13110. if (!panel.editable)
  13111. return;
  13112. if (FBTrace.DBG_EDITOR)
  13113. FBTrace.sysout("editor.startEditing " + value, target);
  13114. defaultValue = target.getAttribute("defaultValue");
  13115. if (value == undefined)
  13116. {
  13117. var textContent = isIE ? "innerText" : "textContent";
  13118. value = target[textContent];
  13119. if (value == defaultValue)
  13120. value = "";
  13121. }
  13122. originalValue = previousValue = value;
  13123. invalidEditor = false;
  13124. currentTarget = target;
  13125. currentPanel = panel;
  13126. currentGroup = getAncestorByClass(target, "editGroup");
  13127. currentPanel.editing = true;
  13128. var panelEditor = currentPanel.getEditor(target, value);
  13129. currentEditor = editor ? editor : panelEditor;
  13130. if (!currentEditor)
  13131. currentEditor = getDefaultEditor(currentPanel);
  13132. var inlineParent = getInlineParent(target);
  13133. var targetSize = getOffsetSize(inlineParent);
  13134. setClass(panel.panelNode, "editing");
  13135. setClass(target, "editing");
  13136. if (currentGroup)
  13137. setClass(currentGroup, "editing");
  13138. currentEditor.show(target, currentPanel, value, targetSize);
  13139. //dispatch(this.fbListeners, "onBeginEditing", [currentPanel, currentEditor, target, value]);
  13140. currentEditor.beginEditing(target, value);
  13141. if (FBTrace.DBG_EDITOR)
  13142. FBTrace.sysout("Editor start panel "+currentPanel.name);
  13143. this.attachListeners(currentEditor, panel.context);
  13144. },
  13145. stopEditing: function(cancel)
  13146. {
  13147. if (!currentTarget)
  13148. return;
  13149. if (FBTrace.DBG_EDITOR)
  13150. FBTrace.sysout("editor.stopEditing cancel:" + cancel+" saveTimeout: "+this.saveTimeout);
  13151. clearTimeout(this.saveTimeout);
  13152. delete this.saveTimeout;
  13153. this.detachListeners(currentEditor, currentPanel.context);
  13154. removeClass(currentPanel.panelNode, "editing");
  13155. removeClass(currentTarget, "editing");
  13156. if (currentGroup)
  13157. removeClass(currentGroup, "editing");
  13158. var value = currentEditor.getValue();
  13159. if (value == defaultValue)
  13160. value = "";
  13161. var removeGroup = currentEditor.endEditing(currentTarget, value, cancel);
  13162. try
  13163. {
  13164. if (cancel)
  13165. {
  13166. //dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, removeGroup && !originalValue]);
  13167. if (value != originalValue)
  13168. this.saveEditAndNotifyListeners(currentTarget, originalValue, previousValue);
  13169. if (removeGroup && !originalValue && currentGroup)
  13170. currentGroup.parentNode.removeChild(currentGroup);
  13171. }
  13172. else if (!value)
  13173. {
  13174. this.saveEditAndNotifyListeners(currentTarget, null, previousValue);
  13175. if (removeGroup && currentGroup)
  13176. currentGroup.parentNode.removeChild(currentGroup);
  13177. }
  13178. else
  13179. this.save(value);
  13180. }
  13181. catch (exc)
  13182. {
  13183. //throw exc.message;
  13184. //ERROR(exc);
  13185. }
  13186. currentEditor.hide();
  13187. currentPanel.editing = false;
  13188. //dispatch(this.fbListeners, "onStopEdit", [currentPanel, currentEditor, currentTarget]);
  13189. //if (FBTrace.DBG_EDITOR)
  13190. // FBTrace.sysout("Editor stop panel "+currentPanel.name);
  13191. currentTarget = null;
  13192. currentGroup = null;
  13193. currentPanel = null;
  13194. currentEditor = null;
  13195. originalValue = null;
  13196. invalidEditor = false;
  13197. return value;
  13198. },
  13199. cancelEditing: function()
  13200. {
  13201. return this.stopEditing(true);
  13202. },
  13203. update: function(saveNow)
  13204. {
  13205. if (this.saveTimeout)
  13206. clearTimeout(this.saveTimeout);
  13207. invalidEditor = true;
  13208. currentEditor.layout();
  13209. if (saveNow)
  13210. this.save();
  13211. else
  13212. {
  13213. var context = currentPanel.context;
  13214. this.saveTimeout = context.setTimeout(bindFixed(this.save, this), saveTimeout);
  13215. if (FBTrace.DBG_EDITOR)
  13216. FBTrace.sysout("editor.update saveTimeout: "+this.saveTimeout);
  13217. }
  13218. },
  13219. save: function(value)
  13220. {
  13221. if (!invalidEditor)
  13222. return;
  13223. if (value == undefined)
  13224. value = currentEditor.getValue();
  13225. if (FBTrace.DBG_EDITOR)
  13226. FBTrace.sysout("editor.save saveTimeout: "+this.saveTimeout+" currentPanel: "+(currentPanel?currentPanel.name:"null"));
  13227. try
  13228. {
  13229. this.saveEditAndNotifyListeners(currentTarget, value, previousValue);
  13230. previousValue = value;
  13231. invalidEditor = false;
  13232. }
  13233. catch (exc)
  13234. {
  13235. if (FBTrace.DBG_ERRORS)
  13236. FBTrace.sysout("editor.save FAILS "+exc, exc);
  13237. }
  13238. },
  13239. saveEditAndNotifyListeners: function(currentTarget, value, previousValue)
  13240. {
  13241. currentEditor.saveEdit(currentTarget, value, previousValue);
  13242. //dispatch(this.fbListeners, "onSaveEdit", [currentPanel, currentEditor, currentTarget, value, previousValue]);
  13243. },
  13244. setEditTarget: function(element)
  13245. {
  13246. if (!element)
  13247. {
  13248. dispatch([Firebug.A11yModel], 'onInlineEditorClose', [currentPanel, currentTarget, true]);
  13249. this.stopEditing();
  13250. }
  13251. else if (hasClass(element, "insertBefore"))
  13252. this.insertRow(element, "before");
  13253. else if (hasClass(element, "insertAfter"))
  13254. this.insertRow(element, "after");
  13255. else
  13256. this.startEditing(element);
  13257. },
  13258. tabNextEditor: function()
  13259. {
  13260. if (!currentTarget)
  13261. return;
  13262. var value = currentEditor.getValue();
  13263. var nextEditable = currentTarget;
  13264. do
  13265. {
  13266. nextEditable = !value && currentGroup
  13267. ? getNextOutsider(nextEditable, currentGroup)
  13268. : getNextByClass(nextEditable, "editable");
  13269. }
  13270. while (nextEditable && !nextEditable.offsetHeight);
  13271. this.setEditTarget(nextEditable);
  13272. },
  13273. tabPreviousEditor: function()
  13274. {
  13275. if (!currentTarget)
  13276. return;
  13277. var value = currentEditor.getValue();
  13278. var prevEditable = currentTarget;
  13279. do
  13280. {
  13281. prevEditable = !value && currentGroup
  13282. ? getPreviousOutsider(prevEditable, currentGroup)
  13283. : getPreviousByClass(prevEditable, "editable");
  13284. }
  13285. while (prevEditable && !prevEditable.offsetHeight);
  13286. this.setEditTarget(prevEditable);
  13287. },
  13288. insertRow: function(relative, insertWhere)
  13289. {
  13290. var group =
  13291. relative || getAncestorByClass(currentTarget, "editGroup") || currentTarget;
  13292. var value = this.stopEditing();
  13293. currentPanel = Firebug.getElementPanel(group);
  13294. currentEditor = currentPanel.getEditor(group, value);
  13295. if (!currentEditor)
  13296. currentEditor = getDefaultEditor(currentPanel);
  13297. currentGroup = currentEditor.insertNewRow(group, insertWhere);
  13298. if (!currentGroup)
  13299. return;
  13300. var editable = hasClass(currentGroup, "editable")
  13301. ? currentGroup
  13302. : getNextByClass(currentGroup, "editable");
  13303. if (editable)
  13304. this.setEditTarget(editable);
  13305. },
  13306. insertRowForObject: function(relative)
  13307. {
  13308. var container = getAncestorByClass(relative, "insertInto");
  13309. if (container)
  13310. {
  13311. relative = getChildByClass(container, "insertBefore");
  13312. if (relative)
  13313. this.insertRow(relative, "before");
  13314. }
  13315. },
  13316. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13317. attachListeners: function(editor, context)
  13318. {
  13319. var win = isIE ?
  13320. currentTarget.ownerDocument.parentWindow :
  13321. currentTarget.ownerDocument.defaultView;
  13322. addEvent(win, "resize", this.onResize);
  13323. addEvent(win, "blur", this.onBlur);
  13324. var chrome = Firebug.chrome;
  13325. this.listeners = [
  13326. chrome.keyCodeListen("ESCAPE", null, bind(this.cancelEditing, this))
  13327. ];
  13328. if (editor.arrowCompletion)
  13329. {
  13330. this.listeners.push(
  13331. chrome.keyCodeListen("UP", null, bindFixed(editor.completeValue, editor, -1)),
  13332. chrome.keyCodeListen("DOWN", null, bindFixed(editor.completeValue, editor, 1)),
  13333. chrome.keyCodeListen("PAGE_UP", null, bindFixed(editor.completeValue, editor, -pageAmount)),
  13334. chrome.keyCodeListen("PAGE_DOWN", null, bindFixed(editor.completeValue, editor, pageAmount))
  13335. );
  13336. }
  13337. if (currentEditor.tabNavigation)
  13338. {
  13339. this.listeners.push(
  13340. chrome.keyCodeListen("RETURN", null, bind(this.tabNextEditor, this)),
  13341. chrome.keyCodeListen("RETURN", isControl, bind(this.insertRow, this, null, "after")),
  13342. chrome.keyCodeListen("TAB", null, bind(this.tabNextEditor, this)),
  13343. chrome.keyCodeListen("TAB", isShift, bind(this.tabPreviousEditor, this))
  13344. );
  13345. }
  13346. else if (currentEditor.multiLine)
  13347. {
  13348. this.listeners.push(
  13349. chrome.keyCodeListen("TAB", null, insertTab)
  13350. );
  13351. }
  13352. else
  13353. {
  13354. this.listeners.push(
  13355. chrome.keyCodeListen("RETURN", null, bindFixed(this.stopEditing, this))
  13356. );
  13357. if (currentEditor.tabCompletion)
  13358. {
  13359. this.listeners.push(
  13360. chrome.keyCodeListen("TAB", null, bind(editor.completeValue, editor, 1)),
  13361. chrome.keyCodeListen("TAB", isShift, bind(editor.completeValue, editor, -1))
  13362. );
  13363. }
  13364. }
  13365. },
  13366. detachListeners: function(editor, context)
  13367. {
  13368. if (!this.listeners)
  13369. return;
  13370. var win = isIE ?
  13371. currentTarget.ownerDocument.parentWindow :
  13372. currentTarget.ownerDocument.defaultView;
  13373. removeEvent(win, "resize", this.onResize);
  13374. removeEvent(win, "blur", this.onBlur);
  13375. var chrome = Firebug.chrome;
  13376. if (chrome)
  13377. {
  13378. for (var i = 0; i < this.listeners.length; ++i)
  13379. chrome.keyIgnore(this.listeners[i]);
  13380. }
  13381. delete this.listeners;
  13382. },
  13383. onResize: function(event)
  13384. {
  13385. currentEditor.layout(true);
  13386. },
  13387. onBlur: function(event)
  13388. {
  13389. if (currentEditor.enterOnBlur && isAncestor(event.target, currentEditor.box))
  13390. this.stopEditing();
  13391. },
  13392. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13393. // extends Module
  13394. initialize: function()
  13395. {
  13396. Firebug.Module.initialize.apply(this, arguments);
  13397. this.onResize = bindFixed(this.onResize, this);
  13398. this.onBlur = bind(this.onBlur, this);
  13399. },
  13400. disable: function()
  13401. {
  13402. this.stopEditing();
  13403. },
  13404. showContext: function(browser, context)
  13405. {
  13406. this.stopEditing();
  13407. },
  13408. showPanel: function(browser, panel)
  13409. {
  13410. this.stopEditing();
  13411. }
  13412. });
  13413. // ************************************************************************************************
  13414. // BaseEditor
  13415. Firebug.BaseEditor = extend(Firebug.MeasureBox,
  13416. {
  13417. getValue: function()
  13418. {
  13419. },
  13420. setValue: function(value)
  13421. {
  13422. },
  13423. show: function(target, panel, value, textSize, targetSize)
  13424. {
  13425. },
  13426. hide: function()
  13427. {
  13428. },
  13429. layout: function(forceAll)
  13430. {
  13431. },
  13432. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13433. // Support for context menus within inline editors.
  13434. getContextMenuItems: function(target)
  13435. {
  13436. var items = [];
  13437. items.push({label: "Cut", commandID: "cmd_cut"});
  13438. items.push({label: "Copy", commandID: "cmd_copy"});
  13439. items.push({label: "Paste", commandID: "cmd_paste"});
  13440. return items;
  13441. },
  13442. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13443. // Editor Module listeners will get "onBeginEditing" just before this call
  13444. beginEditing: function(target, value)
  13445. {
  13446. },
  13447. // Editor Module listeners will get "onSaveEdit" just after this call
  13448. saveEdit: function(target, value, previousValue)
  13449. {
  13450. },
  13451. endEditing: function(target, value, cancel)
  13452. {
  13453. // Remove empty groups by default
  13454. return true;
  13455. },
  13456. insertNewRow: function(target, insertWhere)
  13457. {
  13458. }
  13459. });
  13460. // ************************************************************************************************
  13461. // InlineEditor
  13462. // basic inline editor attributes
  13463. var inlineEditorAttributes = {
  13464. "class": "textEditorInner",
  13465. type: "text",
  13466. spellcheck: "false",
  13467. onkeypress: "$onKeyPress",
  13468. onoverflow: "$onOverflow",
  13469. oncontextmenu: "$onContextMenu"
  13470. };
  13471. // IE does not support the oninput event, so we're using the onkeydown to signalize
  13472. // the relevant keyboard events, and the onpropertychange to actually handle the
  13473. // input event, which should happen after the onkeydown event is fired and after the
  13474. // value of the input is updated, but before the onkeyup and before the input (with the
  13475. // new value) is rendered
  13476. if (isIE)
  13477. {
  13478. inlineEditorAttributes.onpropertychange = "$onInput";
  13479. inlineEditorAttributes.onkeydown = "$onKeyDown";
  13480. }
  13481. // for other browsers we use the oninput event
  13482. else
  13483. {
  13484. inlineEditorAttributes.oninput = "$onInput";
  13485. }
  13486. Firebug.InlineEditor = function(doc)
  13487. {
  13488. this.initializeInline(doc);
  13489. };
  13490. Firebug.InlineEditor.prototype = domplate(Firebug.BaseEditor,
  13491. {
  13492. enterOnBlur: true,
  13493. outerMargin: 8,
  13494. shadowExpand: 7,
  13495. tag:
  13496. DIV({"class": "inlineEditor"},
  13497. DIV({"class": "textEditorTop1"},
  13498. DIV({"class": "textEditorTop2"})
  13499. ),
  13500. DIV({"class": "textEditorInner1"},
  13501. DIV({"class": "textEditorInner2"},
  13502. INPUT(
  13503. inlineEditorAttributes
  13504. )
  13505. )
  13506. ),
  13507. DIV({"class": "textEditorBottom1"},
  13508. DIV({"class": "textEditorBottom2"})
  13509. )
  13510. ),
  13511. inputTag :
  13512. INPUT({"class": "textEditorInner", type: "text",
  13513. /*oninput: "$onInput",*/ onkeypress: "$onKeyPress", onoverflow: "$onOverflow"}
  13514. ),
  13515. expanderTag:
  13516. IMG({"class": "inlineExpander", src: "blank.gif"}),
  13517. initialize: function()
  13518. {
  13519. this.fixedWidth = false;
  13520. this.completeAsYouType = true;
  13521. this.tabNavigation = true;
  13522. this.multiLine = false;
  13523. this.tabCompletion = false;
  13524. this.arrowCompletion = true;
  13525. this.noWrap = true;
  13526. this.numeric = false;
  13527. },
  13528. destroy: function()
  13529. {
  13530. this.destroyInput();
  13531. },
  13532. initializeInline: function(doc)
  13533. {
  13534. if (FBTrace.DBG_EDITOR)
  13535. FBTrace.sysout("Firebug.InlineEditor initializeInline()");
  13536. //this.box = this.tag.replace({}, doc, this);
  13537. this.box = this.tag.append({}, doc.body, this);
  13538. //this.input = this.box.childNodes[1].firstChild.firstChild; // XXXjjb childNode[1] required
  13539. this.input = this.box.getElementsByTagName("input")[0];
  13540. if (isIElt8)
  13541. {
  13542. this.input.style.top = "-8px";
  13543. }
  13544. this.expander = this.expanderTag.replace({}, doc, this);
  13545. this.initialize();
  13546. },
  13547. destroyInput: function()
  13548. {
  13549. // XXXjoe Need to remove input/keypress handlers to avoid leaks
  13550. },
  13551. getValue: function()
  13552. {
  13553. return this.input.value;
  13554. },
  13555. setValue: function(value)
  13556. {
  13557. // It's only a one-line editor, so new lines shouldn't be allowed
  13558. return this.input.value = stripNewLines(value);
  13559. },
  13560. show: function(target, panel, value, targetSize)
  13561. {
  13562. //dispatch([Firebug.A11yModel], "onInlineEditorShow", [panel, this]);
  13563. this.target = target;
  13564. this.panel = panel;
  13565. this.targetSize = targetSize;
  13566. // TODO: xxxpedro editor
  13567. //this.targetOffset = getClientOffset(target);
  13568. // Some browsers (IE, Google Chrome and Safari) will have problem trying to get the
  13569. // offset values of invisible elements, or empty elements. So, in order to get the
  13570. // correct values, we temporary inject a character in the innerHTML of the empty element,
  13571. // then we get the offset values, and next, we restore the original innerHTML value.
  13572. var innerHTML = target.innerHTML;
  13573. var isEmptyElement = !innerHTML;
  13574. if (isEmptyElement)
  13575. target.innerHTML = ".";
  13576. // Get the position of the target element (that is about to be edited)
  13577. this.targetOffset =
  13578. {
  13579. x: target.offsetLeft,
  13580. y: target.offsetTop
  13581. };
  13582. // Restore the original innerHTML value of the empty element
  13583. if (isEmptyElement)
  13584. target.innerHTML = innerHTML;
  13585. this.originalClassName = this.box.className;
  13586. var classNames = target.className.split(" ");
  13587. for (var i = 0; i < classNames.length; ++i)
  13588. setClass(this.box, "editor-" + classNames[i]);
  13589. // Make the editor match the target's font style
  13590. copyTextStyles(target, this.box);
  13591. this.setValue(value);
  13592. if (this.fixedWidth)
  13593. this.updateLayout(true);
  13594. else
  13595. {
  13596. this.startMeasuring(target);
  13597. this.textSize = this.measureInputText(value);
  13598. // Correct the height of the box to make the funky CSS drop-shadow line up
  13599. var parent = this.input.parentNode;
  13600. if (hasClass(parent, "textEditorInner2"))
  13601. {
  13602. var yDiff = this.textSize.height - this.shadowExpand;
  13603. // IE6 height offset
  13604. if (isIE6)
  13605. yDiff -= 2;
  13606. parent.style.height = yDiff + "px";
  13607. parent.parentNode.style.height = yDiff + "px";
  13608. }
  13609. this.updateLayout(true);
  13610. }
  13611. this.getAutoCompleter().reset();
  13612. if (isIElt8)
  13613. panel.panelNode.appendChild(this.box);
  13614. else
  13615. target.offsetParent.appendChild(this.box);
  13616. //console.log(target);
  13617. //this.input.select(); // it's called bellow, with setTimeout
  13618. if (isIE)
  13619. {
  13620. // reset input style
  13621. this.input.style.fontFamily = "Monospace";
  13622. this.input.style.fontSize = "11px";
  13623. }
  13624. // Insert the "expander" to cover the target element with white space
  13625. if (!this.fixedWidth)
  13626. {
  13627. copyBoxStyles(target, this.expander);
  13628. target.parentNode.replaceChild(this.expander, target);
  13629. collapse(target, true);
  13630. this.expander.parentNode.insertBefore(target, this.expander);
  13631. }
  13632. //TODO: xxxpedro
  13633. //scrollIntoCenterView(this.box, null, true);
  13634. // Display the editor after change its size and position to avoid flickering
  13635. this.box.style.display = "block";
  13636. // we need to call input.focus() and input.select() with a timeout,
  13637. // otherwise it won't work on all browsers due to timing issues
  13638. var self = this;
  13639. setTimeout(function(){
  13640. self.input.focus();
  13641. self.input.select();
  13642. },0);
  13643. },
  13644. hide: function()
  13645. {
  13646. this.box.className = this.originalClassName;
  13647. if (!this.fixedWidth)
  13648. {
  13649. this.stopMeasuring();
  13650. collapse(this.target, false);
  13651. if (this.expander.parentNode)
  13652. this.expander.parentNode.removeChild(this.expander);
  13653. }
  13654. if (this.box.parentNode)
  13655. {
  13656. ///setSelectionRange(this.input, 0, 0);
  13657. this.input.blur();
  13658. this.box.parentNode.removeChild(this.box);
  13659. }
  13660. delete this.target;
  13661. delete this.panel;
  13662. },
  13663. layout: function(forceAll)
  13664. {
  13665. if (!this.fixedWidth)
  13666. this.textSize = this.measureInputText(this.input.value);
  13667. if (forceAll)
  13668. this.targetOffset = getClientOffset(this.expander);
  13669. this.updateLayout(false, forceAll);
  13670. },
  13671. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13672. beginEditing: function(target, value)
  13673. {
  13674. },
  13675. saveEdit: function(target, value, previousValue)
  13676. {
  13677. },
  13678. endEditing: function(target, value, cancel)
  13679. {
  13680. // Remove empty groups by default
  13681. return true;
  13682. },
  13683. insertNewRow: function(target, insertWhere)
  13684. {
  13685. },
  13686. advanceToNext: function(target, charCode)
  13687. {
  13688. return false;
  13689. },
  13690. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13691. getAutoCompleteRange: function(value, offset)
  13692. {
  13693. },
  13694. getAutoCompleteList: function(preExpr, expr, postExpr)
  13695. {
  13696. },
  13697. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13698. getAutoCompleter: function()
  13699. {
  13700. if (!this.autoCompleter)
  13701. {
  13702. this.autoCompleter = new Firebug.AutoCompleter(null,
  13703. bind(this.getAutoCompleteRange, this), bind(this.getAutoCompleteList, this),
  13704. true, false);
  13705. }
  13706. return this.autoCompleter;
  13707. },
  13708. completeValue: function(amt)
  13709. {
  13710. //console.log("completeValue");
  13711. var selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, true, amt < 0);
  13712. if (selectRangeCallback)
  13713. {
  13714. Firebug.Editor.update(true);
  13715. // We need to select the editor text after calling update in Safari/Chrome,
  13716. // otherwise the text won't be selected
  13717. if (isSafari)
  13718. setTimeout(selectRangeCallback,0);
  13719. else
  13720. selectRangeCallback();
  13721. }
  13722. else
  13723. this.incrementValue(amt);
  13724. },
  13725. incrementValue: function(amt)
  13726. {
  13727. var value = this.input.value;
  13728. // TODO: xxxpedro editor
  13729. if (isIE)
  13730. var start = getInputSelectionStart(this.input), end = start;
  13731. else
  13732. var start = this.input.selectionStart, end = this.input.selectionEnd;
  13733. //debugger;
  13734. var range = this.getAutoCompleteRange(value, start);
  13735. if (!range || range.type != "int")
  13736. range = {start: 0, end: value.length-1};
  13737. var expr = value.substr(range.start, range.end-range.start+1);
  13738. preExpr = value.substr(0, range.start);
  13739. postExpr = value.substr(range.end+1);
  13740. // See if the value is an integer, and if so increment it
  13741. var intValue = parseInt(expr);
  13742. if (!!intValue || intValue == 0)
  13743. {
  13744. var m = /\d+/.exec(expr);
  13745. var digitPost = expr.substr(m.index+m[0].length);
  13746. var completion = intValue-amt;
  13747. this.input.value = preExpr + completion + digitPost + postExpr;
  13748. setSelectionRange(this.input, start, end);
  13749. Firebug.Editor.update(true);
  13750. return true;
  13751. }
  13752. else
  13753. return false;
  13754. },
  13755. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13756. onKeyPress: function(event)
  13757. {
  13758. //console.log("onKeyPress", event);
  13759. if (event.keyCode == 27 && !this.completeAsYouType)
  13760. {
  13761. var reverted = this.getAutoCompleter().revert(this.input);
  13762. if (reverted)
  13763. cancelEvent(event);
  13764. }
  13765. else if (event.charCode && this.advanceToNext(this.target, event.charCode))
  13766. {
  13767. Firebug.Editor.tabNextEditor();
  13768. cancelEvent(event);
  13769. }
  13770. else
  13771. {
  13772. if (this.numeric && event.charCode && (event.charCode < 48 || event.charCode > 57)
  13773. && event.charCode != 45 && event.charCode != 46)
  13774. FBL.cancelEvent(event);
  13775. else
  13776. {
  13777. // If the user backspaces, don't autocomplete after the upcoming input event
  13778. this.ignoreNextInput = event.keyCode == 8;
  13779. }
  13780. }
  13781. },
  13782. onOverflow: function()
  13783. {
  13784. this.updateLayout(false, false, 3);
  13785. },
  13786. onKeyDown: function(event)
  13787. {
  13788. //console.log("onKeyDown", event.keyCode);
  13789. if (event.keyCode > 46 || event.keyCode == 32 || event.keyCode == 8)
  13790. {
  13791. this.keyDownPressed = true;
  13792. }
  13793. },
  13794. onInput: function(event)
  13795. {
  13796. //debugger;
  13797. // skip not relevant onpropertychange calls on IE
  13798. if (isIE)
  13799. {
  13800. if (event.propertyName != "value" || !isVisible(this.input) || !this.keyDownPressed)
  13801. return;
  13802. this.keyDownPressed = false;
  13803. }
  13804. //console.log("onInput", event);
  13805. //console.trace();
  13806. var selectRangeCallback;
  13807. if (this.ignoreNextInput)
  13808. {
  13809. this.ignoreNextInput = false;
  13810. this.getAutoCompleter().reset();
  13811. }
  13812. else if (this.completeAsYouType)
  13813. selectRangeCallback = this.getAutoCompleter().complete(currentPanel.context, this.input, false);
  13814. else
  13815. this.getAutoCompleter().reset();
  13816. Firebug.Editor.update();
  13817. if (selectRangeCallback)
  13818. {
  13819. // We need to select the editor text after calling update in Safari/Chrome,
  13820. // otherwise the text won't be selected
  13821. if (isSafari)
  13822. setTimeout(selectRangeCallback,0);
  13823. else
  13824. selectRangeCallback();
  13825. }
  13826. },
  13827. onContextMenu: function(event)
  13828. {
  13829. cancelEvent(event);
  13830. var popup = $("fbInlineEditorPopup");
  13831. FBL.eraseNode(popup);
  13832. var target = event.target || event.srcElement;
  13833. var menu = this.getContextMenuItems(target);
  13834. if (menu)
  13835. {
  13836. for (var i = 0; i < menu.length; ++i)
  13837. FBL.createMenuItem(popup, menu[i]);
  13838. }
  13839. if (!popup.firstChild)
  13840. return false;
  13841. popup.openPopupAtScreen(event.screenX, event.screenY, true);
  13842. return true;
  13843. },
  13844. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  13845. updateLayout: function(initial, forceAll, extraWidth)
  13846. {
  13847. if (this.fixedWidth)
  13848. {
  13849. this.box.style.left = (this.targetOffset.x) + "px";
  13850. this.box.style.top = (this.targetOffset.y) + "px";
  13851. var w = this.target.offsetWidth;
  13852. var h = this.target.offsetHeight;
  13853. this.input.style.width = w + "px";
  13854. this.input.style.height = (h-3) + "px";
  13855. }
  13856. else
  13857. {
  13858. if (initial || forceAll)
  13859. {
  13860. this.box.style.left = this.targetOffset.x + "px";
  13861. this.box.style.top = this.targetOffset.y + "px";
  13862. }
  13863. var approxTextWidth = this.textSize.width;
  13864. var maxWidth = (currentPanel.panelNode.scrollWidth - this.targetOffset.x)
  13865. - this.outerMargin;
  13866. var wrapped = initial
  13867. ? this.noWrap && this.targetSize.height > this.textSize.height+3
  13868. : this.noWrap && approxTextWidth > maxWidth;
  13869. if (wrapped)
  13870. {
  13871. var style = isIE ?
  13872. this.target.currentStyle :
  13873. this.target.ownerDocument.defaultView.getComputedStyle(this.target, "");
  13874. targetMargin = parseInt(style.marginLeft) + parseInt(style.marginRight);
  13875. // Make the width fit the remaining x-space from the offset to the far right
  13876. approxTextWidth = maxWidth - targetMargin;
  13877. this.input.style.width = "100%";
  13878. this.box.style.width = approxTextWidth + "px";
  13879. }
  13880. else
  13881. {
  13882. // Make the input one character wider than the text value so that
  13883. // typing does not ever cause the textbox to scroll
  13884. var charWidth = this.measureInputText('m').width;
  13885. // Sometimes we need to make the editor a little wider, specifically when
  13886. // an overflow happens, otherwise it will scroll off some text on the left
  13887. if (extraWidth)
  13888. charWidth *= extraWidth;
  13889. var inputWidth = approxTextWidth + charWidth;
  13890. if (initial)
  13891. {
  13892. if (isIE)
  13893. {
  13894. // TODO: xxxpedro
  13895. var xDiff = 13;
  13896. this.box.style.width = (inputWidth + xDiff) + "px";
  13897. }
  13898. else
  13899. this.box.style.width = "auto";
  13900. }
  13901. else
  13902. {
  13903. // TODO: xxxpedro
  13904. var xDiff = isIE ? 13: this.box.scrollWidth - this.input.offsetWidth;
  13905. this.box.style.width = (inputWidth + xDiff) + "px";
  13906. }
  13907. this.input.style.width = inputWidth + "px";
  13908. }
  13909. this.expander.style.width = approxTextWidth + "px";
  13910. this.expander.style.height = Math.max(this.textSize.height-3,0) + "px";
  13911. }
  13912. if (forceAll)
  13913. scrollIntoCenterView(this.box, null, true);
  13914. }
  13915. });
  13916. // ************************************************************************************************
  13917. // Autocompletion
  13918. Firebug.AutoCompleter = function(getExprOffset, getRange, evaluator, selectMode, caseSensitive)
  13919. {
  13920. var candidates = null;
  13921. var originalValue = null;
  13922. var originalOffset = -1;
  13923. var lastExpr = null;
  13924. var lastOffset = -1;
  13925. var exprOffset = 0;
  13926. var lastIndex = 0;
  13927. var preParsed = null;
  13928. var preExpr = null;
  13929. var postExpr = null;
  13930. this.revert = function(textBox)
  13931. {
  13932. if (originalOffset != -1)
  13933. {
  13934. textBox.value = originalValue;
  13935. setSelectionRange(textBox, originalOffset, originalOffset);
  13936. this.reset();
  13937. return true;
  13938. }
  13939. else
  13940. {
  13941. this.reset();
  13942. return false;
  13943. }
  13944. };
  13945. this.reset = function()
  13946. {
  13947. candidates = null;
  13948. originalValue = null;
  13949. originalOffset = -1;
  13950. lastExpr = null;
  13951. lastOffset = 0;
  13952. exprOffset = 0;
  13953. };
  13954. this.complete = function(context, textBox, cycle, reverse)
  13955. {
  13956. //console.log("complete", context, textBox, cycle, reverse);
  13957. // TODO: xxxpedro important port to firebug (variable leak)
  13958. //var value = lastValue = textBox.value;
  13959. var value = textBox.value;
  13960. //var offset = textBox.selectionStart;
  13961. var offset = getInputSelectionStart(textBox);
  13962. // The result of selectionStart() in Safari/Chrome is 1 unit less than the result
  13963. // in Firefox. Therefore, we need to manually adjust the value here.
  13964. if (isSafari && !cycle && offset >= 0) offset++;
  13965. if (!selectMode && originalOffset != -1)
  13966. offset = originalOffset;
  13967. if (!candidates || !cycle || offset != lastOffset)
  13968. {
  13969. originalOffset = offset;
  13970. originalValue = value;
  13971. // Find the part of the string that will be parsed
  13972. var parseStart = getExprOffset ? getExprOffset(value, offset, context) : 0;
  13973. preParsed = value.substr(0, parseStart);
  13974. var parsed = value.substr(parseStart);
  13975. // Find the part of the string that is being completed
  13976. var range = getRange ? getRange(parsed, offset-parseStart, context) : null;
  13977. if (!range)
  13978. range = {start: 0, end: parsed.length-1 };
  13979. var expr = parsed.substr(range.start, range.end-range.start+1);
  13980. preExpr = parsed.substr(0, range.start);
  13981. postExpr = parsed.substr(range.end+1);
  13982. exprOffset = parseStart + range.start;
  13983. if (!cycle)
  13984. {
  13985. if (!expr)
  13986. return;
  13987. else if (lastExpr && lastExpr.indexOf(expr) != 0)
  13988. {
  13989. candidates = null;
  13990. }
  13991. else if (lastExpr && lastExpr.length >= expr.length)
  13992. {
  13993. candidates = null;
  13994. lastExpr = expr;
  13995. return;
  13996. }
  13997. }
  13998. lastExpr = expr;
  13999. lastOffset = offset;
  14000. var searchExpr;
  14001. // Check if the cursor is at the very right edge of the expression, or
  14002. // somewhere in the middle of it
  14003. if (expr && offset != parseStart+range.end+1)
  14004. {
  14005. if (cycle)
  14006. {
  14007. // We are in the middle of the expression, but we can
  14008. // complete by cycling to the next item in the values
  14009. // list after the expression
  14010. offset = range.start;
  14011. searchExpr = expr;
  14012. expr = "";
  14013. }
  14014. else
  14015. {
  14016. // We can't complete unless we are at the ridge edge
  14017. return;
  14018. }
  14019. }
  14020. var values = evaluator(preExpr, expr, postExpr, context);
  14021. if (!values)
  14022. return;
  14023. if (expr)
  14024. {
  14025. // Filter the list of values to those which begin with expr. We
  14026. // will then go on to complete the first value in the resulting list
  14027. candidates = [];
  14028. if (caseSensitive)
  14029. {
  14030. for (var i = 0; i < values.length; ++i)
  14031. {
  14032. var name = values[i];
  14033. if (name.indexOf && name.indexOf(expr) == 0)
  14034. candidates.push(name);
  14035. }
  14036. }
  14037. else
  14038. {
  14039. var lowerExpr = caseSensitive ? expr : expr.toLowerCase();
  14040. for (var i = 0; i < values.length; ++i)
  14041. {
  14042. var name = values[i];
  14043. if (name.indexOf && name.toLowerCase().indexOf(lowerExpr) == 0)
  14044. candidates.push(name);
  14045. }
  14046. }
  14047. lastIndex = reverse ? candidates.length-1 : 0;
  14048. }
  14049. else if (searchExpr)
  14050. {
  14051. var searchIndex = -1;
  14052. // Find the first instance of searchExpr in the values list. We
  14053. // will then complete the string that is found
  14054. if (caseSensitive)
  14055. {
  14056. searchIndex = values.indexOf(expr);
  14057. }
  14058. else
  14059. {
  14060. var lowerExpr = searchExpr.toLowerCase();
  14061. for (var i = 0; i < values.length; ++i)
  14062. {
  14063. var name = values[i];
  14064. if (name && name.toLowerCase().indexOf(lowerExpr) == 0)
  14065. {
  14066. searchIndex = i;
  14067. break;
  14068. }
  14069. }
  14070. }
  14071. // Nothing found, so there's nothing to complete to
  14072. if (searchIndex == -1)
  14073. return this.reset();
  14074. expr = searchExpr;
  14075. candidates = cloneArray(values);
  14076. lastIndex = searchIndex;
  14077. }
  14078. else
  14079. {
  14080. expr = "";
  14081. candidates = [];
  14082. for (var i = 0; i < values.length; ++i)
  14083. {
  14084. if (values[i].substr)
  14085. candidates.push(values[i]);
  14086. }
  14087. lastIndex = -1;
  14088. }
  14089. }
  14090. if (cycle)
  14091. {
  14092. expr = lastExpr;
  14093. lastIndex += reverse ? -1 : 1;
  14094. }
  14095. if (!candidates.length)
  14096. return;
  14097. if (lastIndex >= candidates.length)
  14098. lastIndex = 0;
  14099. else if (lastIndex < 0)
  14100. lastIndex = candidates.length-1;
  14101. var completion = candidates[lastIndex];
  14102. var preCompletion = expr.substr(0, offset-exprOffset);
  14103. var postCompletion = completion.substr(offset-exprOffset);
  14104. textBox.value = preParsed + preExpr + preCompletion + postCompletion + postExpr;
  14105. var offsetEnd = preParsed.length + preExpr.length + completion.length;
  14106. // TODO: xxxpedro remove the following commented code, if the lib.setSelectionRange()
  14107. // is working well.
  14108. /*
  14109. if (textBox.setSelectionRange)
  14110. {
  14111. // we must select the range with a timeout, otherwise the text won't
  14112. // be properly selected (because after this function executes, the editor's
  14113. // input will be resized to fit the whole text)
  14114. setTimeout(function(){
  14115. if (selectMode)
  14116. textBox.setSelectionRange(offset, offsetEnd);
  14117. else
  14118. textBox.setSelectionRange(offsetEnd, offsetEnd);
  14119. },0);
  14120. }
  14121. /**/
  14122. // we must select the range with a timeout, otherwise the text won't
  14123. // be properly selected (because after this function executes, the editor's
  14124. // input will be resized to fit the whole text)
  14125. /*
  14126. setTimeout(function(){
  14127. if (selectMode)
  14128. setSelectionRange(textBox, offset, offsetEnd);
  14129. else
  14130. setSelectionRange(textBox, offsetEnd, offsetEnd);
  14131. },0);
  14132. return true;
  14133. /**/
  14134. // The editor text should be selected only after calling the editor.update()
  14135. // in Safari/Chrome, otherwise the text won't be selected. So, we're returning
  14136. // a function to be called later (in the proper time for all browsers).
  14137. //
  14138. // TODO: xxxpedro see if we can move the editor.update() calls to here, and avoid
  14139. // returning a closure. the complete() function seems to be called only twice in
  14140. // editor.js. See if this function is called anywhere else (like css.js for example).
  14141. return function(){
  14142. //console.log("autocomplete ", textBox, offset, offsetEnd);
  14143. if (selectMode)
  14144. setSelectionRange(textBox, offset, offsetEnd);
  14145. else
  14146. setSelectionRange(textBox, offsetEnd, offsetEnd);
  14147. };
  14148. /**/
  14149. };
  14150. };
  14151. // ************************************************************************************************
  14152. // Local Helpers
  14153. var getDefaultEditor = function getDefaultEditor(panel)
  14154. {
  14155. if (!defaultEditor)
  14156. {
  14157. var doc = panel.document;
  14158. defaultEditor = new Firebug.InlineEditor(doc);
  14159. }
  14160. return defaultEditor;
  14161. }
  14162. /**
  14163. * An outsider is the first element matching the stepper element that
  14164. * is not an child of group. Elements tagged with insertBefore or insertAfter
  14165. * classes are also excluded from these results unless they are the sibling
  14166. * of group, relative to group's parent editGroup. This allows for the proper insertion
  14167. * rows when groups are nested.
  14168. */
  14169. var getOutsider = function getOutsider(element, group, stepper)
  14170. {
  14171. var parentGroup = getAncestorByClass(group.parentNode, "editGroup");
  14172. var next;
  14173. do
  14174. {
  14175. next = stepper(next || element);
  14176. }
  14177. while (isAncestor(next, group) || isGroupInsert(next, parentGroup));
  14178. return next;
  14179. }
  14180. var isGroupInsert = function isGroupInsert(next, group)
  14181. {
  14182. return (!group || isAncestor(next, group))
  14183. && (hasClass(next, "insertBefore") || hasClass(next, "insertAfter"));
  14184. }
  14185. var getNextOutsider = function getNextOutsider(element, group)
  14186. {
  14187. return getOutsider(element, group, bind(getNextByClass, FBL, "editable"));
  14188. }
  14189. var getPreviousOutsider = function getPreviousOutsider(element, group)
  14190. {
  14191. return getOutsider(element, group, bind(getPreviousByClass, FBL, "editable"));
  14192. }
  14193. var getInlineParent = function getInlineParent(element)
  14194. {
  14195. var lastInline = element;
  14196. for (; element; element = element.parentNode)
  14197. {
  14198. //var s = element.ownerDocument.defaultView.getComputedStyle(element, "");
  14199. var s = isIE ?
  14200. element.currentStyle :
  14201. element.ownerDocument.defaultView.getComputedStyle(element, "");
  14202. if (s.display != "inline")
  14203. return lastInline;
  14204. else
  14205. lastInline = element;
  14206. }
  14207. return null;
  14208. }
  14209. var insertTab = function insertTab()
  14210. {
  14211. insertTextIntoElement(currentEditor.input, Firebug.Editor.tabCharacter);
  14212. }
  14213. // ************************************************************************************************
  14214. Firebug.registerModule(Firebug.Editor);
  14215. // ************************************************************************************************
  14216. }});
  14217. /* See license.txt for terms of usage */
  14218. FBL.ns(function() { with (FBL) {
  14219. // ************************************************************************************************
  14220. // ************************************************************************************************
  14221. // Inspector Module
  14222. var ElementCache = Firebug.Lite.Cache.Element;
  14223. var inspectorTS, inspectorTimer, isInspecting;
  14224. Firebug.Inspector =
  14225. {
  14226. create: function()
  14227. {
  14228. offlineFragment = Env.browser.document.createDocumentFragment();
  14229. createBoxModelInspector();
  14230. createOutlineInspector();
  14231. },
  14232. destroy: function()
  14233. {
  14234. destroyBoxModelInspector();
  14235. destroyOutlineInspector();
  14236. offlineFragment = null;
  14237. },
  14238. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14239. // Inspect functions
  14240. toggleInspect: function()
  14241. {
  14242. if (isInspecting)
  14243. {
  14244. this.stopInspecting();
  14245. }
  14246. else
  14247. {
  14248. Firebug.chrome.inspectButton.changeState("pressed");
  14249. this.startInspecting();
  14250. }
  14251. },
  14252. startInspecting: function()
  14253. {
  14254. isInspecting = true;
  14255. Firebug.chrome.selectPanel("HTML");
  14256. createInspectorFrame();
  14257. var size = Firebug.browser.getWindowScrollSize();
  14258. fbInspectFrame.style.width = size.width + "px";
  14259. fbInspectFrame.style.height = size.height + "px";
  14260. //addEvent(Firebug.browser.document.documentElement, "mousemove", Firebug.Inspector.onInspectingBody);
  14261. addEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting);
  14262. addEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick);
  14263. },
  14264. stopInspecting: function()
  14265. {
  14266. isInspecting = false;
  14267. if (outlineVisible) this.hideOutline();
  14268. removeEvent(fbInspectFrame, "mousemove", Firebug.Inspector.onInspecting);
  14269. removeEvent(fbInspectFrame, "mousedown", Firebug.Inspector.onInspectingClick);
  14270. destroyInspectorFrame();
  14271. Firebug.chrome.inspectButton.restore();
  14272. if (Firebug.chrome.type == "popup")
  14273. Firebug.chrome.node.focus();
  14274. },
  14275. onInspectingClick: function(e)
  14276. {
  14277. fbInspectFrame.style.display = "none";
  14278. var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY);
  14279. fbInspectFrame.style.display = "block";
  14280. // Avoid inspecting the outline, and the FirebugUI
  14281. var id = targ.id;
  14282. if (id && /^fbOutline\w$/.test(id)) return;
  14283. if (id == "FirebugUI") return;
  14284. // Avoid looking at text nodes in Opera
  14285. while (targ.nodeType != 1) targ = targ.parentNode;
  14286. //Firebug.Console.log(targ);
  14287. Firebug.Inspector.stopInspecting();
  14288. },
  14289. onInspecting: function(e)
  14290. {
  14291. if (new Date().getTime() - lastInspecting > 30)
  14292. {
  14293. fbInspectFrame.style.display = "none";
  14294. var targ = Firebug.browser.getElementFromPoint(e.clientX, e.clientY);
  14295. fbInspectFrame.style.display = "block";
  14296. // Avoid inspecting the outline, and the FirebugUI
  14297. var id = targ.id;
  14298. if (id && /^fbOutline\w$/.test(id)) return;
  14299. if (id == "FirebugUI") return;
  14300. // Avoid looking at text nodes in Opera
  14301. while (targ.nodeType != 1) targ = targ.parentNode;
  14302. if (targ.nodeName.toLowerCase() == "body") return;
  14303. //Firebug.Console.log(e.clientX, e.clientY, targ);
  14304. Firebug.Inspector.drawOutline(targ);
  14305. if (ElementCache(targ))
  14306. {
  14307. var target = ""+ElementCache.key(targ);
  14308. var lazySelect = function()
  14309. {
  14310. inspectorTS = new Date().getTime();
  14311. Firebug.HTML.selectTreeNode(""+ElementCache.key(targ))
  14312. };
  14313. if (inspectorTimer)
  14314. {
  14315. clearTimeout(inspectorTimer);
  14316. inspectorTimer = null;
  14317. }
  14318. if (new Date().getTime() - inspectorTS > 200)
  14319. setTimeout(lazySelect, 0)
  14320. else
  14321. inspectorTimer = setTimeout(lazySelect, 300);
  14322. }
  14323. lastInspecting = new Date().getTime();
  14324. }
  14325. },
  14326. // TODO: xxxpedro remove this?
  14327. onInspectingBody: function(e)
  14328. {
  14329. if (new Date().getTime() - lastInspecting > 30)
  14330. {
  14331. var targ = e.target;
  14332. // Avoid inspecting the outline, and the FirebugUI
  14333. var id = targ.id;
  14334. if (id && /^fbOutline\w$/.test(id)) return;
  14335. if (id == "FirebugUI") return;
  14336. // Avoid looking at text nodes in Opera
  14337. while (targ.nodeType != 1) targ = targ.parentNode;
  14338. if (targ.nodeName.toLowerCase() == "body") return;
  14339. //Firebug.Console.log(e.clientX, e.clientY, targ);
  14340. Firebug.Inspector.drawOutline(targ);
  14341. if (ElementCache.has(targ))
  14342. FBL.Firebug.HTML.selectTreeNode(""+ElementCache.key(targ));
  14343. lastInspecting = new Date().getTime();
  14344. }
  14345. },
  14346. /**
  14347. *
  14348. * llttttttrr
  14349. * llttttttrr
  14350. * ll rr
  14351. * ll rr
  14352. * llbbbbbbrr
  14353. * llbbbbbbrr
  14354. */
  14355. drawOutline: function(el)
  14356. {
  14357. var border = 2;
  14358. var scrollbarSize = 17;
  14359. var windowSize = Firebug.browser.getWindowSize();
  14360. var scrollSize = Firebug.browser.getWindowScrollSize();
  14361. var scrollPosition = Firebug.browser.getWindowScrollPosition();
  14362. var box = Firebug.browser.getElementBox(el);
  14363. var top = box.top;
  14364. var left = box.left;
  14365. var height = box.height;
  14366. var width = box.width;
  14367. var freeHorizontalSpace = scrollPosition.left + windowSize.width - left - width -
  14368. (!isIE && scrollSize.height > windowSize.height ? // is *vertical* scrollbar visible
  14369. scrollbarSize : 0);
  14370. var freeVerticalSpace = scrollPosition.top + windowSize.height - top - height -
  14371. (!isIE && scrollSize.width > windowSize.width ? // is *horizontal* scrollbar visible
  14372. scrollbarSize : 0);
  14373. var numVerticalBorders = freeVerticalSpace > 0 ? 2 : 1;
  14374. var o = outlineElements;
  14375. var style;
  14376. style = o.fbOutlineT.style;
  14377. style.top = top-border + "px";
  14378. style.left = left + "px";
  14379. style.height = border + "px"; // TODO: on initialize()
  14380. style.width = width + "px";
  14381. style = o.fbOutlineL.style;
  14382. style.top = top-border + "px";
  14383. style.left = left-border + "px";
  14384. style.height = height+ numVerticalBorders*border + "px";
  14385. style.width = border + "px"; // TODO: on initialize()
  14386. style = o.fbOutlineB.style;
  14387. if (freeVerticalSpace > 0)
  14388. {
  14389. style.top = top+height + "px";
  14390. style.left = left + "px";
  14391. style.width = width + "px";
  14392. //style.height = border + "px"; // TODO: on initialize() or worst case?
  14393. }
  14394. else
  14395. {
  14396. style.top = -2*border + "px";
  14397. style.left = -2*border + "px";
  14398. style.width = border + "px";
  14399. //style.height = border + "px";
  14400. }
  14401. style = o.fbOutlineR.style;
  14402. if (freeHorizontalSpace > 0)
  14403. {
  14404. style.top = top-border + "px";
  14405. style.left = left+width + "px";
  14406. style.height = height + numVerticalBorders*border + "px";
  14407. style.width = (freeHorizontalSpace < border ? freeHorizontalSpace : border) + "px";
  14408. }
  14409. else
  14410. {
  14411. style.top = -2*border + "px";
  14412. style.left = -2*border + "px";
  14413. style.height = border + "px";
  14414. style.width = border + "px";
  14415. }
  14416. if (!outlineVisible) this.showOutline();
  14417. },
  14418. hideOutline: function()
  14419. {
  14420. if (!outlineVisible) return;
  14421. for (var name in outline)
  14422. offlineFragment.appendChild(outlineElements[name]);
  14423. outlineVisible = false;
  14424. },
  14425. showOutline: function()
  14426. {
  14427. if (outlineVisible) return;
  14428. if (boxModelVisible) this.hideBoxModel();
  14429. for (var name in outline)
  14430. Firebug.browser.document.getElementsByTagName("body")[0].appendChild(outlineElements[name]);
  14431. outlineVisible = true;
  14432. },
  14433. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14434. // Box Model
  14435. drawBoxModel: function(el)
  14436. {
  14437. // avoid error when the element is not attached a document
  14438. if (!el || !el.parentNode)
  14439. return;
  14440. var box = Firebug.browser.getElementBox(el);
  14441. var windowSize = Firebug.browser.getWindowSize();
  14442. var scrollPosition = Firebug.browser.getWindowScrollPosition();
  14443. // element may be occluded by the chrome, when in frame mode
  14444. var offsetHeight = Firebug.chrome.type == "frame" ? FirebugChrome.height : 0;
  14445. // if element box is not inside the viewport, don't draw the box model
  14446. if (box.top > scrollPosition.top + windowSize.height - offsetHeight ||
  14447. box.left > scrollPosition.left + windowSize.width ||
  14448. scrollPosition.top > box.top + box.height ||
  14449. scrollPosition.left > box.left + box.width )
  14450. return;
  14451. var top = box.top;
  14452. var left = box.left;
  14453. var height = box.height;
  14454. var width = box.width;
  14455. var margin = Firebug.browser.getMeasurementBox(el, "margin");
  14456. var padding = Firebug.browser.getMeasurementBox(el, "padding");
  14457. var border = Firebug.browser.getMeasurementBox(el, "border");
  14458. boxModelStyle.top = top - margin.top + "px";
  14459. boxModelStyle.left = left - margin.left + "px";
  14460. boxModelStyle.height = height + margin.top + margin.bottom + "px";
  14461. boxModelStyle.width = width + margin.left + margin.right + "px";
  14462. boxBorderStyle.top = margin.top + "px";
  14463. boxBorderStyle.left = margin.left + "px";
  14464. boxBorderStyle.height = height + "px";
  14465. boxBorderStyle.width = width + "px";
  14466. boxPaddingStyle.top = margin.top + border.top + "px";
  14467. boxPaddingStyle.left = margin.left + border.left + "px";
  14468. boxPaddingStyle.height = height - border.top - border.bottom + "px";
  14469. boxPaddingStyle.width = width - border.left - border.right + "px";
  14470. boxContentStyle.top = margin.top + border.top + padding.top + "px";
  14471. boxContentStyle.left = margin.left + border.left + padding.left + "px";
  14472. boxContentStyle.height = height - border.top - padding.top - padding.bottom - border.bottom + "px";
  14473. boxContentStyle.width = width - border.left - padding.left - padding.right - border.right + "px";
  14474. if (!boxModelVisible) this.showBoxModel();
  14475. },
  14476. hideBoxModel: function()
  14477. {
  14478. if (!boxModelVisible) return;
  14479. offlineFragment.appendChild(boxModel);
  14480. boxModelVisible = false;
  14481. },
  14482. showBoxModel: function()
  14483. {
  14484. if (boxModelVisible) return;
  14485. if (outlineVisible) this.hideOutline();
  14486. Firebug.browser.document.getElementsByTagName("body")[0].appendChild(boxModel);
  14487. boxModelVisible = true;
  14488. }
  14489. };
  14490. // ************************************************************************************************
  14491. // Inspector Internals
  14492. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14493. // Shared variables
  14494. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14495. // Internal variables
  14496. var offlineFragment = null;
  14497. var boxModelVisible = false;
  14498. var boxModel, boxModelStyle,
  14499. boxMargin, boxMarginStyle,
  14500. boxBorder, boxBorderStyle,
  14501. boxPadding, boxPaddingStyle,
  14502. boxContent, boxContentStyle;
  14503. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14504. var resetStyle = "margin:0; padding:0; border:0; position:absolute; overflow:hidden; display:block;";
  14505. var offscreenStyle = resetStyle + "top:-1234px; left:-1234px;";
  14506. var inspectStyle = resetStyle + "z-index: 2147483500;";
  14507. var inspectFrameStyle = resetStyle + "z-index: 2147483550; top:0; left:0; background:url(" +
  14508. Env.Location.skinDir + "pixel_transparent.gif);";
  14509. //if (Env.Options.enableTrace) inspectFrameStyle = resetStyle + "z-index: 2147483550; top: 0; left: 0; background: #ff0; opacity: 0.05; _filter: alpha(opacity=5);";
  14510. var inspectModelOpacity = isIE ? "filter:alpha(opacity=80);" : "opacity:0.8;";
  14511. var inspectModelStyle = inspectStyle + inspectModelOpacity;
  14512. var inspectMarginStyle = inspectStyle + "background: #EDFF64; height:100%; width:100%;";
  14513. var inspectBorderStyle = inspectStyle + "background: #666;";
  14514. var inspectPaddingStyle = inspectStyle + "background: SlateBlue;";
  14515. var inspectContentStyle = inspectStyle + "background: SkyBlue;";
  14516. var outlineStyle = {
  14517. fbHorizontalLine: "background: #3875D7;height: 2px;",
  14518. fbVerticalLine: "background: #3875D7;width: 2px;"
  14519. }
  14520. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14521. var lastInspecting = 0;
  14522. var fbInspectFrame = null;
  14523. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14524. var outlineVisible = false;
  14525. var outlineElements = {};
  14526. var outline = {
  14527. "fbOutlineT": "fbHorizontalLine",
  14528. "fbOutlineL": "fbVerticalLine",
  14529. "fbOutlineB": "fbHorizontalLine",
  14530. "fbOutlineR": "fbVerticalLine"
  14531. };
  14532. var getInspectingTarget = function()
  14533. {
  14534. };
  14535. // ************************************************************************************************
  14536. // Section
  14537. var createInspectorFrame = function createInspectorFrame()
  14538. {
  14539. fbInspectFrame = createGlobalElement("div");
  14540. fbInspectFrame.id = "fbInspectFrame";
  14541. fbInspectFrame.firebugIgnore = true;
  14542. fbInspectFrame.style.cssText = inspectFrameStyle;
  14543. Firebug.browser.document.getElementsByTagName("body")[0].appendChild(fbInspectFrame);
  14544. };
  14545. var destroyInspectorFrame = function destroyInspectorFrame()
  14546. {
  14547. if (fbInspectFrame)
  14548. {
  14549. Firebug.browser.document.getElementsByTagName("body")[0].removeChild(fbInspectFrame);
  14550. fbInspectFrame = null;
  14551. }
  14552. };
  14553. var createOutlineInspector = function createOutlineInspector()
  14554. {
  14555. for (var name in outline)
  14556. {
  14557. var el = outlineElements[name] = createGlobalElement("div");
  14558. el.id = name;
  14559. el.firebugIgnore = true;
  14560. el.style.cssText = inspectStyle + outlineStyle[outline[name]];
  14561. offlineFragment.appendChild(el);
  14562. }
  14563. };
  14564. var destroyOutlineInspector = function destroyOutlineInspector()
  14565. {
  14566. for (var name in outline)
  14567. {
  14568. var el = outlineElements[name];
  14569. el.parentNode.removeChild(el);
  14570. }
  14571. };
  14572. var createBoxModelInspector = function createBoxModelInspector()
  14573. {
  14574. boxModel = createGlobalElement("div");
  14575. boxModel.id = "fbBoxModel";
  14576. boxModel.firebugIgnore = true;
  14577. boxModelStyle = boxModel.style;
  14578. boxModelStyle.cssText = inspectModelStyle;
  14579. boxMargin = createGlobalElement("div");
  14580. boxMargin.id = "fbBoxMargin";
  14581. boxMarginStyle = boxMargin.style;
  14582. boxMarginStyle.cssText = inspectMarginStyle;
  14583. boxModel.appendChild(boxMargin);
  14584. boxBorder = createGlobalElement("div");
  14585. boxBorder.id = "fbBoxBorder";
  14586. boxBorderStyle = boxBorder.style;
  14587. boxBorderStyle.cssText = inspectBorderStyle;
  14588. boxModel.appendChild(boxBorder);
  14589. boxPadding = createGlobalElement("div");
  14590. boxPadding.id = "fbBoxPadding";
  14591. boxPaddingStyle = boxPadding.style;
  14592. boxPaddingStyle.cssText = inspectPaddingStyle;
  14593. boxModel.appendChild(boxPadding);
  14594. boxContent = createGlobalElement("div");
  14595. boxContent.id = "fbBoxContent";
  14596. boxContentStyle = boxContent.style;
  14597. boxContentStyle.cssText = inspectContentStyle;
  14598. boxModel.appendChild(boxContent);
  14599. offlineFragment.appendChild(boxModel);
  14600. };
  14601. var destroyBoxModelInspector = function destroyBoxModelInspector()
  14602. {
  14603. boxModel.parentNode.removeChild(boxModel);
  14604. };
  14605. // ************************************************************************************************
  14606. // Section
  14607. // ************************************************************************************************
  14608. }});
  14609. /* See license.txt for terms of usage */
  14610. // next-generation Console Panel (will override consoje.js)
  14611. FBL.ns(function() { with (FBL) {
  14612. // ************************************************************************************************
  14613. // ************************************************************************************************
  14614. // Constants
  14615. /*
  14616. const Cc = Components.classes;
  14617. const Ci = Components.interfaces;
  14618. const nsIPrefBranch2 = Ci.nsIPrefBranch2;
  14619. const PrefService = Cc["@mozilla.org/preferences-service;1"];
  14620. const prefs = PrefService.getService(nsIPrefBranch2);
  14621. /**/
  14622. /*
  14623. // new offline message handler
  14624. o = {x:1,y:2};
  14625. r = Firebug.getRep(o);
  14626. r.tag.tag.compile();
  14627. outputs = [];
  14628. html = r.tag.renderHTML({object:o}, outputs);
  14629. // finish rendering the template (the DOM part)
  14630. target = $("build");
  14631. target.innerHTML = html;
  14632. root = target.firstChild;
  14633. domArgs = [root, r.tag.context, 0];
  14634. domArgs.push.apply(domArgs, r.tag.domArgs);
  14635. domArgs.push.apply(domArgs, outputs);
  14636. r.tag.tag.renderDOM.apply(self ? self : r.tag.subject, domArgs);
  14637. */
  14638. var consoleQueue = [];
  14639. var lastHighlightedObject;
  14640. var FirebugContext = Env.browser;
  14641. // ************************************************************************************************
  14642. var maxQueueRequests = 500;
  14643. // ************************************************************************************************
  14644. Firebug.ConsoleBase =
  14645. {
  14646. log: function(object, context, className, rep, noThrottle, sourceLink)
  14647. {
  14648. //dispatch(this.fbListeners,"log",[context, object, className, sourceLink]);
  14649. return this.logRow(appendObject, object, context, className, rep, sourceLink, noThrottle);
  14650. },
  14651. logFormatted: function(objects, context, className, noThrottle, sourceLink)
  14652. {
  14653. //dispatch(this.fbListeners,"logFormatted",[context, objects, className, sourceLink]);
  14654. return this.logRow(appendFormatted, objects, context, className, null, sourceLink, noThrottle);
  14655. },
  14656. openGroup: function(objects, context, className, rep, noThrottle, sourceLink, noPush)
  14657. {
  14658. return this.logRow(appendOpenGroup, objects, context, className, rep, sourceLink, noThrottle);
  14659. },
  14660. closeGroup: function(context, noThrottle)
  14661. {
  14662. return this.logRow(appendCloseGroup, null, context, null, null, null, noThrottle, true);
  14663. },
  14664. logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
  14665. {
  14666. // TODO: xxxpedro console console2
  14667. noThrottle = true; // xxxpedro forced because there is no TabContext yet
  14668. if (!context)
  14669. context = FirebugContext;
  14670. if (FBTrace.DBG_ERRORS && !context)
  14671. FBTrace.sysout("Console.logRow has no context, skipping objects", objects);
  14672. if (!context)
  14673. return;
  14674. if (noThrottle || !context)
  14675. {
  14676. var panel = this.getPanel(context);
  14677. if (panel)
  14678. {
  14679. var row = panel.append(appender, objects, className, rep, sourceLink, noRow);
  14680. var container = panel.panelNode;
  14681. // TODO: xxxpedro what is this? console console2
  14682. /*
  14683. var template = Firebug.NetMonitor.NetLimit;
  14684. while (container.childNodes.length > maxQueueRequests + 1)
  14685. {
  14686. clearDomplate(container.firstChild.nextSibling);
  14687. container.removeChild(container.firstChild.nextSibling);
  14688. panel.limit.limitInfo.totalCount++;
  14689. template.updateCounter(panel.limit);
  14690. }
  14691. dispatch([Firebug.A11yModel], "onLogRowCreated", [panel , row]);
  14692. /**/
  14693. return row;
  14694. }
  14695. else
  14696. {
  14697. consoleQueue.push([appender, objects, context, className, rep, sourceLink, noThrottle, noRow]);
  14698. }
  14699. }
  14700. else
  14701. {
  14702. if (!context.throttle)
  14703. {
  14704. //FBTrace.sysout("console.logRow has not context.throttle! ");
  14705. return;
  14706. }
  14707. var args = [appender, objects, context, className, rep, sourceLink, true, noRow];
  14708. context.throttle(this.logRow, this, args);
  14709. }
  14710. },
  14711. appendFormatted: function(args, row, context)
  14712. {
  14713. if (!context)
  14714. context = FirebugContext;
  14715. var panel = this.getPanel(context);
  14716. panel.appendFormatted(args, row);
  14717. },
  14718. clear: function(context)
  14719. {
  14720. if (!context)
  14721. //context = FirebugContext;
  14722. context = Firebug.context;
  14723. /*
  14724. if (context)
  14725. Firebug.Errors.clear(context);
  14726. /**/
  14727. var panel = this.getPanel(context, true);
  14728. if (panel)
  14729. {
  14730. panel.clear();
  14731. }
  14732. },
  14733. // Override to direct output to your panel
  14734. getPanel: function(context, noCreate)
  14735. {
  14736. //return context.getPanel("console", noCreate);
  14737. // TODO: xxxpedro console console2
  14738. return Firebug.chrome ? Firebug.chrome.getPanel("Console") : null;
  14739. }
  14740. };
  14741. // ************************************************************************************************
  14742. //TODO: xxxpedro
  14743. //var ActivableConsole = extend(Firebug.ActivableModule, Firebug.ConsoleBase);
  14744. var ActivableConsole = extend(Firebug.ConsoleBase,
  14745. {
  14746. isAlwaysEnabled: function()
  14747. {
  14748. return true;
  14749. }
  14750. });
  14751. Firebug.Console = Firebug.Console = extend(ActivableConsole,
  14752. //Firebug.Console = extend(ActivableConsole,
  14753. {
  14754. dispatchName: "console",
  14755. error: function()
  14756. {
  14757. Firebug.Console.logFormatted(arguments, Firebug.browser, "error");
  14758. },
  14759. flush: function()
  14760. {
  14761. dispatch(this.fbListeners,"flush",[]);
  14762. for (var i=0, length=consoleQueue.length; i<length; i++)
  14763. {
  14764. var args = consoleQueue[i];
  14765. this.logRow.apply(this, args);
  14766. }
  14767. },
  14768. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14769. // extends Module
  14770. showPanel: function(browser, panel)
  14771. {
  14772. },
  14773. getFirebugConsoleElement: function(context, win)
  14774. {
  14775. var element = win.document.getElementById("_firebugConsole");
  14776. if (!element)
  14777. {
  14778. if (FBTrace.DBG_CONSOLE)
  14779. FBTrace.sysout("getFirebugConsoleElement forcing element");
  14780. var elementForcer = "(function(){var r=null; try { r = window._getFirebugConsoleElement();}catch(exc){r=exc;} return r;})();"; // we could just add the elements here
  14781. if (context.stopped)
  14782. Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack
  14783. else
  14784. var r = Firebug.CommandLine.evaluateInWebPage(elementForcer, context, win);
  14785. if (FBTrace.DBG_CONSOLE)
  14786. FBTrace.sysout("getFirebugConsoleElement forcing element result "+r, r);
  14787. var element = win.document.getElementById("_firebugConsole");
  14788. if (!element) // elementForce fails
  14789. {
  14790. if (FBTrace.DBG_ERRORS) FBTrace.sysout("console.getFirebugConsoleElement: no _firebugConsole in win:", win);
  14791. Firebug.Console.logFormatted(["Firebug cannot find _firebugConsole element", r, win], context, "error", true);
  14792. }
  14793. }
  14794. return element;
  14795. },
  14796. isReadyElsePreparing: function(context, win) // this is the only code that should call injector.attachIfNeeded
  14797. {
  14798. if (FBTrace.DBG_CONSOLE)
  14799. FBTrace.sysout("console.isReadyElsePreparing, win is " +
  14800. (win?"an argument: ":"null, context.window: ") +
  14801. (win?win.location:context.window.location), (win?win:context.window));
  14802. if (win)
  14803. return this.injector.attachIfNeeded(context, win);
  14804. else
  14805. {
  14806. var attached = true;
  14807. for (var i = 0; i < context.windows.length; i++)
  14808. attached = attached && this.injector.attachIfNeeded(context, context.windows[i]);
  14809. // already in the list above attached = attached && this.injector.attachIfNeeded(context, context.window);
  14810. if (context.windows.indexOf(context.window) == -1)
  14811. FBTrace.sysout("isReadyElsePreparing ***************** context.window not in context.windows");
  14812. if (FBTrace.DBG_CONSOLE)
  14813. FBTrace.sysout("console.isReadyElsePreparing attached to "+context.windows.length+" and returns "+attached);
  14814. return attached;
  14815. }
  14816. },
  14817. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14818. // extends ActivableModule
  14819. initialize: function()
  14820. {
  14821. this.panelName = "console";
  14822. //TODO: xxxpedro
  14823. //Firebug.ActivableModule.initialize.apply(this, arguments);
  14824. //Firebug.Debugger.addListener(this);
  14825. },
  14826. enable: function()
  14827. {
  14828. if (Firebug.Console.isAlwaysEnabled())
  14829. this.watchForErrors();
  14830. },
  14831. disable: function()
  14832. {
  14833. if (Firebug.Console.isAlwaysEnabled())
  14834. this.unwatchForErrors();
  14835. },
  14836. initContext: function(context, persistedState)
  14837. {
  14838. Firebug.ActivableModule.initContext.apply(this, arguments);
  14839. context.consoleReloadWarning = true; // mark as need to warn.
  14840. },
  14841. loadedContext: function(context)
  14842. {
  14843. for (var url in context.sourceFileMap)
  14844. return; // if there are any sourceFiles, then do nothing
  14845. // else we saw no JS, so the reload warning it not needed.
  14846. this.clearReloadWarning(context);
  14847. },
  14848. clearReloadWarning: function(context) // remove the warning about reloading.
  14849. {
  14850. if (context.consoleReloadWarning)
  14851. {
  14852. var panel = context.getPanel(this.panelName);
  14853. panel.clearReloadWarning();
  14854. delete context.consoleReloadWarning;
  14855. }
  14856. },
  14857. togglePersist: function(context)
  14858. {
  14859. var panel = context.getPanel(this.panelName);
  14860. panel.persistContent = panel.persistContent ? false : true;
  14861. Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", panel.persistContent);
  14862. },
  14863. showContext: function(browser, context)
  14864. {
  14865. Firebug.chrome.setGlobalAttribute("cmd_clearConsole", "disabled", !context);
  14866. Firebug.ActivableModule.showContext.apply(this, arguments);
  14867. },
  14868. destroyContext: function(context, persistedState)
  14869. {
  14870. Firebug.Console.injector.detachConsole(context, context.window); // TODO iterate windows?
  14871. },
  14872. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14873. onPanelEnable: function(panelName)
  14874. {
  14875. if (panelName != this.panelName) // we don't care about other panels
  14876. return;
  14877. if (FBTrace.DBG_CONSOLE)
  14878. FBTrace.sysout("console.onPanelEnable**************");
  14879. this.watchForErrors();
  14880. Firebug.Debugger.addDependentModule(this); // we inject the console during JS compiles so we need jsd
  14881. },
  14882. onPanelDisable: function(panelName)
  14883. {
  14884. if (panelName != this.panelName) // we don't care about other panels
  14885. return;
  14886. if (FBTrace.DBG_CONSOLE)
  14887. FBTrace.sysout("console.onPanelDisable**************");
  14888. Firebug.Debugger.removeDependentModule(this); // we inject the console during JS compiles so we need jsd
  14889. this.unwatchForErrors();
  14890. // Make sure possible errors coming from the page and displayed in the Firefox
  14891. // status bar are removed.
  14892. this.clear();
  14893. },
  14894. onSuspendFirebug: function()
  14895. {
  14896. if (FBTrace.DBG_CONSOLE)
  14897. FBTrace.sysout("console.onSuspendFirebug\n");
  14898. if (Firebug.Console.isAlwaysEnabled())
  14899. this.unwatchForErrors();
  14900. },
  14901. onResumeFirebug: function()
  14902. {
  14903. if (FBTrace.DBG_CONSOLE)
  14904. FBTrace.sysout("console.onResumeFirebug\n");
  14905. if (Firebug.Console.isAlwaysEnabled())
  14906. this.watchForErrors();
  14907. },
  14908. watchForErrors: function()
  14909. {
  14910. Firebug.Errors.checkEnabled();
  14911. $('fbStatusIcon').setAttribute("console", "on");
  14912. },
  14913. unwatchForErrors: function()
  14914. {
  14915. Firebug.Errors.checkEnabled();
  14916. $('fbStatusIcon').removeAttribute("console");
  14917. },
  14918. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14919. // Firebug.Debugger listener
  14920. onMonitorScript: function(context, frame)
  14921. {
  14922. Firebug.Console.log(frame, context);
  14923. },
  14924. onFunctionCall: function(context, frame, depth, calling)
  14925. {
  14926. if (calling)
  14927. Firebug.Console.openGroup([frame, "depth:"+depth], context);
  14928. else
  14929. Firebug.Console.closeGroup(context);
  14930. },
  14931. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  14932. logRow: function(appender, objects, context, className, rep, sourceLink, noThrottle, noRow)
  14933. {
  14934. if (!context)
  14935. context = FirebugContext;
  14936. if (FBTrace.DBG_WINDOWS && !context) FBTrace.sysout("Console.logRow: no context \n");
  14937. if (this.isAlwaysEnabled())
  14938. return Firebug.ConsoleBase.logRow.apply(this, arguments);
  14939. }
  14940. });
  14941. Firebug.ConsoleListener =
  14942. {
  14943. log: function(context, object, className, sourceLink)
  14944. {
  14945. },
  14946. logFormatted: function(context, objects, className, sourceLink)
  14947. {
  14948. }
  14949. };
  14950. // ************************************************************************************************
  14951. Firebug.ConsolePanel = function () {} // XXjjb attach Firebug so this panel can be extended.
  14952. //TODO: xxxpedro
  14953. //Firebug.ConsolePanel.prototype = extend(Firebug.ActivablePanel,
  14954. Firebug.ConsolePanel.prototype = extend(Firebug.Panel,
  14955. {
  14956. wasScrolledToBottom: false,
  14957. messageCount: 0,
  14958. lastLogTime: 0,
  14959. groups: null,
  14960. limit: null,
  14961. append: function(appender, objects, className, rep, sourceLink, noRow)
  14962. {
  14963. var container = this.getTopContainer();
  14964. if (noRow)
  14965. {
  14966. appender.apply(this, [objects]);
  14967. }
  14968. else
  14969. {
  14970. // xxxHonza: Don't update the this.wasScrolledToBottom flag now.
  14971. // At the beginning (when the first log is created) the isScrolledToBottom
  14972. // always returns true.
  14973. //if (this.panelNode.offsetHeight)
  14974. // this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
  14975. var row = this.createRow("logRow", className);
  14976. appender.apply(this, [objects, row, rep]);
  14977. if (sourceLink)
  14978. FirebugReps.SourceLink.tag.append({object: sourceLink}, row);
  14979. container.appendChild(row);
  14980. this.filterLogRow(row, this.wasScrolledToBottom);
  14981. if (this.wasScrolledToBottom)
  14982. scrollToBottom(this.panelNode);
  14983. return row;
  14984. }
  14985. },
  14986. clear: function()
  14987. {
  14988. if (this.panelNode)
  14989. {
  14990. if (FBTrace.DBG_CONSOLE)
  14991. FBTrace.sysout("ConsolePanel.clear");
  14992. clearNode(this.panelNode);
  14993. this.insertLogLimit(this.context);
  14994. }
  14995. },
  14996. insertLogLimit: function()
  14997. {
  14998. // Create limit row. This row is the first in the list of entries
  14999. // and initially hidden. It's displayed as soon as the number of
  15000. // entries reaches the limit.
  15001. var row = this.createRow("limitRow");
  15002. var limitInfo = {
  15003. totalCount: 0,
  15004. limitPrefsTitle: $STRF("LimitPrefsTitle", [Firebug.prefDomain+".console.logLimit"])
  15005. };
  15006. //TODO: xxxpedro console net limit!?
  15007. return;
  15008. var netLimitRep = Firebug.NetMonitor.NetLimit;
  15009. var nodes = netLimitRep.createTable(row, limitInfo);
  15010. this.limit = nodes[1];
  15011. var container = this.panelNode;
  15012. container.insertBefore(nodes[0], container.firstChild);
  15013. },
  15014. insertReloadWarning: function()
  15015. {
  15016. // put the message in, we will clear if the window console is injected.
  15017. this.warningRow = this.append(appendObject, $STR("message.Reload to activate window console"), "info");
  15018. },
  15019. clearReloadWarning: function()
  15020. {
  15021. if (this.warningRow)
  15022. {
  15023. this.warningRow.parentNode.removeChild(this.warningRow);
  15024. delete this.warningRow;
  15025. }
  15026. },
  15027. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15028. appendObject: function(object, row, rep)
  15029. {
  15030. if (!rep)
  15031. rep = Firebug.getRep(object);
  15032. return rep.tag.append({object: object}, row);
  15033. },
  15034. appendFormatted: function(objects, row, rep)
  15035. {
  15036. if (!objects || !objects.length)
  15037. return;
  15038. function logText(text, row)
  15039. {
  15040. var node = row.ownerDocument.createTextNode(text);
  15041. row.appendChild(node);
  15042. }
  15043. var format = objects[0];
  15044. var objIndex = 0;
  15045. if (typeof(format) != "string")
  15046. {
  15047. format = "";
  15048. objIndex = -1;
  15049. }
  15050. else // a string
  15051. {
  15052. if (objects.length === 1) // then we have only a string...
  15053. {
  15054. if (format.length < 1) { // ...and it has no characters.
  15055. logText("(an empty string)", row);
  15056. return;
  15057. }
  15058. }
  15059. }
  15060. var parts = parseFormat(format);
  15061. var trialIndex = objIndex;
  15062. for (var i= 0; i < parts.length; i++)
  15063. {
  15064. var part = parts[i];
  15065. if (part && typeof(part) == "object")
  15066. {
  15067. if (++trialIndex > objects.length) // then too few parameters for format, assume unformatted.
  15068. {
  15069. format = "";
  15070. objIndex = -1;
  15071. parts.length = 0;
  15072. break;
  15073. }
  15074. }
  15075. }
  15076. for (var i = 0; i < parts.length; ++i)
  15077. {
  15078. var part = parts[i];
  15079. if (part && typeof(part) == "object")
  15080. {
  15081. var object = objects[++objIndex];
  15082. if (typeof(object) != "undefined")
  15083. this.appendObject(object, row, part.rep);
  15084. else
  15085. this.appendObject(part.type, row, FirebugReps.Text);
  15086. }
  15087. else
  15088. FirebugReps.Text.tag.append({object: part}, row);
  15089. }
  15090. for (var i = objIndex+1; i < objects.length; ++i)
  15091. {
  15092. logText(" ", row);
  15093. var object = objects[i];
  15094. if (typeof(object) == "string")
  15095. FirebugReps.Text.tag.append({object: object}, row);
  15096. else
  15097. this.appendObject(object, row);
  15098. }
  15099. },
  15100. appendOpenGroup: function(objects, row, rep)
  15101. {
  15102. if (!this.groups)
  15103. this.groups = [];
  15104. setClass(row, "logGroup");
  15105. setClass(row, "opened");
  15106. var innerRow = this.createRow("logRow");
  15107. setClass(innerRow, "logGroupLabel");
  15108. if (rep)
  15109. rep.tag.replace({"objects": objects}, innerRow);
  15110. else
  15111. this.appendFormatted(objects, innerRow, rep);
  15112. row.appendChild(innerRow);
  15113. //dispatch([Firebug.A11yModel], 'onLogRowCreated', [this, innerRow]);
  15114. var groupBody = this.createRow("logGroupBody");
  15115. row.appendChild(groupBody);
  15116. groupBody.setAttribute('role', 'group');
  15117. this.groups.push(groupBody);
  15118. addEvent(innerRow, "mousedown", function(event)
  15119. {
  15120. if (isLeftClick(event))
  15121. {
  15122. //console.log(event.currentTarget == event.target);
  15123. var target = event.target || event.srcElement;
  15124. target = getAncestorByClass(target, "logGroupLabel");
  15125. var groupRow = target.parentNode;
  15126. if (hasClass(groupRow, "opened"))
  15127. {
  15128. removeClass(groupRow, "opened");
  15129. target.setAttribute('aria-expanded', 'false');
  15130. }
  15131. else
  15132. {
  15133. setClass(groupRow, "opened");
  15134. target.setAttribute('aria-expanded', 'true');
  15135. }
  15136. }
  15137. });
  15138. },
  15139. appendCloseGroup: function(object, row, rep)
  15140. {
  15141. if (this.groups)
  15142. this.groups.pop();
  15143. },
  15144. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15145. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15146. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15147. // TODO: xxxpedro console2
  15148. onMouseMove: function(event)
  15149. {
  15150. var target = event.srcElement || event.target;
  15151. var object = getAncestorByClass(target, "objectLink-element");
  15152. object = object ? object.repObject : null;
  15153. if(object && instanceOf(object, "Element") && object.nodeType == 1)
  15154. {
  15155. if(object != lastHighlightedObject)
  15156. {
  15157. Firebug.Inspector.drawBoxModel(object);
  15158. object = lastHighlightedObject;
  15159. }
  15160. }
  15161. else
  15162. Firebug.Inspector.hideBoxModel();
  15163. },
  15164. onMouseDown: function(event)
  15165. {
  15166. var target = event.srcElement || event.target;
  15167. var object = getAncestorByClass(target, "objectLink");
  15168. var repObject = object ? object.repObject : null;
  15169. if (!repObject)
  15170. {
  15171. return;
  15172. }
  15173. if (hasClass(object, "objectLink-object"))
  15174. {
  15175. Firebug.chrome.selectPanel("DOM");
  15176. Firebug.chrome.getPanel("DOM").select(repObject, true);
  15177. }
  15178. else if (hasClass(object, "objectLink-element"))
  15179. {
  15180. Firebug.chrome.selectPanel("HTML");
  15181. Firebug.chrome.getPanel("HTML").select(repObject, true);
  15182. }
  15183. /*
  15184. if(object && instanceOf(object, "Element") && object.nodeType == 1)
  15185. {
  15186. if(object != lastHighlightedObject)
  15187. {
  15188. Firebug.Inspector.drawBoxModel(object);
  15189. object = lastHighlightedObject;
  15190. }
  15191. }
  15192. else
  15193. Firebug.Inspector.hideBoxModel();
  15194. /**/
  15195. },
  15196. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15197. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15198. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15199. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15200. // extends Panel
  15201. name: "Console",
  15202. title: "Console",
  15203. //searchable: true,
  15204. //breakable: true,
  15205. //editable: false,
  15206. options:
  15207. {
  15208. hasCommandLine: true,
  15209. hasToolButtons: true,
  15210. isPreRendered: true
  15211. },
  15212. create: function()
  15213. {
  15214. Firebug.Panel.create.apply(this, arguments);
  15215. this.context = Firebug.browser.window;
  15216. this.document = Firebug.chrome.document;
  15217. this.onMouseMove = bind(this.onMouseMove, this);
  15218. this.onMouseDown = bind(this.onMouseDown, this);
  15219. this.clearButton = new Button({
  15220. element: $("fbConsole_btClear"),
  15221. owner: Firebug.Console,
  15222. onClick: Firebug.Console.clear
  15223. });
  15224. },
  15225. initialize: function()
  15226. {
  15227. Firebug.Panel.initialize.apply(this, arguments); // loads persisted content
  15228. //Firebug.ActivablePanel.initialize.apply(this, arguments); // loads persisted content
  15229. if (!this.persistedContent && Firebug.Console.isAlwaysEnabled())
  15230. {
  15231. this.insertLogLimit(this.context);
  15232. // Initialize log limit and listen for changes.
  15233. this.updateMaxLimit();
  15234. if (this.context.consoleReloadWarning) // we have not yet injected the console
  15235. this.insertReloadWarning();
  15236. }
  15237. //Firebug.Console.injector.install(Firebug.browser.window);
  15238. addEvent(this.panelNode, "mouseover", this.onMouseMove);
  15239. addEvent(this.panelNode, "mousedown", this.onMouseDown);
  15240. this.clearButton.initialize();
  15241. //consolex.trace();
  15242. //TODO: xxxpedro remove this
  15243. /*
  15244. Firebug.Console.openGroup(["asd"], null, "group", null, false);
  15245. Firebug.Console.log("asd");
  15246. Firebug.Console.log("asd");
  15247. Firebug.Console.log("asd");
  15248. /**/
  15249. //TODO: xxxpedro preferences prefs
  15250. //prefs.addObserver(Firebug.prefDomain, this, false);
  15251. },
  15252. initializeNode : function()
  15253. {
  15254. //dispatch([Firebug.A11yModel], 'onInitializeNode', [this]);
  15255. if (FBTrace.DBG_CONSOLE)
  15256. {
  15257. this.onScroller = bind(this.onScroll, this);
  15258. addEvent(this.panelNode, "scroll", this.onScroller);
  15259. }
  15260. this.onResizer = bind(this.onResize, this);
  15261. this.resizeEventTarget = Firebug.chrome.$('fbContentBox');
  15262. addEvent(this.resizeEventTarget, "resize", this.onResizer);
  15263. },
  15264. destroyNode : function()
  15265. {
  15266. //dispatch([Firebug.A11yModel], 'onDestroyNode', [this]);
  15267. if (this.onScroller)
  15268. removeEvent(this.panelNode, "scroll", this.onScroller);
  15269. //removeEvent(this.resizeEventTarget, "resize", this.onResizer);
  15270. },
  15271. shutdown: function()
  15272. {
  15273. //TODO: xxxpedro console console2
  15274. this.clearButton.shutdown();
  15275. removeEvent(this.panelNode, "mousemove", this.onMouseMove);
  15276. removeEvent(this.panelNode, "mousedown", this.onMouseDown);
  15277. this.destroyNode();
  15278. Firebug.Panel.shutdown.apply(this, arguments);
  15279. //TODO: xxxpedro preferences prefs
  15280. //prefs.removeObserver(Firebug.prefDomain, this, false);
  15281. },
  15282. ishow: function(state)
  15283. {
  15284. if (FBTrace.DBG_CONSOLE)
  15285. FBTrace.sysout("Console.panel show; " + this.context.getName(), state);
  15286. var enabled = Firebug.Console.isAlwaysEnabled();
  15287. if (enabled)
  15288. {
  15289. Firebug.Console.disabledPanelPage.hide(this);
  15290. this.showCommandLine(true);
  15291. this.showToolbarButtons("fbConsoleButtons", true);
  15292. Firebug.chrome.setGlobalAttribute("cmd_togglePersistConsole", "checked", this.persistContent);
  15293. if (state && state.wasScrolledToBottom)
  15294. {
  15295. this.wasScrolledToBottom = state.wasScrolledToBottom;
  15296. delete state.wasScrolledToBottom;
  15297. }
  15298. if (this.wasScrolledToBottom)
  15299. scrollToBottom(this.panelNode);
  15300. if (FBTrace.DBG_CONSOLE)
  15301. FBTrace.sysout("console.show ------------------ wasScrolledToBottom: " +
  15302. this.wasScrolledToBottom + ", " + this.context.getName());
  15303. }
  15304. else
  15305. {
  15306. this.hide(state);
  15307. Firebug.Console.disabledPanelPage.show(this);
  15308. }
  15309. },
  15310. ihide: function(state)
  15311. {
  15312. if (FBTrace.DBG_CONSOLE)
  15313. FBTrace.sysout("Console.panel hide; " + this.context.getName(), state);
  15314. this.showToolbarButtons("fbConsoleButtons", false);
  15315. this.showCommandLine(false);
  15316. if (FBTrace.DBG_CONSOLE)
  15317. FBTrace.sysout("console.hide ------------------ wasScrolledToBottom: " +
  15318. this.wasScrolledToBottom + ", " + this.context.getName());
  15319. },
  15320. destroy: function(state)
  15321. {
  15322. if (this.panelNode.offsetHeight)
  15323. this.wasScrolledToBottom = isScrolledToBottom(this.panelNode);
  15324. if (state)
  15325. state.wasScrolledToBottom = this.wasScrolledToBottom;
  15326. if (FBTrace.DBG_CONSOLE)
  15327. FBTrace.sysout("console.destroy ------------------ wasScrolledToBottom: " +
  15328. this.wasScrolledToBottom + ", " + this.context.getName());
  15329. },
  15330. shouldBreakOnNext: function()
  15331. {
  15332. // xxxHonza: shouldn't the breakOnErrors be context related?
  15333. // xxxJJB, yes, but we can't support it because we can't yet tell
  15334. // which window the error is on.
  15335. return Firebug.getPref(Firebug.servicePrefDomain, "breakOnErrors");
  15336. },
  15337. getBreakOnNextTooltip: function(enabled)
  15338. {
  15339. return (enabled ? $STR("console.Disable Break On All Errors") :
  15340. $STR("console.Break On All Errors"));
  15341. },
  15342. enablePanel: function(module)
  15343. {
  15344. if (FBTrace.DBG_CONSOLE)
  15345. FBTrace.sysout("console.ConsolePanel.enablePanel; " + this.context.getName());
  15346. Firebug.ActivablePanel.enablePanel.apply(this, arguments);
  15347. this.showCommandLine(true);
  15348. if (this.wasScrolledToBottom)
  15349. scrollToBottom(this.panelNode);
  15350. },
  15351. disablePanel: function(module)
  15352. {
  15353. if (FBTrace.DBG_CONSOLE)
  15354. FBTrace.sysout("console.ConsolePanel.disablePanel; " + this.context.getName());
  15355. Firebug.ActivablePanel.disablePanel.apply(this, arguments);
  15356. this.showCommandLine(false);
  15357. },
  15358. getOptionsMenuItems: function()
  15359. {
  15360. return [
  15361. optionMenu("ShowJavaScriptErrors", "showJSErrors"),
  15362. optionMenu("ShowJavaScriptWarnings", "showJSWarnings"),
  15363. optionMenu("ShowCSSErrors", "showCSSErrors"),
  15364. optionMenu("ShowXMLErrors", "showXMLErrors"),
  15365. optionMenu("ShowXMLHttpRequests", "showXMLHttpRequests"),
  15366. optionMenu("ShowChromeErrors", "showChromeErrors"),
  15367. optionMenu("ShowChromeMessages", "showChromeMessages"),
  15368. optionMenu("ShowExternalErrors", "showExternalErrors"),
  15369. optionMenu("ShowNetworkErrors", "showNetworkErrors"),
  15370. this.getShowStackTraceMenuItem(),
  15371. this.getStrictOptionMenuItem(),
  15372. "-",
  15373. optionMenu("LargeCommandLine", "largeCommandLine")
  15374. ];
  15375. },
  15376. getShowStackTraceMenuItem: function()
  15377. {
  15378. var menuItem = serviceOptionMenu("ShowStackTrace", "showStackTrace");
  15379. if (FirebugContext && !Firebug.Debugger.isAlwaysEnabled())
  15380. menuItem.disabled = true;
  15381. return menuItem;
  15382. },
  15383. getStrictOptionMenuItem: function()
  15384. {
  15385. var strictDomain = "javascript.options";
  15386. var strictName = "strict";
  15387. var strictValue = prefs.getBoolPref(strictDomain+"."+strictName);
  15388. return {label: "JavascriptOptionsStrict", type: "checkbox", checked: strictValue,
  15389. command: bindFixed(Firebug.setPref, Firebug, strictDomain, strictName, !strictValue) };
  15390. },
  15391. getBreakOnMenuItems: function()
  15392. {
  15393. //xxxHonza: no BON options for now.
  15394. /*return [
  15395. optionMenu("console.option.Persist Break On Error", "persistBreakOnError")
  15396. ];*/
  15397. return [];
  15398. },
  15399. search: function(text)
  15400. {
  15401. if (!text)
  15402. return;
  15403. // Make previously visible nodes invisible again
  15404. if (this.matchSet)
  15405. {
  15406. for (var i in this.matchSet)
  15407. removeClass(this.matchSet[i], "matched");
  15408. }
  15409. this.matchSet = [];
  15410. function findRow(node) { return getAncestorByClass(node, "logRow"); }
  15411. var search = new TextSearch(this.panelNode, findRow);
  15412. var logRow = search.find(text);
  15413. if (!logRow)
  15414. {
  15415. dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, []]);
  15416. return false;
  15417. }
  15418. for (; logRow; logRow = search.findNext())
  15419. {
  15420. setClass(logRow, "matched");
  15421. this.matchSet.push(logRow);
  15422. }
  15423. dispatch([Firebug.A11yModel], 'onConsoleSearchMatchFound', [this, text, this.matchSet]);
  15424. return true;
  15425. },
  15426. breakOnNext: function(breaking)
  15427. {
  15428. Firebug.setPref(Firebug.servicePrefDomain, "breakOnErrors", breaking);
  15429. },
  15430. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15431. // private
  15432. createRow: function(rowName, className)
  15433. {
  15434. var elt = this.document.createElement("div");
  15435. elt.className = rowName + (className ? " " + rowName + "-" + className : "");
  15436. return elt;
  15437. },
  15438. getTopContainer: function()
  15439. {
  15440. if (this.groups && this.groups.length)
  15441. return this.groups[this.groups.length-1];
  15442. else
  15443. return this.panelNode;
  15444. },
  15445. filterLogRow: function(logRow, scrolledToBottom)
  15446. {
  15447. if (this.searchText)
  15448. {
  15449. setClass(logRow, "matching");
  15450. setClass(logRow, "matched");
  15451. // Search after a delay because we must wait for a frame to be created for
  15452. // the new logRow so that the finder will be able to locate it
  15453. setTimeout(bindFixed(function()
  15454. {
  15455. if (this.searchFilter(this.searchText, logRow))
  15456. this.matchSet.push(logRow);
  15457. else
  15458. removeClass(logRow, "matched");
  15459. removeClass(logRow, "matching");
  15460. if (scrolledToBottom)
  15461. scrollToBottom(this.panelNode);
  15462. }, this), 100);
  15463. }
  15464. },
  15465. searchFilter: function(text, logRow)
  15466. {
  15467. var count = this.panelNode.childNodes.length;
  15468. var searchRange = this.document.createRange();
  15469. searchRange.setStart(this.panelNode, 0);
  15470. searchRange.setEnd(this.panelNode, count);
  15471. var startPt = this.document.createRange();
  15472. startPt.setStartBefore(logRow);
  15473. var endPt = this.document.createRange();
  15474. endPt.setStartAfter(logRow);
  15475. return finder.Find(text, searchRange, startPt, endPt) != null;
  15476. },
  15477. // nsIPrefObserver
  15478. observe: function(subject, topic, data)
  15479. {
  15480. // We're observing preferences only.
  15481. if (topic != "nsPref:changed")
  15482. return;
  15483. // xxxHonza check this out.
  15484. var prefDomain = "Firebug.extension.";
  15485. var prefName = data.substr(prefDomain.length);
  15486. if (prefName == "console.logLimit")
  15487. this.updateMaxLimit();
  15488. },
  15489. updateMaxLimit: function()
  15490. {
  15491. var value = 1000;
  15492. //TODO: xxxpedro preferences log limit?
  15493. //var value = Firebug.getPref(Firebug.prefDomain, "console.logLimit");
  15494. maxQueueRequests = value ? value : maxQueueRequests;
  15495. },
  15496. showCommandLine: function(shouldShow)
  15497. {
  15498. //TODO: xxxpedro show command line important
  15499. return;
  15500. if (shouldShow)
  15501. {
  15502. collapse(Firebug.chrome.$("fbCommandBox"), false);
  15503. Firebug.CommandLine.setMultiLine(Firebug.largeCommandLine, Firebug.chrome);
  15504. }
  15505. else
  15506. {
  15507. // Make sure that entire content of the Console panel is hidden when
  15508. // the panel is disabled.
  15509. Firebug.CommandLine.setMultiLine(false, Firebug.chrome, Firebug.largeCommandLine);
  15510. collapse(Firebug.chrome.$("fbCommandBox"), true);
  15511. }
  15512. },
  15513. onScroll: function(event)
  15514. {
  15515. // Update the scroll position flag if the position changes.
  15516. this.wasScrolledToBottom = FBL.isScrolledToBottom(this.panelNode);
  15517. if (FBTrace.DBG_CONSOLE)
  15518. FBTrace.sysout("console.onScroll ------------------ wasScrolledToBottom: " +
  15519. this.wasScrolledToBottom + ", wasScrolledToBottom: " +
  15520. this.context.getName(), event);
  15521. },
  15522. onResize: function(event)
  15523. {
  15524. if (FBTrace.DBG_CONSOLE)
  15525. FBTrace.sysout("console.onResize ------------------ wasScrolledToBottom: " +
  15526. this.wasScrolledToBottom + ", offsetHeight: " + this.panelNode.offsetHeight +
  15527. ", scrollTop: " + this.panelNode.scrollTop + ", scrollHeight: " +
  15528. this.panelNode.scrollHeight + ", " + this.context.getName(), event);
  15529. if (this.wasScrolledToBottom)
  15530. scrollToBottom(this.panelNode);
  15531. }
  15532. });
  15533. // ************************************************************************************************
  15534. function parseFormat(format)
  15535. {
  15536. var parts = [];
  15537. if (format.length <= 0)
  15538. return parts;
  15539. var reg = /((^%|.%)(\d+)?(\.)([a-zA-Z]))|((^%|.%)([a-zA-Z]))/;
  15540. for (var m = reg.exec(format); m; m = reg.exec(format))
  15541. {
  15542. if (m[0].substr(0, 2) == "%%")
  15543. {
  15544. parts.push(format.substr(0, m.index));
  15545. parts.push(m[0].substr(1));
  15546. }
  15547. else
  15548. {
  15549. var type = m[8] ? m[8] : m[5];
  15550. var precision = m[3] ? parseInt(m[3]) : (m[4] == "." ? -1 : 0);
  15551. var rep = null;
  15552. switch (type)
  15553. {
  15554. case "s":
  15555. rep = FirebugReps.Text;
  15556. break;
  15557. case "f":
  15558. case "i":
  15559. case "d":
  15560. rep = FirebugReps.Number;
  15561. break;
  15562. case "o":
  15563. rep = null;
  15564. break;
  15565. }
  15566. parts.push(format.substr(0, m[0][0] == "%" ? m.index : m.index+1));
  15567. parts.push({rep: rep, precision: precision, type: ("%" + type)});
  15568. }
  15569. format = format.substr(m.index+m[0].length);
  15570. }
  15571. parts.push(format);
  15572. return parts;
  15573. }
  15574. // ************************************************************************************************
  15575. var appendObject = Firebug.ConsolePanel.prototype.appendObject;
  15576. var appendFormatted = Firebug.ConsolePanel.prototype.appendFormatted;
  15577. var appendOpenGroup = Firebug.ConsolePanel.prototype.appendOpenGroup;
  15578. var appendCloseGroup = Firebug.ConsolePanel.prototype.appendCloseGroup;
  15579. // ************************************************************************************************
  15580. //Firebug.registerActivableModule(Firebug.Console);
  15581. Firebug.registerModule(Firebug.Console);
  15582. Firebug.registerPanel(Firebug.ConsolePanel);
  15583. // ************************************************************************************************
  15584. }});
  15585. /* See license.txt for terms of usage */
  15586. FBL.ns(function() { with (FBL) {
  15587. // ************************************************************************************************
  15588. // Constants
  15589. //const Cc = Components.classes;
  15590. //const Ci = Components.interfaces;
  15591. var frameCounters = {};
  15592. var traceRecursion = 0;
  15593. Firebug.Console.injector =
  15594. {
  15595. install: function(context)
  15596. {
  15597. var win = context.window;
  15598. var consoleHandler = new FirebugConsoleHandler(context, win);
  15599. var properties =
  15600. [
  15601. "log",
  15602. "debug",
  15603. "info",
  15604. "warn",
  15605. "error",
  15606. "assert",
  15607. "dir",
  15608. "dirxml",
  15609. "group",
  15610. "groupCollapsed",
  15611. "groupEnd",
  15612. "time",
  15613. "timeEnd",
  15614. "count",
  15615. "trace",
  15616. "profile",
  15617. "profileEnd",
  15618. "clear",
  15619. "open",
  15620. "close"
  15621. ];
  15622. var Handler = function(name)
  15623. {
  15624. var c = consoleHandler;
  15625. var f = consoleHandler[name];
  15626. return function(){return f.apply(c,arguments)};
  15627. };
  15628. var installer = function(c)
  15629. {
  15630. for (var i=0, l=properties.length; i<l; i++)
  15631. {
  15632. var name = properties[i];
  15633. c[name] = new Handler(name);
  15634. c.firebuglite = Firebug.version;
  15635. }
  15636. };
  15637. var consoleNS = (!isFirefox || isFirefox && !("console" in win)) ? "console" : "firebug";
  15638. var sandbox = new win.Function("arguments.callee.install(window." + consoleNS + "={})");
  15639. sandbox.install = installer;
  15640. sandbox();
  15641. },
  15642. isAttached: function(context, win)
  15643. {
  15644. if (win.wrappedJSObject)
  15645. {
  15646. var attached = (win.wrappedJSObject._getFirebugConsoleElement ? true : false);
  15647. if (FBTrace.DBG_CONSOLE)
  15648. FBTrace.sysout("Console.isAttached:"+attached+" to win.wrappedJSObject "+safeGetWindowLocation(win.wrappedJSObject));
  15649. return attached;
  15650. }
  15651. else
  15652. {
  15653. if (FBTrace.DBG_CONSOLE)
  15654. FBTrace.sysout("Console.isAttached? to win "+win.location+" fnc:"+win._getFirebugConsoleElement);
  15655. return (win._getFirebugConsoleElement ? true : false);
  15656. }
  15657. },
  15658. attachIfNeeded: function(context, win)
  15659. {
  15660. if (FBTrace.DBG_CONSOLE)
  15661. FBTrace.sysout("Console.attachIfNeeded has win "+(win? ((win.wrappedJSObject?"YES":"NO")+" wrappedJSObject"):"null") );
  15662. if (this.isAttached(context, win))
  15663. return true;
  15664. if (FBTrace.DBG_CONSOLE)
  15665. FBTrace.sysout("Console.attachIfNeeded found isAttached false ");
  15666. this.attachConsoleInjector(context, win);
  15667. this.addConsoleListener(context, win);
  15668. Firebug.Console.clearReloadWarning(context);
  15669. var attached = this.isAttached(context, win);
  15670. if (attached)
  15671. dispatch(Firebug.Console.fbListeners, "onConsoleInjected", [context, win]);
  15672. return attached;
  15673. },
  15674. attachConsoleInjector: function(context, win)
  15675. {
  15676. var consoleInjection = this.getConsoleInjectionScript(); // Do it all here.
  15677. if (FBTrace.DBG_CONSOLE)
  15678. FBTrace.sysout("attachConsoleInjector evaluating in "+win.location, consoleInjection);
  15679. Firebug.CommandLine.evaluateInWebPage(consoleInjection, context, win);
  15680. if (FBTrace.DBG_CONSOLE)
  15681. FBTrace.sysout("attachConsoleInjector evaluation completed for "+win.location);
  15682. },
  15683. getConsoleInjectionScript: function() {
  15684. if (!this.consoleInjectionScript)
  15685. {
  15686. var script = "";
  15687. script += "window.__defineGetter__('console', function() {\n";
  15688. script += " return (window._firebug ? window._firebug : window.loadFirebugConsole()); })\n\n";
  15689. script += "window.loadFirebugConsole = function() {\n";
  15690. script += "window._firebug = new _FirebugConsole();";
  15691. if (FBTrace.DBG_CONSOLE)
  15692. script += " window.dump('loadFirebugConsole '+window.location+'\\n');\n";
  15693. script += " return window._firebug };\n";
  15694. var theFirebugConsoleScript = getResource("chrome://firebug/content/consoleInjected.js");
  15695. script += theFirebugConsoleScript;
  15696. this.consoleInjectionScript = script;
  15697. }
  15698. return this.consoleInjectionScript;
  15699. },
  15700. forceConsoleCompilationInPage: function(context, win)
  15701. {
  15702. if (!win)
  15703. {
  15704. if (FBTrace.DBG_CONSOLE)
  15705. FBTrace.sysout("no win in forceConsoleCompilationInPage!");
  15706. return;
  15707. }
  15708. var consoleForcer = "window.loadFirebugConsole();";
  15709. if (context.stopped)
  15710. Firebug.Console.injector.evaluateConsoleScript(context); // todo evaluate consoleForcer on stack
  15711. else
  15712. Firebug.CommandLine.evaluateInWebPage(consoleForcer, context, win);
  15713. if (FBTrace.DBG_CONSOLE)
  15714. FBTrace.sysout("forceConsoleCompilationInPage "+win.location, consoleForcer);
  15715. },
  15716. evaluateConsoleScript: function(context)
  15717. {
  15718. var scriptSource = this.getConsoleInjectionScript(); // TODO XXXjjb this should be getConsoleInjectionScript
  15719. Firebug.Debugger.evaluate(scriptSource, context);
  15720. },
  15721. addConsoleListener: function(context, win)
  15722. {
  15723. if (!context.activeConsoleHandlers) // then we have not been this way before
  15724. context.activeConsoleHandlers = [];
  15725. else
  15726. { // we've been this way before...
  15727. for (var i=0; i<context.activeConsoleHandlers.length; i++)
  15728. {
  15729. if (context.activeConsoleHandlers[i].window == win)
  15730. {
  15731. context.activeConsoleHandlers[i].detach();
  15732. if (FBTrace.DBG_CONSOLE)
  15733. FBTrace.sysout("consoleInjector addConsoleListener removed handler("+context.activeConsoleHandlers[i].handler_name+") from _firebugConsole in : "+win.location+"\n");
  15734. context.activeConsoleHandlers.splice(i,1);
  15735. }
  15736. }
  15737. }
  15738. // We need the element to attach our event listener.
  15739. var element = Firebug.Console.getFirebugConsoleElement(context, win);
  15740. if (element)
  15741. element.setAttribute("FirebugVersion", Firebug.version); // Initialize Firebug version.
  15742. else
  15743. return false;
  15744. var handler = new FirebugConsoleHandler(context, win);
  15745. handler.attachTo(element);
  15746. context.activeConsoleHandlers.push(handler);
  15747. if (FBTrace.DBG_CONSOLE)
  15748. FBTrace.sysout("consoleInjector addConsoleListener attached handler("+handler.handler_name+") to _firebugConsole in : "+win.location+"\n");
  15749. return true;
  15750. },
  15751. detachConsole: function(context, win)
  15752. {
  15753. if (win && win.document)
  15754. {
  15755. var element = win.document.getElementById("_firebugConsole");
  15756. if (element)
  15757. element.parentNode.removeChild(element);
  15758. }
  15759. }
  15760. }
  15761. var total_handlers = 0;
  15762. var FirebugConsoleHandler = function FirebugConsoleHandler(context, win)
  15763. {
  15764. this.window = win;
  15765. this.attachTo = function(element)
  15766. {
  15767. this.element = element;
  15768. // When raised on our injected element, callback to Firebug and append to console
  15769. this.boundHandler = bind(this.handleEvent, this);
  15770. this.element.addEventListener('firebugAppendConsole', this.boundHandler, true); // capturing
  15771. };
  15772. this.detach = function()
  15773. {
  15774. this.element.removeEventListener('firebugAppendConsole', this.boundHandler, true);
  15775. };
  15776. this.handler_name = ++total_handlers;
  15777. this.handleEvent = function(event)
  15778. {
  15779. if (FBTrace.DBG_CONSOLE)
  15780. FBTrace.sysout("FirebugConsoleHandler("+this.handler_name+") "+event.target.getAttribute("methodName")+", event", event);
  15781. if (!Firebug.CommandLine.CommandHandler.handle(event, this, win))
  15782. {
  15783. if (FBTrace.DBG_CONSOLE)
  15784. FBTrace.sysout("FirebugConsoleHandler", this);
  15785. var methodName = event.target.getAttribute("methodName");
  15786. Firebug.Console.log($STRF("console.MethodNotSupported", [methodName]));
  15787. }
  15788. };
  15789. this.firebuglite = Firebug.version;
  15790. this.init = function()
  15791. {
  15792. var consoleElement = win.document.getElementById('_firebugConsole');
  15793. consoleElement.setAttribute("FirebugVersion", Firebug.version);
  15794. };
  15795. this.log = function()
  15796. {
  15797. logFormatted(arguments, "log");
  15798. };
  15799. this.debug = function()
  15800. {
  15801. logFormatted(arguments, "debug", true);
  15802. };
  15803. this.info = function()
  15804. {
  15805. logFormatted(arguments, "info", true);
  15806. };
  15807. this.warn = function()
  15808. {
  15809. logFormatted(arguments, "warn", true);
  15810. };
  15811. this.error = function()
  15812. {
  15813. //TODO: xxxpedro console error
  15814. //if (arguments.length == 1)
  15815. //{
  15816. // logAssert("error", arguments); // add more info based on stack trace
  15817. //}
  15818. //else
  15819. //{
  15820. //Firebug.Errors.increaseCount(context);
  15821. logFormatted(arguments, "error", true); // user already added info
  15822. //}
  15823. };
  15824. this.exception = function()
  15825. {
  15826. logAssert("error", arguments);
  15827. };
  15828. this.assert = function(x)
  15829. {
  15830. if (!x)
  15831. {
  15832. var rest = [];
  15833. for (var i = 1; i < arguments.length; i++)
  15834. rest.push(arguments[i]);
  15835. logAssert("assert", rest);
  15836. }
  15837. };
  15838. this.dir = function(o)
  15839. {
  15840. Firebug.Console.log(o, context, "dir", Firebug.DOMPanel.DirTable);
  15841. };
  15842. this.dirxml = function(o)
  15843. {
  15844. ///if (o instanceof Window)
  15845. if (instanceOf(o, "Window"))
  15846. o = o.document.documentElement;
  15847. ///else if (o instanceof Document)
  15848. else if (instanceOf(o, "Document"))
  15849. o = o.documentElement;
  15850. // TODO: xxxpedro html3
  15851. ///Firebug.Console.log(o, context, "dirxml", Firebug.HTMLPanel.SoloElement);
  15852. var div = Firebug.Console.log(o, context, "dirxml");
  15853. var html = [];
  15854. Firebug.Reps.appendNode(o, html);
  15855. div.innerHTML = html.join("");
  15856. };
  15857. this.group = function()
  15858. {
  15859. //TODO: xxxpedro;
  15860. //var sourceLink = getStackLink();
  15861. var sourceLink = null;
  15862. Firebug.Console.openGroup(arguments, null, "group", null, false, sourceLink);
  15863. };
  15864. this.groupEnd = function()
  15865. {
  15866. Firebug.Console.closeGroup(context);
  15867. };
  15868. this.groupCollapsed = function()
  15869. {
  15870. var sourceLink = getStackLink();
  15871. // noThrottle true is probably ok, openGroups will likely be short strings.
  15872. var row = Firebug.Console.openGroup(arguments, null, "group", null, true, sourceLink);
  15873. removeClass(row, "opened");
  15874. };
  15875. this.profile = function(title)
  15876. {
  15877. logFormatted(["console.profile() not supported."], "warn", true);
  15878. //Firebug.Profiler.startProfiling(context, title);
  15879. };
  15880. this.profileEnd = function()
  15881. {
  15882. logFormatted(["console.profile() not supported."], "warn", true);
  15883. //Firebug.Profiler.stopProfiling(context);
  15884. };
  15885. this.count = function(key)
  15886. {
  15887. // TODO: xxxpedro console2: is there a better way to find a unique ID for the coun() call?
  15888. var frameId = "0";
  15889. //var frameId = FBL.getStackFrameId();
  15890. if (frameId)
  15891. {
  15892. if (!frameCounters)
  15893. frameCounters = {};
  15894. if (key != undefined)
  15895. frameId += key;
  15896. var frameCounter = frameCounters[frameId];
  15897. if (!frameCounter)
  15898. {
  15899. var logRow = logFormatted(["0"], null, true, true);
  15900. frameCounter = {logRow: logRow, count: 1};
  15901. frameCounters[frameId] = frameCounter;
  15902. }
  15903. else
  15904. ++frameCounter.count;
  15905. var label = key == undefined
  15906. ? frameCounter.count
  15907. : key + " " + frameCounter.count;
  15908. frameCounter.logRow.firstChild.firstChild.nodeValue = label;
  15909. }
  15910. };
  15911. this.trace = function()
  15912. {
  15913. var getFuncName = function getFuncName (f)
  15914. {
  15915. if (f.getName instanceof Function)
  15916. {
  15917. return f.getName();
  15918. }
  15919. if (f.name) // in FireFox, Function objects have a name property...
  15920. {
  15921. return f.name;
  15922. }
  15923. var name = f.toString().match(/function\s*([_$\w\d]*)/)[1];
  15924. return name || "anonymous";
  15925. };
  15926. var wasVisited = function(fn)
  15927. {
  15928. for (var i=0, l=frames.length; i<l; i++)
  15929. {
  15930. if (frames[i].fn == fn)
  15931. {
  15932. return true;
  15933. }
  15934. }
  15935. return false;
  15936. };
  15937. traceRecursion++;
  15938. if (traceRecursion > 1)
  15939. {
  15940. traceRecursion--;
  15941. return;
  15942. }
  15943. var frames = [];
  15944. for (var fn = arguments.callee.caller.caller; fn; fn = fn.caller)
  15945. {
  15946. if (wasVisited(fn)) break;
  15947. var args = [];
  15948. for (var i = 0, l = fn.arguments.length; i < l; ++i)
  15949. {
  15950. args.push({value: fn.arguments[i]});
  15951. }
  15952. frames.push({fn: fn, name: getFuncName(fn), args: args});
  15953. }
  15954. // ****************************************************************************************
  15955. try
  15956. {
  15957. (0)();
  15958. }
  15959. catch(e)
  15960. {
  15961. var result = e;
  15962. var stack =
  15963. result.stack || // Firefox / Google Chrome
  15964. result.stacktrace || // Opera
  15965. "";
  15966. stack = stack.replace(/\n\r|\r\n/g, "\n"); // normalize line breaks
  15967. var items = stack.split(/[\n\r]/);
  15968. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  15969. // Google Chrome
  15970. if (FBL.isSafari)
  15971. {
  15972. //var reChromeStackItem = /^\s+at\s+([^\(]+)\s\((.*)\)$/;
  15973. //var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/;
  15974. var reChromeStackItem = /^\s+at\s+(.*)((?:http|https|ftp|file):\/\/.*)$/;
  15975. var reChromeStackItemName = /\s*\($/;
  15976. var reChromeStackItemValue = /^(.+)\:(\d+\:\d+)\)?$/;
  15977. var framePos = 0;
  15978. for (var i=4, length=items.length; i<length; i++, framePos++)
  15979. {
  15980. var frame = frames[framePos];
  15981. var item = items[i];
  15982. var match = item.match(reChromeStackItem);
  15983. //Firebug.Console.log("["+ framePos +"]--------------------------");
  15984. //Firebug.Console.log(item);
  15985. //Firebug.Console.log("................");
  15986. if (match)
  15987. {
  15988. var name = match[1];
  15989. if (name)
  15990. {
  15991. name = name.replace(reChromeStackItemName, "");
  15992. frame.name = name;
  15993. }
  15994. //Firebug.Console.log("name: "+name);
  15995. var value = match[2].match(reChromeStackItemValue);
  15996. if (value)
  15997. {
  15998. frame.href = value[1];
  15999. frame.lineNo = value[2];
  16000. //Firebug.Console.log("url: "+value[1]);
  16001. //Firebug.Console.log("line: "+value[2]);
  16002. }
  16003. //else
  16004. // Firebug.Console.log(match[2]);
  16005. }
  16006. }
  16007. }
  16008. /**/
  16009. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16010. else if (FBL.isFirefox)
  16011. {
  16012. // Firefox
  16013. var reFirefoxStackItem = /^(.*)@(.*)$/;
  16014. var reFirefoxStackItemValue = /^(.+)\:(\d+)$/;
  16015. var framePos = 0;
  16016. for (var i=2, length=items.length; i<length; i++, framePos++)
  16017. {
  16018. var frame = frames[framePos] || {};
  16019. var item = items[i];
  16020. var match = item.match(reFirefoxStackItem);
  16021. if (match)
  16022. {
  16023. var name = match[1];
  16024. //Firebug.Console.logFormatted("name: "+name);
  16025. var value = match[2].match(reFirefoxStackItemValue);
  16026. if (value)
  16027. {
  16028. frame.href = value[1];
  16029. frame.lineNo = value[2];
  16030. //Firebug.Console.log("href: "+ value[1]);
  16031. //Firebug.Console.log("line: " + value[2]);
  16032. }
  16033. //else
  16034. // Firebug.Console.logFormatted([match[2]]);
  16035. }
  16036. }
  16037. }
  16038. /**/
  16039. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16040. /*
  16041. else if (FBL.isOpera)
  16042. {
  16043. // Opera
  16044. var reOperaStackItem = /^\s\s(?:\.\.\.\s\s)?Line\s(\d+)\sof\s(.+)$/;
  16045. var reOperaStackItemValue = /^linked\sscript\s(.+)$/;
  16046. for (var i=0, length=items.length; i<length; i+=2)
  16047. {
  16048. var item = items[i];
  16049. var match = item.match(reOperaStackItem);
  16050. if (match)
  16051. {
  16052. //Firebug.Console.log(match[1]);
  16053. var value = match[2].match(reOperaStackItemValue);
  16054. if (value)
  16055. {
  16056. //Firebug.Console.log(value[1]);
  16057. }
  16058. //else
  16059. // Firebug.Console.log(match[2]);
  16060. //Firebug.Console.log("--------------------------");
  16061. }
  16062. }
  16063. }
  16064. /**/
  16065. }
  16066. //console.log(stack);
  16067. //console.dir(frames);
  16068. Firebug.Console.log({frames: frames}, context, "stackTrace", FirebugReps.StackTrace);
  16069. traceRecursion--;
  16070. };
  16071. this.trace_ok = function()
  16072. {
  16073. var getFuncName = function getFuncName (f)
  16074. {
  16075. if (f.getName instanceof Function)
  16076. return f.getName();
  16077. if (f.name) // in FireFox, Function objects have a name property...
  16078. return f.name;
  16079. var name = f.toString().match(/function\s*([_$\w\d]*)/)[1];
  16080. return name || "anonymous";
  16081. };
  16082. var wasVisited = function(fn)
  16083. {
  16084. for (var i=0, l=frames.length; i<l; i++)
  16085. {
  16086. if (frames[i].fn == fn)
  16087. return true;
  16088. }
  16089. return false;
  16090. };
  16091. var frames = [];
  16092. for (var fn = arguments.callee.caller; fn; fn = fn.caller)
  16093. {
  16094. if (wasVisited(fn)) break;
  16095. var args = [];
  16096. for (var i = 0, l = fn.arguments.length; i < l; ++i)
  16097. {
  16098. args.push({value: fn.arguments[i]});
  16099. }
  16100. frames.push({fn: fn, name: getFuncName(fn), args: args});
  16101. }
  16102. Firebug.Console.log({frames: frames}, context, "stackTrace", FirebugReps.StackTrace);
  16103. };
  16104. this.clear = function()
  16105. {
  16106. Firebug.Console.clear(context);
  16107. };
  16108. this.time = function(name, reset)
  16109. {
  16110. if (!name)
  16111. return;
  16112. var time = new Date().getTime();
  16113. if (!this.timeCounters)
  16114. this.timeCounters = {};
  16115. var key = "KEY"+name.toString();
  16116. if (!reset && this.timeCounters[key])
  16117. return;
  16118. this.timeCounters[key] = time;
  16119. };
  16120. this.timeEnd = function(name)
  16121. {
  16122. var time = new Date().getTime();
  16123. if (!this.timeCounters)
  16124. return;
  16125. var key = "KEY"+name.toString();
  16126. var timeCounter = this.timeCounters[key];
  16127. if (timeCounter)
  16128. {
  16129. var diff = time - timeCounter;
  16130. var label = name + ": " + diff + "ms";
  16131. this.info(label);
  16132. delete this.timeCounters[key];
  16133. }
  16134. return diff;
  16135. };
  16136. // These functions are over-ridden by commandLine
  16137. this.evaluated = function(result, context)
  16138. {
  16139. if (FBTrace.DBG_CONSOLE)
  16140. FBTrace.sysout("consoleInjector.FirebugConsoleHandler evalutated default called", result);
  16141. Firebug.Console.log(result, context);
  16142. };
  16143. this.evaluateError = function(result, context)
  16144. {
  16145. Firebug.Console.log(result, context, "errorMessage");
  16146. };
  16147. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16148. function logFormatted(args, className, linkToSource, noThrottle)
  16149. {
  16150. var sourceLink = linkToSource ? getStackLink() : null;
  16151. return Firebug.Console.logFormatted(args, context, className, noThrottle, sourceLink);
  16152. }
  16153. function logAssert(category, args)
  16154. {
  16155. Firebug.Errors.increaseCount(context);
  16156. if (!args || !args.length || args.length == 0)
  16157. var msg = [FBL.$STR("Assertion")];
  16158. else
  16159. var msg = args[0];
  16160. if (Firebug.errorStackTrace)
  16161. {
  16162. var trace = Firebug.errorStackTrace;
  16163. delete Firebug.errorStackTrace;
  16164. if (FBTrace.DBG_CONSOLE)
  16165. FBTrace.sysout("logAssert trace from errorStackTrace", trace);
  16166. }
  16167. else if (msg.stack)
  16168. {
  16169. var trace = parseToStackTrace(msg.stack);
  16170. if (FBTrace.DBG_CONSOLE)
  16171. FBTrace.sysout("logAssert trace from msg.stack", trace);
  16172. }
  16173. else
  16174. {
  16175. var trace = getJSDUserStack();
  16176. if (FBTrace.DBG_CONSOLE)
  16177. FBTrace.sysout("logAssert trace from getJSDUserStack", trace);
  16178. }
  16179. var errorObject = new FBL.ErrorMessage(msg, (msg.fileName?msg.fileName:win.location), (msg.lineNumber?msg.lineNumber:0), "", category, context, trace);
  16180. if (trace && trace.frames && trace.frames[0])
  16181. errorObject.correctWithStackTrace(trace);
  16182. errorObject.resetSource();
  16183. var objects = errorObject;
  16184. if (args.length > 1)
  16185. {
  16186. objects = [errorObject];
  16187. for (var i = 1; i < args.length; i++)
  16188. objects.push(args[i]);
  16189. }
  16190. var row = Firebug.Console.log(objects, context, "errorMessage", null, true); // noThrottle
  16191. row.scrollIntoView();
  16192. }
  16193. function getComponentsStackDump()
  16194. {
  16195. // Starting with our stack, walk back to the user-level code
  16196. var frame = Components.stack;
  16197. var userURL = win.location.href.toString();
  16198. if (FBTrace.DBG_CONSOLE)
  16199. FBTrace.sysout("consoleInjector.getComponentsStackDump initial stack for userURL "+userURL, frame);
  16200. // Drop frames until we get into user code.
  16201. while (frame && FBL.isSystemURL(frame.filename) )
  16202. frame = frame.caller;
  16203. // Drop two more frames, the injected console function and firebugAppendConsole()
  16204. if (frame)
  16205. frame = frame.caller;
  16206. if (frame)
  16207. frame = frame.caller;
  16208. if (FBTrace.DBG_CONSOLE)
  16209. FBTrace.sysout("consoleInjector.getComponentsStackDump final stack for userURL "+userURL, frame);
  16210. return frame;
  16211. }
  16212. function getStackLink()
  16213. {
  16214. // TODO: xxxpedro console2
  16215. return;
  16216. //return FBL.getFrameSourceLink(getComponentsStackDump());
  16217. }
  16218. function getJSDUserStack()
  16219. {
  16220. var trace = FBL.getCurrentStackTrace(context);
  16221. var frames = trace ? trace.frames : null;
  16222. if (frames && (frames.length > 0) )
  16223. {
  16224. var oldest = frames.length - 1; // 6 - 1 = 5
  16225. for (var i = 0; i < frames.length; i++)
  16226. {
  16227. if (frames[oldest - i].href.indexOf("chrome:") == 0) break;
  16228. var fn = frames[oldest - i].fn + "";
  16229. if (fn && (fn.indexOf("_firebugEvalEvent") != -1) ) break; // command line
  16230. }
  16231. FBTrace.sysout("consoleInjector getJSDUserStack: "+frames.length+" oldest: "+oldest+" i: "+i+" i - oldest + 2: "+(i - oldest + 2), trace);
  16232. trace.frames = trace.frames.slice(2 - i); // take the oldest frames, leave 2 behind they are injection code
  16233. return trace;
  16234. }
  16235. else
  16236. return "Firebug failed to get stack trace with any frames";
  16237. }
  16238. }
  16239. // ************************************************************************************************
  16240. // Register console namespace
  16241. FBL.registerConsole = function()
  16242. {
  16243. //TODO: xxxpedro console options override
  16244. //if (Env.Options.overrideConsole)
  16245. var win = Env.browser.window;
  16246. Firebug.Console.injector.install(win);
  16247. };
  16248. registerConsole();
  16249. }});
  16250. /* See license.txt for terms of usage */
  16251. FBL.ns(function() { with (FBL) {
  16252. // ************************************************************************************************
  16253. // ************************************************************************************************
  16254. // Globals
  16255. var commandPrefix = ">>>";
  16256. var reOpenBracket = /[\[\(\{]/;
  16257. var reCloseBracket = /[\]\)\}]/;
  16258. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16259. var commandHistory = [];
  16260. var commandPointer = -1;
  16261. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16262. var isAutoCompleting = null;
  16263. var autoCompletePrefix = null;
  16264. var autoCompleteExpr = null;
  16265. var autoCompleteBuffer = null;
  16266. var autoCompletePosition = null;
  16267. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16268. var fbCommandLine = null;
  16269. var fbLargeCommandLine = null;
  16270. var fbLargeCommandButtons = null;
  16271. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16272. var _completion =
  16273. {
  16274. window:
  16275. [
  16276. "console"
  16277. ],
  16278. document:
  16279. [
  16280. "getElementById",
  16281. "getElementsByTagName"
  16282. ]
  16283. };
  16284. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16285. var _stack = function(command)
  16286. {
  16287. commandHistory.push(command);
  16288. commandPointer = commandHistory.length;
  16289. };
  16290. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16291. // ************************************************************************************************
  16292. // CommandLine
  16293. Firebug.CommandLine = extend(Firebug.Module,
  16294. {
  16295. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16296. element: null,
  16297. isMultiLine: false,
  16298. isActive: false,
  16299. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16300. initialize: function(doc)
  16301. {
  16302. this.clear = bind(this.clear, this);
  16303. this.enter = bind(this.enter, this);
  16304. this.onError = bind(this.onError, this);
  16305. this.onKeyDown = bind(this.onKeyDown, this);
  16306. this.onMultiLineKeyDown = bind(this.onMultiLineKeyDown, this);
  16307. addEvent(Firebug.browser.window, "error", this.onError);
  16308. addEvent(Firebug.chrome.window, "error", this.onError);
  16309. },
  16310. shutdown: function(doc)
  16311. {
  16312. this.deactivate();
  16313. removeEvent(Firebug.browser.window, "error", this.onError);
  16314. removeEvent(Firebug.chrome.window, "error", this.onError);
  16315. },
  16316. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16317. activate: function(multiLine, hideToggleIcon, onRun)
  16318. {
  16319. defineCommandLineAPI();
  16320. if (this.isActive)
  16321. {
  16322. if (this.isMultiLine == multiLine) return;
  16323. this.deactivate();
  16324. }
  16325. fbCommandLine = $("fbCommandLine");
  16326. fbLargeCommandLine = $("fbLargeCommandLine");
  16327. fbLargeCommandButtons = $("fbLargeCommandButtons");
  16328. if (multiLine)
  16329. {
  16330. onRun = onRun || this.enter;
  16331. this.isMultiLine = true;
  16332. this.element = fbLargeCommandLine;
  16333. addEvent(this.element, "keydown", this.onMultiLineKeyDown);
  16334. addEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine);
  16335. this.runButton = new Button({
  16336. element: $("fbCommand_btRun"),
  16337. owner: Firebug.CommandLine,
  16338. onClick: onRun
  16339. });
  16340. this.runButton.initialize();
  16341. this.clearButton = new Button({
  16342. element: $("fbCommand_btClear"),
  16343. owner: Firebug.CommandLine,
  16344. onClick: this.clear
  16345. });
  16346. this.clearButton.initialize();
  16347. }
  16348. else
  16349. {
  16350. this.isMultiLine = false;
  16351. this.element = fbCommandLine;
  16352. if (!fbCommandLine)
  16353. return;
  16354. addEvent(this.element, "keydown", this.onKeyDown);
  16355. }
  16356. //Firebug.Console.log("activate", this.element);
  16357. if (isOpera)
  16358. fixOperaTabKey(this.element);
  16359. if(this.lastValue)
  16360. this.element.value = this.lastValue;
  16361. this.isActive = true;
  16362. },
  16363. deactivate: function()
  16364. {
  16365. if (!this.isActive) return;
  16366. //Firebug.Console.log("deactivate", this.element);
  16367. this.isActive = false;
  16368. this.lastValue = this.element.value;
  16369. if (this.isMultiLine)
  16370. {
  16371. removeEvent(this.element, "keydown", this.onMultiLineKeyDown);
  16372. removeEvent($("fbSmallCommandLineIcon"), "click", Firebug.chrome.hideLargeCommandLine);
  16373. this.runButton.destroy();
  16374. this.clearButton.destroy();
  16375. }
  16376. else
  16377. {
  16378. removeEvent(this.element, "keydown", this.onKeyDown);
  16379. }
  16380. this.element = null
  16381. delete this.element;
  16382. fbCommandLine = null;
  16383. fbLargeCommandLine = null;
  16384. fbLargeCommandButtons = null;
  16385. },
  16386. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16387. focus: function()
  16388. {
  16389. this.element.focus();
  16390. },
  16391. blur: function()
  16392. {
  16393. this.element.blur();
  16394. },
  16395. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16396. clear: function()
  16397. {
  16398. this.element.value = "";
  16399. },
  16400. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16401. evaluate: function(expr)
  16402. {
  16403. // TODO: need to register the API in console.firebug.commandLineAPI
  16404. var api = "Firebug.CommandLine.API"
  16405. var result = Firebug.context.evaluate(expr, "window", api, Firebug.Console.error);
  16406. return result;
  16407. },
  16408. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16409. enter: function()
  16410. {
  16411. var command = this.element.value;
  16412. if (!command) return;
  16413. _stack(command);
  16414. Firebug.Console.log(commandPrefix + " " + stripNewLines(command), Firebug.browser, "command", FirebugReps.Text);
  16415. var result = this.evaluate(command);
  16416. Firebug.Console.log(result);
  16417. },
  16418. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16419. prevCommand: function()
  16420. {
  16421. if (commandPointer > 0 && commandHistory.length > 0)
  16422. this.element.value = commandHistory[--commandPointer];
  16423. },
  16424. nextCommand: function()
  16425. {
  16426. var element = this.element;
  16427. var limit = commandHistory.length -1;
  16428. var i = commandPointer;
  16429. if (i < limit)
  16430. element.value = commandHistory[++commandPointer];
  16431. else if (i == limit)
  16432. {
  16433. ++commandPointer;
  16434. element.value = "";
  16435. }
  16436. },
  16437. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16438. autocomplete: function(reverse)
  16439. {
  16440. var element = this.element;
  16441. var command = element.value;
  16442. var offset = getExpressionOffset(command);
  16443. var valBegin = offset ? command.substr(0, offset) : "";
  16444. var val = command.substr(offset);
  16445. var buffer, obj, objName, commandBegin, result, prefix;
  16446. // if it is the beginning of the completion
  16447. if(!isAutoCompleting)
  16448. {
  16449. // group1 - command begin
  16450. // group2 - base object
  16451. // group3 - property prefix
  16452. var reObj = /(.*[^_$\w\d\.])?((?:[_$\w][_$\w\d]*\.)*)([_$\w][_$\w\d]*)?$/;
  16453. var r = reObj.exec(val);
  16454. // parse command
  16455. if (r[1] || r[2] || r[3])
  16456. {
  16457. commandBegin = r[1] || "";
  16458. objName = r[2] || "";
  16459. prefix = r[3] || "";
  16460. }
  16461. else if (val == "")
  16462. {
  16463. commandBegin = objName = prefix = "";
  16464. } else
  16465. return;
  16466. isAutoCompleting = true;
  16467. // find base object
  16468. if(objName == "")
  16469. obj = window;
  16470. else
  16471. {
  16472. objName = objName.replace(/\.$/, "");
  16473. var n = objName.split(".");
  16474. var target = window, o;
  16475. for (var i=0, ni; ni = n[i]; i++)
  16476. {
  16477. if (o = target[ni])
  16478. target = o;
  16479. else
  16480. {
  16481. target = null;
  16482. break;
  16483. }
  16484. }
  16485. obj = target;
  16486. }
  16487. // map base object
  16488. if(obj)
  16489. {
  16490. autoCompletePrefix = prefix;
  16491. autoCompleteExpr = valBegin + commandBegin + (objName ? objName + "." : "");
  16492. autoCompletePosition = -1;
  16493. buffer = autoCompleteBuffer = isIE ?
  16494. _completion[objName || "window"] || [] : [];
  16495. for(var p in obj)
  16496. buffer.push(p);
  16497. }
  16498. // if it is the continuation of the last completion
  16499. } else
  16500. buffer = autoCompleteBuffer;
  16501. if (buffer)
  16502. {
  16503. prefix = autoCompletePrefix;
  16504. var diff = reverse ? -1 : 1;
  16505. for(var i=autoCompletePosition+diff, l=buffer.length, bi; i>=0 && i<l; i+=diff)
  16506. {
  16507. bi = buffer[i];
  16508. if (bi.indexOf(prefix) == 0)
  16509. {
  16510. autoCompletePosition = i;
  16511. result = bi;
  16512. break;
  16513. }
  16514. }
  16515. }
  16516. if (result)
  16517. element.value = autoCompleteExpr + result;
  16518. },
  16519. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16520. setMultiLine: function(multiLine)
  16521. {
  16522. if (multiLine == this.isMultiLine) return;
  16523. this.activate(multiLine);
  16524. },
  16525. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16526. onError: function(msg, href, lineNo)
  16527. {
  16528. href = href || "";
  16529. var lastSlash = href.lastIndexOf("/");
  16530. var fileName = lastSlash == -1 ? href : href.substr(lastSlash+1);
  16531. var html = [
  16532. '<span class="errorMessage">', msg, '</span>',
  16533. '<div class="objectBox-sourceLink">', fileName, ' (line ', lineNo, ')</div>'
  16534. ];
  16535. // TODO: xxxpedro ajust to Console2
  16536. //Firebug.Console.writeRow(html, "error");
  16537. },
  16538. onKeyDown: function(e)
  16539. {
  16540. e = e || event;
  16541. var code = e.keyCode;
  16542. /*tab, shift, control, alt*/
  16543. if (code != 9 && code != 16 && code != 17 && code != 18)
  16544. {
  16545. isAutoCompleting = false;
  16546. }
  16547. if (code == 13 /* enter */)
  16548. {
  16549. this.enter();
  16550. this.clear();
  16551. }
  16552. else if (code == 27 /* ESC */)
  16553. {
  16554. setTimeout(this.clear, 0);
  16555. }
  16556. else if (code == 38 /* up */)
  16557. {
  16558. this.prevCommand();
  16559. }
  16560. else if (code == 40 /* down */)
  16561. {
  16562. this.nextCommand();
  16563. }
  16564. else if (code == 9 /* tab */)
  16565. {
  16566. this.autocomplete(e.shiftKey);
  16567. }
  16568. else
  16569. return;
  16570. cancelEvent(e, true);
  16571. return false;
  16572. },
  16573. onMultiLineKeyDown: function(e)
  16574. {
  16575. e = e || event;
  16576. var code = e.keyCode;
  16577. if (code == 13 /* enter */ && e.ctrlKey)
  16578. {
  16579. this.enter();
  16580. }
  16581. }
  16582. });
  16583. Firebug.registerModule(Firebug.CommandLine);
  16584. // ************************************************************************************************
  16585. //
  16586. function getExpressionOffset(command)
  16587. {
  16588. // XXXjoe This is kind of a poor-man's JavaScript parser - trying
  16589. // to find the start of the expression that the cursor is inside.
  16590. // Not 100% fool proof, but hey...
  16591. var bracketCount = 0;
  16592. var start = command.length-1;
  16593. for (; start >= 0; --start)
  16594. {
  16595. var c = command[start];
  16596. if ((c == "," || c == ";" || c == " ") && !bracketCount)
  16597. break;
  16598. if (reOpenBracket.test(c))
  16599. {
  16600. if (bracketCount)
  16601. --bracketCount;
  16602. else
  16603. break;
  16604. }
  16605. else if (reCloseBracket.test(c))
  16606. ++bracketCount;
  16607. }
  16608. return start + 1;
  16609. }
  16610. // ************************************************************************************************
  16611. // CommandLine API
  16612. var CommandLineAPI =
  16613. {
  16614. $: function(id)
  16615. {
  16616. return Firebug.browser.document.getElementById(id)
  16617. },
  16618. $$: function(selector, context)
  16619. {
  16620. context = context || Firebug.browser.document;
  16621. return Firebug.Selector ?
  16622. Firebug.Selector(selector, context) :
  16623. Firebug.Console.error("Firebug.Selector module not loaded.");
  16624. },
  16625. $0: null,
  16626. $1: null,
  16627. dir: function(o)
  16628. {
  16629. Firebug.Console.log(o, Firebug.context, "dir", Firebug.DOMPanel.DirTable);
  16630. },
  16631. dirxml: function(o)
  16632. {
  16633. ///if (o instanceof Window)
  16634. if (instanceOf(o, "Window"))
  16635. o = o.document.documentElement;
  16636. ///else if (o instanceof Document)
  16637. else if (instanceOf(o, "Document"))
  16638. o = o.documentElement;
  16639. // TODO: xxxpedro html3
  16640. ///Firebug.Console.log(o, Firebug.context, "dirxml", Firebug.HTMLPanel.SoloElement);
  16641. var div = Firebug.Console.log(o, Firebug.context, "dirxml");
  16642. var html = [];
  16643. Firebug.Reps.appendNode(o, html);
  16644. div.innerHTML = html.join("");
  16645. }
  16646. };
  16647. // ************************************************************************************************
  16648. var defineCommandLineAPI = function defineCommandLineAPI()
  16649. {
  16650. Firebug.CommandLine.API = {};
  16651. for (var m in CommandLineAPI)
  16652. if (!Env.browser.window[m])
  16653. Firebug.CommandLine.API[m] = CommandLineAPI[m];
  16654. var stack = FirebugChrome.htmlSelectionStack;
  16655. if (stack)
  16656. {
  16657. Firebug.CommandLine.API.$0 = stack[0];
  16658. Firebug.CommandLine.API.$1 = stack[1];
  16659. }
  16660. };
  16661. // ************************************************************************************************
  16662. }});
  16663. /* See license.txt for terms of usage */
  16664. FBL.ns(function() { with (FBL) {
  16665. // ************************************************************************************************
  16666. if (Env.Options.disableXHRListener)
  16667. return;
  16668. // ************************************************************************************************
  16669. // XHRSpy
  16670. var XHRSpy = function()
  16671. {
  16672. this.requestHeaders = [];
  16673. this.responseHeaders = [];
  16674. };
  16675. XHRSpy.prototype =
  16676. {
  16677. method: null,
  16678. url: null,
  16679. async: null,
  16680. xhrRequest: null,
  16681. href: null,
  16682. loaded: false,
  16683. logRow: null,
  16684. responseText: null,
  16685. requestHeaders: null,
  16686. responseHeaders: null,
  16687. sourceLink: null, // {href:"file.html", line: 22}
  16688. getURL: function()
  16689. {
  16690. return this.href;
  16691. }
  16692. };
  16693. // ************************************************************************************************
  16694. // XMLHttpRequestWrapper
  16695. var XMLHttpRequestWrapper = function(activeXObject)
  16696. {
  16697. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16698. // XMLHttpRequestWrapper internal variables
  16699. var xhrRequest = typeof activeXObject != "undefined" ?
  16700. activeXObject :
  16701. new _XMLHttpRequest(),
  16702. spy = new XHRSpy(),
  16703. self = this,
  16704. reqType,
  16705. reqUrl,
  16706. reqStartTS;
  16707. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16708. // XMLHttpRequestWrapper internal methods
  16709. var updateSelfPropertiesIgnore = {
  16710. abort: 1,
  16711. channel: 1,
  16712. getAllResponseHeaders: 1,
  16713. getInterface: 1,
  16714. getResponseHeader: 1,
  16715. mozBackgroundRequest: 1,
  16716. multipart: 1,
  16717. onreadystatechange: 1,
  16718. open: 1,
  16719. send: 1,
  16720. setRequestHeader: 1
  16721. };
  16722. var updateSelfProperties = function()
  16723. {
  16724. if (supportsXHRIterator)
  16725. {
  16726. for (var propName in xhrRequest)
  16727. {
  16728. if (propName in updateSelfPropertiesIgnore)
  16729. continue;
  16730. try
  16731. {
  16732. var propValue = xhrRequest[propName];
  16733. if (propValue && !isFunction(propValue))
  16734. self[propName] = propValue;
  16735. }
  16736. catch(E)
  16737. {
  16738. //console.log(propName, E.message);
  16739. }
  16740. }
  16741. }
  16742. else
  16743. {
  16744. // will fail to read these xhrRequest properties if the request is not completed
  16745. if (xhrRequest.readyState == 4)
  16746. {
  16747. self.status = xhrRequest.status;
  16748. self.statusText = xhrRequest.statusText;
  16749. self.responseText = xhrRequest.responseText;
  16750. self.responseXML = xhrRequest.responseXML;
  16751. }
  16752. }
  16753. };
  16754. var updateXHRPropertiesIgnore = {
  16755. channel: 1,
  16756. onreadystatechange: 1,
  16757. readyState: 1,
  16758. responseBody: 1,
  16759. responseText: 1,
  16760. responseXML: 1,
  16761. status: 1,
  16762. statusText: 1,
  16763. upload: 1
  16764. };
  16765. var updateXHRProperties = function()
  16766. {
  16767. for (var propName in self)
  16768. {
  16769. if (propName in updateXHRPropertiesIgnore)
  16770. continue;
  16771. try
  16772. {
  16773. var propValue = self[propName];
  16774. if (propValue && !xhrRequest[propName])
  16775. {
  16776. xhrRequest[propName] = propValue;
  16777. }
  16778. }
  16779. catch(E)
  16780. {
  16781. //console.log(propName, E.message);
  16782. }
  16783. }
  16784. };
  16785. var logXHR = function()
  16786. {
  16787. var row = Firebug.Console.log(spy, null, "spy", Firebug.Spy.XHR);
  16788. if (row)
  16789. {
  16790. setClass(row, "loading");
  16791. spy.logRow = row;
  16792. }
  16793. };
  16794. var finishXHR = function()
  16795. {
  16796. var duration = new Date().getTime() - reqStartTS;
  16797. var success = xhrRequest.status == 200;
  16798. var responseHeadersText = xhrRequest.getAllResponseHeaders();
  16799. var responses = responseHeadersText ? responseHeadersText.split(/[\n\r]/) : [];
  16800. var reHeader = /^(\S+):\s*(.*)/;
  16801. for (var i=0, l=responses.length; i<l; i++)
  16802. {
  16803. var text = responses[i];
  16804. var match = text.match(reHeader);
  16805. if (match)
  16806. {
  16807. var name = match[1];
  16808. var value = match[2];
  16809. // update the spy mimeType property so we can detect when to show
  16810. // custom response viewers (such as HTML, XML or JSON viewer)
  16811. if (name == "Content-Type")
  16812. spy.mimeType = value;
  16813. /*
  16814. if (name == "Last Modified")
  16815. {
  16816. if (!spy.cacheEntry)
  16817. spy.cacheEntry = [];
  16818. spy.cacheEntry.push({
  16819. name: [name],
  16820. value: [value]
  16821. });
  16822. }
  16823. /**/
  16824. spy.responseHeaders.push({
  16825. name: [name],
  16826. value: [value]
  16827. });
  16828. }
  16829. }
  16830. with({
  16831. row: spy.logRow,
  16832. status: xhrRequest.status == 0 ?
  16833. // if xhrRequest.status == 0 then accessing xhrRequest.statusText
  16834. // will cause an error, so we must handle this case (Issue 3504)
  16835. "" : xhrRequest.status + " " + xhrRequest.statusText,
  16836. time: duration,
  16837. success: success
  16838. })
  16839. {
  16840. setTimeout(function(){
  16841. spy.responseText = xhrRequest.responseText;
  16842. // update row information to avoid "ethernal spinning gif" bug in IE
  16843. row = row || spy.logRow;
  16844. // if chrome document is not loaded, there will be no row yet, so just ignore
  16845. if (!row) return;
  16846. // update the XHR representation data
  16847. handleRequestStatus(success, status, time);
  16848. },200);
  16849. }
  16850. spy.loaded = true;
  16851. /*
  16852. // commented because they are being updated by the updateSelfProperties() function
  16853. self.status = xhrRequest.status;
  16854. self.statusText = xhrRequest.statusText;
  16855. self.responseText = xhrRequest.responseText;
  16856. self.responseXML = xhrRequest.responseXML;
  16857. /**/
  16858. updateSelfProperties();
  16859. };
  16860. var handleStateChange = function()
  16861. {
  16862. //Firebug.Console.log(["onreadystatechange", xhrRequest.readyState, xhrRequest.readyState == 4 && xhrRequest.status]);
  16863. self.readyState = xhrRequest.readyState;
  16864. if (xhrRequest.readyState == 4)
  16865. {
  16866. finishXHR();
  16867. xhrRequest.onreadystatechange = function(){};
  16868. }
  16869. //Firebug.Console.log(spy.url + ": " + xhrRequest.readyState);
  16870. self.onreadystatechange();
  16871. };
  16872. // update the XHR representation data
  16873. var handleRequestStatus = function(success, status, time)
  16874. {
  16875. var row = spy.logRow;
  16876. FBL.removeClass(row, "loading");
  16877. if (!success)
  16878. FBL.setClass(row, "error");
  16879. var item = FBL.$$(".spyStatus", row)[0];
  16880. item.innerHTML = status;
  16881. if (time)
  16882. {
  16883. var item = FBL.$$(".spyTime", row)[0];
  16884. item.innerHTML = time + "ms";
  16885. }
  16886. };
  16887. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16888. // XMLHttpRequestWrapper public properties and handlers
  16889. this.readyState = 0;
  16890. this.onreadystatechange = function(){};
  16891. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16892. // XMLHttpRequestWrapper public methods
  16893. this.open = function(method, url, async, user, password)
  16894. {
  16895. //Firebug.Console.log("xhrRequest open");
  16896. updateSelfProperties();
  16897. if (spy.loaded)
  16898. spy = new XHRSpy();
  16899. spy.method = method;
  16900. spy.url = url;
  16901. spy.async = async;
  16902. spy.href = url;
  16903. spy.xhrRequest = xhrRequest;
  16904. spy.urlParams = parseURLParamsArray(url);
  16905. try
  16906. {
  16907. // xhrRequest.open.apply may not be available in IE
  16908. if (supportsApply)
  16909. xhrRequest.open.apply(xhrRequest, arguments);
  16910. else
  16911. xhrRequest.open(method, url, async, user, password);
  16912. }
  16913. catch(e)
  16914. {
  16915. }
  16916. xhrRequest.onreadystatechange = handleStateChange;
  16917. };
  16918. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16919. this.send = function(data)
  16920. {
  16921. //Firebug.Console.log("xhrRequest send");
  16922. spy.data = data;
  16923. reqStartTS = new Date().getTime();
  16924. updateXHRProperties();
  16925. try
  16926. {
  16927. xhrRequest.send(data);
  16928. }
  16929. catch(e)
  16930. {
  16931. // TODO: xxxpedro XHR throws or not?
  16932. //throw e;
  16933. }
  16934. finally
  16935. {
  16936. logXHR();
  16937. if (!spy.async)
  16938. {
  16939. self.readyState = xhrRequest.readyState;
  16940. // sometimes an error happens when calling finishXHR()
  16941. // Issue 3422: Firebug Lite breaks Google Instant Search
  16942. try
  16943. {
  16944. finishXHR();
  16945. }
  16946. catch(E)
  16947. {
  16948. }
  16949. }
  16950. }
  16951. };
  16952. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16953. this.setRequestHeader = function(header, value)
  16954. {
  16955. spy.requestHeaders.push({name: [header], value: [value]});
  16956. return xhrRequest.setRequestHeader(header, value);
  16957. };
  16958. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16959. this.abort = function()
  16960. {
  16961. xhrRequest.abort();
  16962. updateSelfProperties();
  16963. handleRequestStatus(false, "Aborted");
  16964. };
  16965. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16966. this.getResponseHeader = function(header)
  16967. {
  16968. return xhrRequest.getResponseHeader(header);
  16969. };
  16970. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16971. this.getAllResponseHeaders = function()
  16972. {
  16973. return xhrRequest.getAllResponseHeaders();
  16974. };
  16975. /**/
  16976. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  16977. // Clone XHR object
  16978. // xhrRequest.open.apply not available in IE and will throw an error in
  16979. // IE6 by simply reading xhrRequest.open so we must sniff it
  16980. var supportsApply = !isIE6 &&
  16981. xhrRequest &&
  16982. xhrRequest.open &&
  16983. typeof xhrRequest.open.apply != "undefined";
  16984. var numberOfXHRProperties = 0;
  16985. for (var propName in xhrRequest)
  16986. {
  16987. numberOfXHRProperties++;
  16988. if (propName in updateSelfPropertiesIgnore)
  16989. continue;
  16990. try
  16991. {
  16992. var propValue = xhrRequest[propName];
  16993. if (isFunction(propValue))
  16994. {
  16995. if (typeof self[propName] == "undefined")
  16996. {
  16997. this[propName] = (function(name, xhr){
  16998. return supportsApply ?
  16999. // if the browser supports apply
  17000. function()
  17001. {
  17002. return xhr[name].apply(xhr, arguments);
  17003. }
  17004. :
  17005. function(a,b,c,d,e)
  17006. {
  17007. return xhr[name](a,b,c,d,e);
  17008. };
  17009. })(propName, xhrRequest);
  17010. }
  17011. }
  17012. else
  17013. this[propName] = propValue;
  17014. }
  17015. catch(E)
  17016. {
  17017. //console.log(propName, E.message);
  17018. }
  17019. }
  17020. // IE6 does not support for (var prop in XHR)
  17021. var supportsXHRIterator = numberOfXHRProperties > 0;
  17022. /**/
  17023. return this;
  17024. };
  17025. // ************************************************************************************************
  17026. // ActiveXObject Wrapper (IE6 only)
  17027. var _ActiveXObject;
  17028. var isIE6 = /msie 6/i.test(navigator.appVersion);
  17029. if (isIE6)
  17030. {
  17031. _ActiveXObject = window.ActiveXObject;
  17032. var xhrObjects = " MSXML2.XMLHTTP.5.0 MSXML2.XMLHTTP.4.0 MSXML2.XMLHTTP.3.0 MSXML2.XMLHTTP Microsoft.XMLHTTP ";
  17033. window.ActiveXObject = function(name)
  17034. {
  17035. var error = null;
  17036. try
  17037. {
  17038. var activeXObject = new _ActiveXObject(name);
  17039. }
  17040. catch(e)
  17041. {
  17042. error = e;
  17043. }
  17044. finally
  17045. {
  17046. if (!error)
  17047. {
  17048. if (xhrObjects.indexOf(" " + name + " ") != -1)
  17049. return new XMLHttpRequestWrapper(activeXObject);
  17050. else
  17051. return activeXObject;
  17052. }
  17053. else
  17054. throw error.message;
  17055. }
  17056. };
  17057. }
  17058. // ************************************************************************************************
  17059. // Register the XMLHttpRequestWrapper for non-IE6 browsers
  17060. if (!isIE6)
  17061. {
  17062. var _XMLHttpRequest = XMLHttpRequest;
  17063. window.XMLHttpRequest = function()
  17064. {
  17065. return new XMLHttpRequestWrapper();
  17066. };
  17067. }
  17068. // ************************************************************************************************
  17069. }});
  17070. /* See license.txt for terms of usage */
  17071. FBL.ns(function() { with (FBL) {
  17072. // ************************************************************************************************
  17073. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17074. var reIgnore = /about:|javascript:|resource:|chrome:|jar:/;
  17075. var layoutInterval = 300;
  17076. var indentWidth = 18;
  17077. var cacheSession = null;
  17078. var contexts = new Array();
  17079. var panelName = "net";
  17080. var maxQueueRequests = 500;
  17081. //var panelBar1 = $("fbPanelBar1"); // chrome not available at startup
  17082. var activeRequests = [];
  17083. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17084. var mimeExtensionMap =
  17085. {
  17086. "txt": "text/plain",
  17087. "html": "text/html",
  17088. "htm": "text/html",
  17089. "xhtml": "text/html",
  17090. "xml": "text/xml",
  17091. "css": "text/css",
  17092. "js": "application/x-javascript",
  17093. "jss": "application/x-javascript",
  17094. "jpg": "image/jpg",
  17095. "jpeg": "image/jpeg",
  17096. "gif": "image/gif",
  17097. "png": "image/png",
  17098. "bmp": "image/bmp",
  17099. "swf": "application/x-shockwave-flash",
  17100. "flv": "video/x-flv"
  17101. };
  17102. var fileCategories =
  17103. {
  17104. "undefined": 1,
  17105. "html": 1,
  17106. "css": 1,
  17107. "js": 1,
  17108. "xhr": 1,
  17109. "image": 1,
  17110. "flash": 1,
  17111. "txt": 1,
  17112. "bin": 1
  17113. };
  17114. var textFileCategories =
  17115. {
  17116. "txt": 1,
  17117. "html": 1,
  17118. "xhr": 1,
  17119. "css": 1,
  17120. "js": 1
  17121. };
  17122. var binaryFileCategories =
  17123. {
  17124. "bin": 1,
  17125. "flash": 1
  17126. };
  17127. var mimeCategoryMap =
  17128. {
  17129. "text/plain": "txt",
  17130. "application/octet-stream": "bin",
  17131. "text/html": "html",
  17132. "text/xml": "html",
  17133. "text/css": "css",
  17134. "application/x-javascript": "js",
  17135. "text/javascript": "js",
  17136. "application/javascript" : "js",
  17137. "image/jpeg": "image",
  17138. "image/jpg": "image",
  17139. "image/gif": "image",
  17140. "image/png": "image",
  17141. "image/bmp": "image",
  17142. "application/x-shockwave-flash": "flash",
  17143. "video/x-flv": "flash"
  17144. };
  17145. var binaryCategoryMap =
  17146. {
  17147. "image": 1,
  17148. "flash" : 1
  17149. };
  17150. // ************************************************************************************************
  17151. /**
  17152. * @module Represents a module object for the Net panel. This object is derived
  17153. * from <code>Firebug.ActivableModule</code> in order to support activation (enable/disable).
  17154. * This allows to avoid (performance) expensive features if the functionality is not necessary
  17155. * for the user.
  17156. */
  17157. Firebug.NetMonitor = extend(Firebug.ActivableModule,
  17158. {
  17159. dispatchName: "netMonitor",
  17160. clear: function(context)
  17161. {
  17162. // The user pressed a Clear button so, remove content of the panel...
  17163. var panel = context.getPanel(panelName, true);
  17164. if (panel)
  17165. panel.clear();
  17166. },
  17167. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17168. // extends Module
  17169. initialize: function()
  17170. {
  17171. return;
  17172. this.panelName = panelName;
  17173. Firebug.ActivableModule.initialize.apply(this, arguments);
  17174. if (Firebug.TraceModule)
  17175. Firebug.TraceModule.addListener(this.TraceListener);
  17176. // HTTP observer must be registered now (and not in monitorContext, since if a
  17177. // page is opened in a new tab the top document request would be missed otherwise.
  17178. NetHttpObserver.registerObserver();
  17179. NetHttpActivityObserver.registerObserver();
  17180. Firebug.Debugger.addListener(this.DebuggerListener);
  17181. },
  17182. shutdown: function()
  17183. {
  17184. return;
  17185. prefs.removeObserver(Firebug.prefDomain, this, false);
  17186. if (Firebug.TraceModule)
  17187. Firebug.TraceModule.removeListener(this.TraceListener);
  17188. NetHttpObserver.unregisterObserver();
  17189. NetHttpActivityObserver.unregisterObserver();
  17190. Firebug.Debugger.removeListener(this.DebuggerListener);
  17191. }
  17192. });
  17193. /**
  17194. * @domplate Represents a template that is used to reneder detailed info about a request.
  17195. * This template is rendered when a request is expanded.
  17196. */
  17197. Firebug.NetMonitor.NetInfoBody = domplate(Firebug.Rep, new Firebug.Listener(),
  17198. {
  17199. tag:
  17200. DIV({"class": "netInfoBody", _repObject: "$file"},
  17201. TAG("$infoTabs", {file: "$file"}),
  17202. TAG("$infoBodies", {file: "$file"})
  17203. ),
  17204. infoTabs:
  17205. DIV({"class": "netInfoTabs focusRow subFocusRow", "role": "tablist"},
  17206. A({"class": "netInfoParamsTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17207. view: "Params",
  17208. $collapsed: "$file|hideParams"},
  17209. $STR("URLParameters")
  17210. ),
  17211. A({"class": "netInfoHeadersTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17212. view: "Headers"},
  17213. $STR("Headers")
  17214. ),
  17215. A({"class": "netInfoPostTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17216. view: "Post",
  17217. $collapsed: "$file|hidePost"},
  17218. $STR("Post")
  17219. ),
  17220. A({"class": "netInfoPutTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17221. view: "Put",
  17222. $collapsed: "$file|hidePut"},
  17223. $STR("Put")
  17224. ),
  17225. A({"class": "netInfoResponseTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17226. view: "Response",
  17227. $collapsed: "$file|hideResponse"},
  17228. $STR("Response")
  17229. ),
  17230. A({"class": "netInfoCacheTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17231. view: "Cache",
  17232. $collapsed: "$file|hideCache"},
  17233. $STR("Cache")
  17234. ),
  17235. A({"class": "netInfoHtmlTab netInfoTab a11yFocus", onclick: "$onClickTab", "role": "tab",
  17236. view: "Html",
  17237. $collapsed: "$file|hideHtml"},
  17238. $STR("HTML")
  17239. )
  17240. ),
  17241. infoBodies:
  17242. DIV({"class": "netInfoBodies outerFocusRow"},
  17243. TABLE({"class": "netInfoParamsText netInfoText netInfoParamsTable", "role": "tabpanel",
  17244. cellpadding: 0, cellspacing: 0}, TBODY()),
  17245. DIV({"class": "netInfoHeadersText netInfoText", "role": "tabpanel"}),
  17246. DIV({"class": "netInfoPostText netInfoText", "role": "tabpanel"}),
  17247. DIV({"class": "netInfoPutText netInfoText", "role": "tabpanel"}),
  17248. PRE({"class": "netInfoResponseText netInfoText", "role": "tabpanel"}),
  17249. DIV({"class": "netInfoCacheText netInfoText", "role": "tabpanel"},
  17250. TABLE({"class": "netInfoCacheTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17251. TBODY({"role": "list", "aria-label": $STR("Cache")})
  17252. )
  17253. ),
  17254. DIV({"class": "netInfoHtmlText netInfoText", "role": "tabpanel"},
  17255. IFRAME({"class": "netInfoHtmlPreview", "role": "document"})
  17256. )
  17257. ),
  17258. headerDataTag:
  17259. FOR("param", "$headers",
  17260. TR({"role": "listitem"},
  17261. TD({"class": "netInfoParamName", "role": "presentation"},
  17262. TAG("$param|getNameTag", {param: "$param"})
  17263. ),
  17264. TD({"class": "netInfoParamValue", "role": "list", "aria-label": "$param.name"},
  17265. FOR("line", "$param|getParamValueIterator",
  17266. CODE({"class": "focusRow subFocusRow", "role": "listitem"}, "$line")
  17267. )
  17268. )
  17269. )
  17270. ),
  17271. customTab:
  17272. A({"class": "netInfo$tabId\\Tab netInfoTab", onclick: "$onClickTab", view: "$tabId", "role": "tab"},
  17273. "$tabTitle"
  17274. ),
  17275. customBody:
  17276. DIV({"class": "netInfo$tabId\\Text netInfoText", "role": "tabpanel"}),
  17277. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17278. nameTag:
  17279. SPAN("$param|getParamName"),
  17280. nameWithTooltipTag:
  17281. SPAN({title: "$param.name"}, "$param|getParamName"),
  17282. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17283. getNameTag: function(param)
  17284. {
  17285. return (this.getParamName(param) == param.name) ? this.nameTag : this.nameWithTooltipTag;
  17286. },
  17287. getParamName: function(param)
  17288. {
  17289. var limit = 25;
  17290. var name = param.name;
  17291. if (name.length > limit)
  17292. name = name.substr(0, limit) + "...";
  17293. return name;
  17294. },
  17295. getParamTitle: function(param)
  17296. {
  17297. var limit = 25;
  17298. var name = param.name;
  17299. if (name.length > limit)
  17300. return name;
  17301. return "";
  17302. },
  17303. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17304. hideParams: function(file)
  17305. {
  17306. return !file.urlParams || !file.urlParams.length;
  17307. },
  17308. hidePost: function(file)
  17309. {
  17310. return file.method.toUpperCase() != "POST";
  17311. },
  17312. hidePut: function(file)
  17313. {
  17314. return file.method.toUpperCase() != "PUT";
  17315. },
  17316. hideResponse: function(file)
  17317. {
  17318. return false;
  17319. //return file.category in binaryFileCategories;
  17320. },
  17321. hideCache: function(file)
  17322. {
  17323. return true;
  17324. //xxxHonza: I don't see any reason why not to display the cache also info for images.
  17325. return !file.cacheEntry; // || file.category=="image";
  17326. },
  17327. hideHtml: function(file)
  17328. {
  17329. return (file.mimeType != "text/html") && (file.mimeType != "application/xhtml+xml");
  17330. },
  17331. onClickTab: function(event)
  17332. {
  17333. this.selectTab(event.currentTarget || event.srcElement);
  17334. },
  17335. getParamValueIterator: function(param)
  17336. {
  17337. // TODO: xxxpedro console2
  17338. return param.value;
  17339. // This value is inserted into CODE element and so, make sure the HTML isn't escaped (1210).
  17340. // This is why the second parameter is true.
  17341. // The CODE (with style white-space:pre) element preserves whitespaces so they are
  17342. // displayed the same, as they come from the server (1194).
  17343. // In case of a long header values of post parameters the value must be wrapped (2105).
  17344. return wrapText(param.value, true);
  17345. },
  17346. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  17347. appendTab: function(netInfoBox, tabId, tabTitle)
  17348. {
  17349. // Create new tab and body.
  17350. var args = {tabId: tabId, tabTitle: tabTitle};
  17351. ///this.customTab.append(args, netInfoBox.getElementsByClassName("netInfoTabs").item(0));
  17352. ///this.customBody.append(args, netInfoBox.getElementsByClassName("netInfoBodies").item(0));
  17353. this.customTab.append(args, $$(".netInfoTabs", netInfoBox)[0]);
  17354. this.customBody.append(args, $$(".netInfoBodies", netInfoBox)[0]);
  17355. },
  17356. selectTabByName: function(netInfoBox, tabName)
  17357. {
  17358. var tab = getChildByClass(netInfoBox, "netInfoTabs", "netInfo"+tabName+"Tab");
  17359. if (tab)
  17360. this.selectTab(tab);
  17361. },
  17362. selectTab: function(tab)
  17363. {
  17364. var view = tab.getAttribute("view");
  17365. var netInfoBox = getAncestorByClass(tab, "netInfoBody");
  17366. var selectedTab = netInfoBox.selectedTab;
  17367. if (selectedTab)
  17368. {
  17369. //netInfoBox.selectedText.removeAttribute("selected");
  17370. removeClass(netInfoBox.selectedText, "netInfoTextSelected");
  17371. removeClass(selectedTab, "netInfoTabSelected");
  17372. //selectedTab.removeAttribute("selected");
  17373. selectedTab.setAttribute("aria-selected", "false");
  17374. }
  17375. var textBodyName = "netInfo" + view + "Text";
  17376. selectedTab = netInfoBox.selectedTab = tab;
  17377. netInfoBox.selectedText = $$("."+textBodyName, netInfoBox)[0];
  17378. //netInfoBox.selectedText = netInfoBox.getElementsByClassName(textBodyName).item(0);
  17379. //netInfoBox.selectedText.setAttribute("selected", "true");
  17380. setClass(netInfoBox.selectedText, "netInfoTextSelected");
  17381. setClass(selectedTab, "netInfoTabSelected");
  17382. selectedTab.setAttribute("selected", "true");
  17383. selectedTab.setAttribute("aria-selected", "true");
  17384. var file = Firebug.getRepObject(netInfoBox);
  17385. //var context = Firebug.getElementPanel(netInfoBox).context;
  17386. var context = Firebug.chrome;
  17387. this.updateInfo(netInfoBox, file, context);
  17388. },
  17389. updateInfo: function(netInfoBox, file, context)
  17390. {
  17391. if (FBTrace.DBG_NET)
  17392. FBTrace.sysout("net.updateInfo; file", file);
  17393. if (!netInfoBox)
  17394. {
  17395. if (FBTrace.DBG_NET || FBTrace.DBG_ERRORS)
  17396. FBTrace.sysout("net.updateInfo; ERROR netInfo == null " + file.href, file);
  17397. return;
  17398. }
  17399. var tab = netInfoBox.selectedTab;
  17400. if (hasClass(tab, "netInfoParamsTab"))
  17401. {
  17402. if (file.urlParams && !netInfoBox.urlParamsPresented)
  17403. {
  17404. netInfoBox.urlParamsPresented = true;
  17405. this.insertHeaderRows(netInfoBox, file.urlParams, "Params");
  17406. }
  17407. }
  17408. else if (hasClass(tab, "netInfoHeadersTab"))
  17409. {
  17410. var headersText = $$(".netInfoHeadersText", netInfoBox)[0];
  17411. //var headersText = netInfoBox.getElementsByClassName("netInfoHeadersText").item(0);
  17412. if (file.responseHeaders && !netInfoBox.responseHeadersPresented)
  17413. {
  17414. netInfoBox.responseHeadersPresented = true;
  17415. NetInfoHeaders.renderHeaders(headersText, file.responseHeaders, "ResponseHeaders");
  17416. }
  17417. if (file.requestHeaders && !netInfoBox.requestHeadersPresented)
  17418. {
  17419. netInfoBox.requestHeadersPresented = true;
  17420. NetInfoHeaders.renderHeaders(headersText, file.requestHeaders, "RequestHeaders");
  17421. }
  17422. }
  17423. else if (hasClass(tab, "netInfoPostTab"))
  17424. {
  17425. if (!netInfoBox.postPresented)
  17426. {
  17427. netInfoBox.postPresented = true;
  17428. //var postText = netInfoBox.getElementsByClassName("netInfoPostText").item(0);
  17429. var postText = $$(".netInfoPostText", netInfoBox)[0];
  17430. NetInfoPostData.render(context, postText, file);
  17431. }
  17432. }
  17433. else if (hasClass(tab, "netInfoPutTab"))
  17434. {
  17435. if (!netInfoBox.putPresented)
  17436. {
  17437. netInfoBox.putPresented = true;
  17438. //var putText = netInfoBox.getElementsByClassName("netInfoPutText").item(0);
  17439. var putText = $$(".netInfoPutText", netInfoBox)[0];
  17440. NetInfoPostData.render(context, putText, file);
  17441. }
  17442. }
  17443. else if (hasClass(tab, "netInfoResponseTab") && file.loaded && !netInfoBox.responsePresented)
  17444. {
  17445. ///var responseTextBox = netInfoBox.getElementsByClassName("netInfoResponseText").item(0);
  17446. var responseTextBox = $$(".netInfoResponseText", netInfoBox)[0];
  17447. if (file.category == "image")
  17448. {
  17449. netInfoBox.responsePresented = true;
  17450. var responseImage = netInfoBox.ownerDocument.createElement("img");
  17451. responseImage.src = file.href;
  17452. clearNode(responseTextBox);
  17453. responseTextBox.appendChild(responseImage, responseTextBox);
  17454. }
  17455. else ///if (!(binaryCategoryMap.hasOwnProperty(file.category)))
  17456. {
  17457. this.setResponseText(file, netInfoBox, responseTextBox, context);
  17458. }
  17459. }
  17460. else if (hasClass(tab, "netInfoCacheTab") && file.loaded && !netInfoBox.cachePresented)
  17461. {
  17462. var responseTextBox = netInfoBox.getElementsByClassName("netInfoCacheText").item(0);
  17463. if (file.cacheEntry) {
  17464. netInfoBox.cachePresented = true;
  17465. this.insertHeaderRows(netInfoBox, file.cacheEntry, "Cache");
  17466. }
  17467. }
  17468. else if (hasClass(tab, "netInfoHtmlTab") && file.loaded && !netInfoBox.htmlPresented)
  17469. {
  17470. netInfoBox.htmlPresented = true;
  17471. var text = Utils.getResponseText(file, context);
  17472. ///var iframe = netInfoBox.getElementsByClassName("netInfoHtmlPreview").item(0);
  17473. var iframe = $$(".netInfoHtmlPreview", netInfoBox)[0];
  17474. ///iframe.contentWindow.document.body.innerHTML = text;
  17475. // TODO: xxxpedro net - remove scripts
  17476. var reScript = /<script(.|\s)*?\/script>/gi;
  17477. text = text.replace(reScript, "");
  17478. iframe.contentWindow.document.write(text);
  17479. iframe.contentWindow.document.close();
  17480. }
  17481. // Notify listeners about update so, content of custom tabs can be updated.
  17482. dispatch(NetInfoBody.fbListeners, "updateTabBody", [netInfoBox, file, context]);
  17483. },
  17484. setResponseText: function(file, netInfoBox, responseTextBox, context)
  17485. {
  17486. //**********************************************
  17487. //**********************************************
  17488. //**********************************************
  17489. netInfoBox.responsePresented = true;
  17490. // line breaks somehow are different in IE
  17491. // make this only once in the initialization? we don't have net panels and modules yet.
  17492. if (isIE)
  17493. responseTextBox.style.whiteSpace = "nowrap";
  17494. responseTextBox[
  17495. typeof responseTextBox.textContent != "undefined" ?
  17496. "textContent" :
  17497. "innerText"
  17498. ] = file.responseText;
  17499. return;
  17500. //**********************************************
  17501. //**********************************************
  17502. //**********************************************
  17503. // Get response text and make sure it doesn't exceed the max limit.
  17504. var text = Utils.getResponseText(file, context);
  17505. var limit = Firebug.netDisplayedResponseLimit + 15;
  17506. var limitReached = text ? (text.length > limit) : false;
  17507. if (limitReached)
  17508. text = text.substr(0, limit) + "...";
  17509. // Insert the response into the UI.
  17510. if (text)
  17511. insertWrappedText(text, responseTextBox);
  17512. else
  17513. insertWrappedText("", responseTextBox);
  17514. // Append a message informing the user that the response isn't fully displayed.
  17515. if (limitReached)
  17516. {
  17517. var object = {
  17518. text: $STR("net.responseSizeLimitMessage"),
  17519. onClickLink: function() {
  17520. var panel = context.getPanel("net", true);
  17521. panel.openResponseInTab(file);
  17522. }
  17523. };
  17524. Firebug.NetMonitor.ResponseSizeLimit.append(object, responseTextBox);
  17525. }
  17526. netInfoBox.responsePresented = true;
  17527. if (FBTrace.DBG_NET)
  17528. FBTrace.sysout("net.setResponseText; response text updated");
  17529. },
  17530. insertHeaderRows: function(netInfoBox, headers, tableName, rowName)
  17531. {
  17532. if (!headers.length)
  17533. return;
  17534. var headersTable = $$(".netInfo"+tableName+"Table", netInfoBox)[0];
  17535. //var headersTable = netInfoBox.getElementsByClassName("netInfo"+tableName+"Table").item(0);
  17536. var tbody = getChildByClass(headersTable, "netInfo" + rowName + "Body");
  17537. if (!tbody)
  17538. tbody = headersTable.firstChild;
  17539. var titleRow = getChildByClass(tbody, "netInfo" + rowName + "Title");
  17540. this.headerDataTag.insertRows({headers: headers}, titleRow ? titleRow : tbody);
  17541. removeClass(titleRow, "collapsed");
  17542. }
  17543. });
  17544. var NetInfoBody = Firebug.NetMonitor.NetInfoBody;
  17545. // ************************************************************************************************
  17546. /**
  17547. * @domplate Used within the Net panel to display raw source of request and response headers
  17548. * as well as pretty-formatted summary of these headers.
  17549. */
  17550. Firebug.NetMonitor.NetInfoHeaders = domplate(Firebug.Rep, //new Firebug.Listener(),
  17551. {
  17552. tag:
  17553. DIV({"class": "netInfoHeadersTable", "role": "tabpanel"},
  17554. DIV({"class": "netInfoHeadersGroup netInfoResponseHeadersTitle"},
  17555. SPAN($STR("ResponseHeaders")),
  17556. SPAN({"class": "netHeadersViewSource response collapsed", onclick: "$onViewSource",
  17557. _sourceDisplayed: false, _rowName: "ResponseHeaders"},
  17558. $STR("net.headers.view source")
  17559. )
  17560. ),
  17561. TABLE({cellpadding: 0, cellspacing: 0},
  17562. TBODY({"class": "netInfoResponseHeadersBody", "role": "list",
  17563. "aria-label": $STR("ResponseHeaders")})
  17564. ),
  17565. DIV({"class": "netInfoHeadersGroup netInfoRequestHeadersTitle"},
  17566. SPAN($STR("RequestHeaders")),
  17567. SPAN({"class": "netHeadersViewSource request collapsed", onclick: "$onViewSource",
  17568. _sourceDisplayed: false, _rowName: "RequestHeaders"},
  17569. $STR("net.headers.view source")
  17570. )
  17571. ),
  17572. TABLE({cellpadding: 0, cellspacing: 0},
  17573. TBODY({"class": "netInfoRequestHeadersBody", "role": "list",
  17574. "aria-label": $STR("RequestHeaders")})
  17575. )
  17576. ),
  17577. sourceTag:
  17578. TR({"role": "presentation"},
  17579. TD({colspan: 2, "role": "presentation"},
  17580. PRE({"class": "source"})
  17581. )
  17582. ),
  17583. onViewSource: function(event)
  17584. {
  17585. var target = event.target;
  17586. var requestHeaders = (target.rowName == "RequestHeaders");
  17587. var netInfoBox = getAncestorByClass(target, "netInfoBody");
  17588. var file = netInfoBox.repObject;
  17589. if (target.sourceDisplayed)
  17590. {
  17591. var headers = requestHeaders ? file.requestHeaders : file.responseHeaders;
  17592. this.insertHeaderRows(netInfoBox, headers, target.rowName);
  17593. target.innerHTML = $STR("net.headers.view source");
  17594. }
  17595. else
  17596. {
  17597. var source = requestHeaders ? file.requestHeadersText : file.responseHeadersText;
  17598. this.insertSource(netInfoBox, source, target.rowName);
  17599. target.innerHTML = $STR("net.headers.pretty print");
  17600. }
  17601. target.sourceDisplayed = !target.sourceDisplayed;
  17602. cancelEvent(event);
  17603. },
  17604. insertSource: function(netInfoBox, source, rowName)
  17605. {
  17606. // This breaks copy to clipboard.
  17607. //if (source)
  17608. // source = source.replace(/\r\n/gm, "<span style='color:lightgray'>\\r\\n</span>\r\n");
  17609. ///var tbody = netInfoBox.getElementsByClassName("netInfo" + rowName + "Body").item(0);
  17610. var tbody = $$(".netInfo" + rowName + "Body", netInfoBox)[0];
  17611. var node = this.sourceTag.replace({}, tbody);
  17612. ///var sourceNode = node.getElementsByClassName("source").item(0);
  17613. var sourceNode = $$(".source", node)[0];
  17614. sourceNode.innerHTML = source;
  17615. },
  17616. insertHeaderRows: function(netInfoBox, headers, rowName)
  17617. {
  17618. var headersTable = $$(".netInfoHeadersTable", netInfoBox)[0];
  17619. var tbody = $$(".netInfo" + rowName + "Body", headersTable)[0];
  17620. //var headersTable = netInfoBox.getElementsByClassName("netInfoHeadersTable").item(0);
  17621. //var tbody = headersTable.getElementsByClassName("netInfo" + rowName + "Body").item(0);
  17622. clearNode(tbody);
  17623. if (!headers.length)
  17624. return;
  17625. NetInfoBody.headerDataTag.insertRows({headers: headers}, tbody);
  17626. var titleRow = getChildByClass(headersTable, "netInfo" + rowName + "Title");
  17627. removeClass(titleRow, "collapsed");
  17628. },
  17629. init: function(parent)
  17630. {
  17631. var rootNode = this.tag.append({}, parent);
  17632. var netInfoBox = getAncestorByClass(parent, "netInfoBody");
  17633. var file = netInfoBox.repObject;
  17634. var viewSource;
  17635. viewSource = $$(".request", rootNode)[0];
  17636. //viewSource = rootNode.getElementsByClassName("netHeadersViewSource request").item(0);
  17637. if (file.requestHeadersText)
  17638. removeClass(viewSource, "collapsed");
  17639. viewSource = $$(".response", rootNode)[0];
  17640. //viewSource = rootNode.getElementsByClassName("netHeadersViewSource response").item(0);
  17641. if (file.responseHeadersText)
  17642. removeClass(viewSource, "collapsed");
  17643. },
  17644. renderHeaders: function(parent, headers, rowName)
  17645. {
  17646. if (!parent.firstChild)
  17647. this.init(parent);
  17648. this.insertHeaderRows(parent, headers, rowName);
  17649. }
  17650. });
  17651. var NetInfoHeaders = Firebug.NetMonitor.NetInfoHeaders;
  17652. // ************************************************************************************************
  17653. /**
  17654. * @domplate Represents posted data within request info (the info, which is visible when
  17655. * a request entry is expanded. This template renders content of the Post tab.
  17656. */
  17657. Firebug.NetMonitor.NetInfoPostData = domplate(Firebug.Rep, /*new Firebug.Listener(),*/
  17658. {
  17659. // application/x-www-form-urlencoded
  17660. paramsTable:
  17661. TABLE({"class": "netInfoPostParamsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17662. TBODY({"role": "list", "aria-label": $STR("net.label.Parameters")},
  17663. TR({"class": "netInfoPostParamsTitle", "role": "presentation"},
  17664. TD({colspan: 3, "role": "presentation"},
  17665. DIV({"class": "netInfoPostParams"},
  17666. $STR("net.label.Parameters"),
  17667. SPAN({"class": "netInfoPostContentType"},
  17668. "application/x-www-form-urlencoded"
  17669. )
  17670. )
  17671. )
  17672. )
  17673. )
  17674. ),
  17675. // multipart/form-data
  17676. partsTable:
  17677. TABLE({"class": "netInfoPostPartsTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17678. TBODY({"role": "list", "aria-label": $STR("net.label.Parts")},
  17679. TR({"class": "netInfoPostPartsTitle", "role": "presentation"},
  17680. TD({colspan: 2, "role":"presentation" },
  17681. DIV({"class": "netInfoPostParams"},
  17682. $STR("net.label.Parts"),
  17683. SPAN({"class": "netInfoPostContentType"},
  17684. "multipart/form-data"
  17685. )
  17686. )
  17687. )
  17688. )
  17689. )
  17690. ),
  17691. // application/json
  17692. jsonTable:
  17693. TABLE({"class": "netInfoPostJSONTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17694. ///TBODY({"role": "list", "aria-label": $STR("jsonviewer.tab.JSON")},
  17695. TBODY({"role": "list", "aria-label": $STR("JSON")},
  17696. TR({"class": "netInfoPostJSONTitle", "role": "presentation"},
  17697. TD({"role": "presentation" },
  17698. DIV({"class": "netInfoPostParams"},
  17699. ///$STR("jsonviewer.tab.JSON")
  17700. $STR("JSON")
  17701. )
  17702. )
  17703. ),
  17704. TR(
  17705. TD({"class": "netInfoPostJSONBody"})
  17706. )
  17707. )
  17708. ),
  17709. // application/xml
  17710. xmlTable:
  17711. TABLE({"class": "netInfoPostXMLTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17712. TBODY({"role": "list", "aria-label": $STR("xmlviewer.tab.XML")},
  17713. TR({"class": "netInfoPostXMLTitle", "role": "presentation"},
  17714. TD({"role": "presentation" },
  17715. DIV({"class": "netInfoPostParams"},
  17716. $STR("xmlviewer.tab.XML")
  17717. )
  17718. )
  17719. ),
  17720. TR(
  17721. TD({"class": "netInfoPostXMLBody"})
  17722. )
  17723. )
  17724. ),
  17725. sourceTable:
  17726. TABLE({"class": "netInfoPostSourceTable", cellpadding: 0, cellspacing: 0, "role": "presentation"},
  17727. TBODY({"role": "list", "aria-label": $STR("net.label.Source")},
  17728. TR({"class": "netInfoPostSourceTitle", "role": "presentation"},
  17729. TD({colspan: 2, "role": "presentation"},
  17730. DIV({"class": "netInfoPostSource"},
  17731. $STR("net.label.Source")
  17732. )
  17733. )
  17734. )
  17735. )
  17736. ),
  17737. sourceBodyTag:
  17738. TR({"role": "presentation"},
  17739. TD({colspan: 2, "role": "presentation"},
  17740. FOR("line", "$param|getParamValueIterator",
  17741. CODE({"class":"focusRow subFocusRow" , "role": "listitem"},"$line")
  17742. )
  17743. )
  17744. ),
  17745. getParamValueIterator: function(param)
  17746. {
  17747. return NetInfoBody.getParamValueIterator(param);
  17748. },
  17749. render: function(context, parentNode, file)
  17750. {
  17751. //debugger;
  17752. var spy = getAncestorByClass(parentNode, "spyHead");
  17753. var spyObject = spy.repObject;
  17754. var data = spyObject.data;
  17755. ///var contentType = Utils.findHeader(file.requestHeaders, "content-type");
  17756. var contentType = file.mimeType;
  17757. ///var text = Utils.getPostText(file, context, true);
  17758. ///if (text == undefined)
  17759. /// return;
  17760. ///if (Utils.isURLEncodedRequest(file, context))
  17761. // fake Utils.isURLEncodedRequest identification
  17762. if (contentType && contentType == "application/x-www-form-urlencoded" ||
  17763. data && data.indexOf("=") != -1)
  17764. {
  17765. ///var lines = text.split("\n");
  17766. ///var params = parseURLEncodedText(lines[lines.length-1]);
  17767. var params = parseURLEncodedTextArray(data);
  17768. if (params)
  17769. this.insertParameters(parentNode, params);
  17770. }
  17771. ///if (Utils.isMultiPartRequest(file, context))
  17772. ///{
  17773. /// var data = this.parseMultiPartText(file, context);
  17774. /// if (data)
  17775. /// this.insertParts(parentNode, data);
  17776. ///}
  17777. // moved to the top
  17778. ///var contentType = Utils.findHeader(file.requestHeaders, "content-type");
  17779. ///if (Firebug.JSONViewerModel.isJSON(contentType))
  17780. var jsonData = {
  17781. responseText: data
  17782. };
  17783. if (Firebug.JSONViewerModel.isJSON(contentType, data))
  17784. ///this.insertJSON(parentNode, file, context);
  17785. this.insertJSON(parentNode, jsonData, context);
  17786. ///if (Firebug.XMLViewerModel.isXML(contentType))
  17787. /// this.insertXML(parentNode, file, context);
  17788. ///var postText = Utils.getPostText(file, context);
  17789. ///postText = Utils.formatPostText(postText);
  17790. var postText = data;
  17791. if (postText)
  17792. this.insertSource(parentNode, postText);
  17793. },
  17794. insertParameters: function(parentNode, params)
  17795. {
  17796. if (!params || !params.length)
  17797. return;
  17798. var paramTable = this.paramsTable.append({object:{}}, parentNode);
  17799. var row = $$(".netInfoPostParamsTitle", paramTable)[0];
  17800. //var paramTable = this.paramsTable.append(null, parentNode);
  17801. //var row = paramTable.getElementsByClassName("netInfoPostParamsTitle").item(0);
  17802. var tbody = paramTable.getElementsByTagName("tbody")[0];
  17803. NetInfoBody.headerDataTag.insertRows({headers: params}, row);
  17804. },
  17805. insertParts: function(parentNode, data)
  17806. {
  17807. if (!data.params || !data.params.length)
  17808. return;
  17809. var partsTable = this.partsTable.append({object:{}}, parentNode);
  17810. var row = $$(".netInfoPostPartsTitle", paramTable)[0];
  17811. //var partsTable = this.partsTable.append(null, parentNode);
  17812. //var row = partsTable.getElementsByClassName("netInfoPostPartsTitle").item(0);
  17813. NetInfoBody.headerDataTag.insertRows({headers: data.params}, row);
  17814. },
  17815. insertJSON: function(parentNode, file, context)
  17816. {
  17817. ///var text = Utils.getPostText(file, context);
  17818. var text = file.responseText;
  17819. ///var data = parseJSONString(text, "http://" + file.request.originalURI.host);
  17820. var data = parseJSONString(text);
  17821. if (!data)
  17822. return;
  17823. ///var jsonTable = this.jsonTable.append(null, parentNode);
  17824. var jsonTable = this.jsonTable.append({}, parentNode);
  17825. ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostJSONBody").item(0);
  17826. var jsonBody = $$(".netInfoPostJSONBody", jsonTable)[0];
  17827. if (!this.toggles)
  17828. this.toggles = {};
  17829. Firebug.DOMPanel.DirTable.tag.replace(
  17830. {object: data, toggles: this.toggles}, jsonBody);
  17831. },
  17832. insertXML: function(parentNode, file, context)
  17833. {
  17834. var text = Utils.getPostText(file, context);
  17835. var jsonTable = this.xmlTable.append(null, parentNode);
  17836. ///var jsonBody = jsonTable.getElementsByClassName("netInfoPostXMLBody").item(0);
  17837. var jsonBody = $$(".netInfoPostXMLBody", jsonTable)[0];
  17838. Firebug.XMLViewerModel.insertXML(jsonBody, text);
  17839. },
  17840. insertSource: function(parentNode, text)
  17841. {
  17842. var sourceTable = this.sourceTable.append({object:{}}, parentNode);
  17843. var row = $$(".netInfoPostSourceTitle", sourceTable)[0];
  17844. //var sourceTable = this.sourceTable.append(null, parentNode);
  17845. //var row = sourceTable.getElementsByClassName("netInfoPostSourceTitle").item(0);
  17846. var param = {value: [text]};
  17847. this.sourceBodyTag.insertRows({param: param}, row);
  17848. },
  17849. parseMultiPartText: function(file, context)
  17850. {
  17851. var text = Utils.getPostText(file, context);
  17852. if (text == undefined)
  17853. return null;
  17854. FBTrace.sysout("net.parseMultiPartText; boundary: ", text);
  17855. var boundary = text.match(/\s*boundary=\s*(.*)/)[1];
  17856. var divider = "\r\n\r\n";
  17857. var bodyStart = text.indexOf(divider);
  17858. var body = text.substr(bodyStart + divider.length);
  17859. var postData = {};
  17860. postData.mimeType = "multipart/form-data";
  17861. postData.params = [];
  17862. var parts = body.split("--" + boundary);
  17863. for (var i=0; i<parts.length; i++)
  17864. {
  17865. var part = parts[i].split(divider);
  17866. if (part.length != 2)
  17867. continue;
  17868. var m = part[0].match(/\s*name=\"(.*)\"(;|$)/);
  17869. postData.params.push({
  17870. name: (m && m.length > 1) ? m[1] : "",
  17871. value: trim(part[1])
  17872. });
  17873. }
  17874. return postData;
  17875. }
  17876. });
  17877. var NetInfoPostData = Firebug.NetMonitor.NetInfoPostData;
  17878. // ************************************************************************************************
  17879. // TODO: xxxpedro net i18n
  17880. var $STRP = function(a){return a;};
  17881. Firebug.NetMonitor.NetLimit = domplate(Firebug.Rep,
  17882. {
  17883. collapsed: true,
  17884. tableTag:
  17885. DIV(
  17886. TABLE({width: "100%", cellpadding: 0, cellspacing: 0},
  17887. TBODY()
  17888. )
  17889. ),
  17890. limitTag:
  17891. TR({"class": "netRow netLimitRow", $collapsed: "$isCollapsed"},
  17892. TD({"class": "netCol netLimitCol", colspan: 6},
  17893. TABLE({cellpadding: 0, cellspacing: 0},
  17894. TBODY(
  17895. TR(
  17896. TD(
  17897. SPAN({"class": "netLimitLabel"},
  17898. $STRP("plural.Limit_Exceeded", [0])
  17899. )
  17900. ),
  17901. TD({style: "width:100%"}),
  17902. TD(
  17903. BUTTON({"class": "netLimitButton", title: "$limitPrefsTitle",
  17904. onclick: "$onPreferences"},
  17905. $STR("LimitPrefs")
  17906. )
  17907. ),
  17908. TD("&nbsp;")
  17909. )
  17910. )
  17911. )
  17912. )
  17913. ),
  17914. isCollapsed: function()
  17915. {
  17916. return this.collapsed;
  17917. },
  17918. onPreferences: function(event)
  17919. {
  17920. openNewTab("about:config");
  17921. },
  17922. updateCounter: function(row)
  17923. {
  17924. removeClass(row, "collapsed");
  17925. // Update info within the limit row.
  17926. var limitLabel = row.getElementsByClassName("netLimitLabel").item(0);
  17927. limitLabel.firstChild.nodeValue = $STRP("plural.Limit_Exceeded", [row.limitInfo.totalCount]);
  17928. },
  17929. createTable: function(parent, limitInfo)
  17930. {
  17931. var table = this.tableTag.replace({}, parent);
  17932. var row = this.createRow(table.firstChild.firstChild, limitInfo);
  17933. return [table, row];
  17934. },
  17935. createRow: function(parent, limitInfo)
  17936. {
  17937. var row = this.limitTag.insertRows(limitInfo, parent, this)[0];
  17938. row.limitInfo = limitInfo;
  17939. return row;
  17940. },
  17941. // nsIPrefObserver
  17942. observe: function(subject, topic, data)
  17943. {
  17944. // We're observing preferences only.
  17945. if (topic != "nsPref:changed")
  17946. return;
  17947. if (data.indexOf("net.logLimit") != -1)
  17948. this.updateMaxLimit();
  17949. },
  17950. updateMaxLimit: function()
  17951. {
  17952. var value = Firebug.getPref(Firebug.prefDomain, "net.logLimit");
  17953. maxQueueRequests = value ? value : maxQueueRequests;
  17954. }
  17955. });
  17956. var NetLimit = Firebug.NetMonitor.NetLimit;
  17957. // ************************************************************************************************
  17958. Firebug.NetMonitor.ResponseSizeLimit = domplate(Firebug.Rep,
  17959. {
  17960. tag:
  17961. DIV({"class": "netInfoResponseSizeLimit"},
  17962. SPAN("$object.beforeLink"),
  17963. A({"class": "objectLink", onclick: "$onClickLink"},
  17964. "$object.linkText"
  17965. ),
  17966. SPAN("$object.afterLink")
  17967. ),
  17968. reLink: /^(.*)<a>(.*)<\/a>(.*$)/,
  17969. append: function(obj, parent)
  17970. {
  17971. var m = obj.text.match(this.reLink);
  17972. return this.tag.append({onClickLink: obj.onClickLink,
  17973. object: {
  17974. beforeLink: m[1],
  17975. linkText: m[2],
  17976. afterLink: m[3]
  17977. }}, parent, this);
  17978. }
  17979. });
  17980. // ************************************************************************************************
  17981. // ************************************************************************************************
  17982. Firebug.NetMonitor.Utils =
  17983. {
  17984. findHeader: function(headers, name)
  17985. {
  17986. if (!headers)
  17987. return null;
  17988. name = name.toLowerCase();
  17989. for (var i = 0; i < headers.length; ++i)
  17990. {
  17991. var headerName = headers[i].name.toLowerCase();
  17992. if (headerName == name)
  17993. return headers[i].value;
  17994. }
  17995. },
  17996. formatPostText: function(text)
  17997. {
  17998. if (text instanceof XMLDocument)
  17999. return getElementXML(text.documentElement);
  18000. else
  18001. return text;
  18002. },
  18003. getPostText: function(file, context, noLimit)
  18004. {
  18005. if (!file.postText)
  18006. {
  18007. file.postText = readPostTextFromRequest(file.request, context);
  18008. if (!file.postText && context)
  18009. file.postText = readPostTextFromPage(file.href, context);
  18010. }
  18011. if (!file.postText)
  18012. return file.postText;
  18013. var limit = Firebug.netDisplayedPostBodyLimit;
  18014. if (file.postText.length > limit && !noLimit)
  18015. {
  18016. return cropString(file.postText, limit,
  18017. "\n\n... " + $STR("net.postDataSizeLimitMessage") + " ...\n\n");
  18018. }
  18019. return file.postText;
  18020. },
  18021. getResponseText: function(file, context)
  18022. {
  18023. // The response can be also empty string so, check agains "undefined".
  18024. return (typeof(file.responseText) != "undefined")? file.responseText :
  18025. context.sourceCache.loadText(file.href, file.method, file);
  18026. },
  18027. isURLEncodedRequest: function(file, context)
  18028. {
  18029. var text = Utils.getPostText(file, context);
  18030. if (text && text.toLowerCase().indexOf("content-type: application/x-www-form-urlencoded") == 0)
  18031. return true;
  18032. // The header value doesn't have to be always exactly "application/x-www-form-urlencoded",
  18033. // there can be even charset specified. So, use indexOf rather than just "==".
  18034. var headerValue = Utils.findHeader(file.requestHeaders, "content-type");
  18035. if (headerValue && headerValue.indexOf("application/x-www-form-urlencoded") == 0)
  18036. return true;
  18037. return false;
  18038. },
  18039. isMultiPartRequest: function(file, context)
  18040. {
  18041. var text = Utils.getPostText(file, context);
  18042. if (text && text.toLowerCase().indexOf("content-type: multipart/form-data") == 0)
  18043. return true;
  18044. return false;
  18045. },
  18046. getMimeType: function(mimeType, uri)
  18047. {
  18048. if (!mimeType || !(mimeCategoryMap.hasOwnProperty(mimeType)))
  18049. {
  18050. var ext = getFileExtension(uri);
  18051. if (!ext)
  18052. return mimeType;
  18053. else
  18054. {
  18055. var extMimeType = mimeExtensionMap[ext.toLowerCase()];
  18056. return extMimeType ? extMimeType : mimeType;
  18057. }
  18058. }
  18059. else
  18060. return mimeType;
  18061. },
  18062. getDateFromSeconds: function(s)
  18063. {
  18064. var d = new Date();
  18065. d.setTime(s*1000);
  18066. return d;
  18067. },
  18068. getHttpHeaders: function(request, file)
  18069. {
  18070. try
  18071. {
  18072. var http = QI(request, Ci.nsIHttpChannel);
  18073. file.status = request.responseStatus;
  18074. // xxxHonza: is there any problem to do this in requestedFile method?
  18075. file.method = http.requestMethod;
  18076. file.urlParams = parseURLParams(file.href);
  18077. file.mimeType = Utils.getMimeType(request.contentType, request.name);
  18078. if (!file.responseHeaders && Firebug.collectHttpHeaders)
  18079. {
  18080. var requestHeaders = [], responseHeaders = [];
  18081. http.visitRequestHeaders({
  18082. visitHeader: function(name, value)
  18083. {
  18084. requestHeaders.push({name: name, value: value});
  18085. }
  18086. });
  18087. http.visitResponseHeaders({
  18088. visitHeader: function(name, value)
  18089. {
  18090. responseHeaders.push({name: name, value: value});
  18091. }
  18092. });
  18093. file.requestHeaders = requestHeaders;
  18094. file.responseHeaders = responseHeaders;
  18095. }
  18096. }
  18097. catch (exc)
  18098. {
  18099. // An exception can be throwed e.g. when the request is aborted and
  18100. // request.responseStatus is accessed.
  18101. if (FBTrace.DBG_ERRORS)
  18102. FBTrace.sysout("net.getHttpHeaders FAILS " + file.href, exc);
  18103. }
  18104. },
  18105. isXHR: function(request)
  18106. {
  18107. try
  18108. {
  18109. var callbacks = request.notificationCallbacks;
  18110. var xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null;
  18111. if (FBTrace.DBG_NET)
  18112. FBTrace.sysout("net.isXHR; " + (xhrRequest != null) + ", " + safeGetName(request));
  18113. return (xhrRequest != null);
  18114. }
  18115. catch (exc)
  18116. {
  18117. }
  18118. return false;
  18119. },
  18120. getFileCategory: function(file)
  18121. {
  18122. if (file.category)
  18123. {
  18124. if (FBTrace.DBG_NET)
  18125. FBTrace.sysout("net.getFileCategory; current: " + file.category + " for: " + file.href, file);
  18126. return file.category;
  18127. }
  18128. if (file.isXHR)
  18129. {
  18130. if (FBTrace.DBG_NET)
  18131. FBTrace.sysout("net.getFileCategory; XHR for: " + file.href, file);
  18132. return file.category = "xhr";
  18133. }
  18134. if (!file.mimeType)
  18135. {
  18136. var ext = getFileExtension(file.href);
  18137. if (ext)
  18138. file.mimeType = mimeExtensionMap[ext.toLowerCase()];
  18139. }
  18140. /*if (FBTrace.DBG_NET)
  18141. FBTrace.sysout("net.getFileCategory; " + mimeCategoryMap[file.mimeType] +
  18142. ", mimeType: " + file.mimeType + " for: " + file.href, file);*/
  18143. if (!file.mimeType)
  18144. return "";
  18145. // Solve cases when charset is also specified, eg "text/html; charset=UTF-8".
  18146. var mimeType = file.mimeType;
  18147. if (mimeType)
  18148. mimeType = mimeType.split(";")[0];
  18149. return (file.category = mimeCategoryMap[mimeType]);
  18150. }
  18151. };
  18152. var Utils = Firebug.NetMonitor.Utils;
  18153. // ************************************************************************************************
  18154. //Firebug.registerRep(Firebug.NetMonitor.NetRequestTable);
  18155. //Firebug.registerActivableModule(Firebug.NetMonitor);
  18156. //Firebug.registerPanel(NetPanel);
  18157. Firebug.registerModule(Firebug.NetMonitor);
  18158. //Firebug.registerRep(Firebug.NetMonitor.BreakpointRep);
  18159. // ************************************************************************************************
  18160. }});
  18161. /* See license.txt for terms of usage */
  18162. FBL.ns(function() { with (FBL) {
  18163. // ************************************************************************************************
  18164. // Constants
  18165. //const Cc = Components.classes;
  18166. //const Ci = Components.interfaces;
  18167. // List of contexts with XHR spy attached.
  18168. var contexts = [];
  18169. // ************************************************************************************************
  18170. // Spy Module
  18171. /**
  18172. * @module Represents a XHR Spy module. The main purpose of the XHR Spy feature is to monitor
  18173. * XHR activity of the current page and create appropriate log into the Console panel.
  18174. * This feature can be controlled by an option <i>Show XMLHttpRequests</i> (from within the
  18175. * console panel).
  18176. *
  18177. * The module is responsible for attaching/detaching a HTTP Observers when Firebug is
  18178. * activated/deactivated for a site.
  18179. */
  18180. Firebug.Spy = extend(Firebug.Module,
  18181. /** @lends Firebug.Spy */
  18182. {
  18183. dispatchName: "spy",
  18184. initialize: function()
  18185. {
  18186. if (Firebug.TraceModule)
  18187. Firebug.TraceModule.addListener(this.TraceListener);
  18188. Firebug.Module.initialize.apply(this, arguments);
  18189. },
  18190. shutdown: function()
  18191. {
  18192. Firebug.Module.shutdown.apply(this, arguments);
  18193. if (Firebug.TraceModule)
  18194. Firebug.TraceModule.removeListener(this.TraceListener);
  18195. },
  18196. initContext: function(context)
  18197. {
  18198. context.spies = [];
  18199. if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled())
  18200. this.attachObserver(context, context.window);
  18201. if (FBTrace.DBG_SPY)
  18202. FBTrace.sysout("spy.initContext " + contexts.length + " ", context.getName());
  18203. },
  18204. destroyContext: function(context)
  18205. {
  18206. // For any spies that are in progress, remove our listeners so that they don't leak
  18207. this.detachObserver(context, null);
  18208. if (FBTrace.DBG_SPY && context.spies.length)
  18209. FBTrace.sysout("spy.destroyContext; ERROR There are leaking Spies ("
  18210. + context.spies.length + ") " + context.getName());
  18211. delete context.spies;
  18212. if (FBTrace.DBG_SPY)
  18213. FBTrace.sysout("spy.destroyContext " + contexts.length + " ", context.getName());
  18214. },
  18215. watchWindow: function(context, win)
  18216. {
  18217. if (Firebug.showXMLHttpRequests && Firebug.Console.isAlwaysEnabled())
  18218. this.attachObserver(context, win);
  18219. },
  18220. unwatchWindow: function(context, win)
  18221. {
  18222. try
  18223. {
  18224. // This make sure that the existing context is properly removed from "contexts" array.
  18225. this.detachObserver(context, win);
  18226. }
  18227. catch (ex)
  18228. {
  18229. // Get exceptions here sometimes, so let's just ignore them
  18230. // since the window is going away anyhow
  18231. ERROR(ex);
  18232. }
  18233. },
  18234. updateOption: function(name, value)
  18235. {
  18236. // XXXjjb Honza, if Console.isEnabled(context) false, then this can't be called,
  18237. // but somehow seems not correct
  18238. if (name == "showXMLHttpRequests")
  18239. {
  18240. var tach = value ? this.attachObserver : this.detachObserver;
  18241. for (var i = 0; i < TabWatcher.contexts.length; ++i)
  18242. {
  18243. var context = TabWatcher.contexts[i];
  18244. iterateWindows(context.window, function(win)
  18245. {
  18246. tach.apply(this, [context, win]);
  18247. });
  18248. }
  18249. }
  18250. },
  18251. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18252. // Attaching Spy to XHR requests.
  18253. /**
  18254. * Returns false if Spy should not be attached to XHRs executed by the specified window.
  18255. */
  18256. skipSpy: function(win)
  18257. {
  18258. if (!win)
  18259. return true;
  18260. // Don't attach spy to chrome.
  18261. var uri = safeGetWindowLocation(win);
  18262. if (uri && (uri.indexOf("about:") == 0 || uri.indexOf("chrome:") == 0))
  18263. return true;
  18264. },
  18265. attachObserver: function(context, win)
  18266. {
  18267. if (Firebug.Spy.skipSpy(win))
  18268. return;
  18269. for (var i=0; i<contexts.length; ++i)
  18270. {
  18271. if ((contexts[i].context == context) && (contexts[i].win == win))
  18272. return;
  18273. }
  18274. // Register HTTP observers only once.
  18275. if (contexts.length == 0)
  18276. {
  18277. httpObserver.addObserver(SpyHttpObserver, "firebug-http-event", false);
  18278. SpyHttpActivityObserver.registerObserver();
  18279. }
  18280. contexts.push({context: context, win: win});
  18281. if (FBTrace.DBG_SPY)
  18282. FBTrace.sysout("spy.attachObserver (HTTP) " + contexts.length + " ", context.getName());
  18283. },
  18284. detachObserver: function(context, win)
  18285. {
  18286. for (var i=0; i<contexts.length; ++i)
  18287. {
  18288. if (contexts[i].context == context)
  18289. {
  18290. if (win && (contexts[i].win != win))
  18291. continue;
  18292. contexts.splice(i, 1);
  18293. // If no context is using spy, remvove the (only one) HTTP observer.
  18294. if (contexts.length == 0)
  18295. {
  18296. httpObserver.removeObserver(SpyHttpObserver, "firebug-http-event");
  18297. SpyHttpActivityObserver.unregisterObserver();
  18298. }
  18299. if (FBTrace.DBG_SPY)
  18300. FBTrace.sysout("spy.detachObserver (HTTP) " + contexts.length + " ",
  18301. context.getName());
  18302. return;
  18303. }
  18304. }
  18305. },
  18306. /**
  18307. * Return XHR object that is associated with specified request <i>nsIHttpChannel</i>.
  18308. * Returns null if the request doesn't represent XHR.
  18309. */
  18310. getXHR: function(request)
  18311. {
  18312. // Does also query-interface for nsIHttpChannel.
  18313. if (!(request instanceof Ci.nsIHttpChannel))
  18314. return null;
  18315. try
  18316. {
  18317. var callbacks = request.notificationCallbacks;
  18318. return (callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null);
  18319. }
  18320. catch (exc)
  18321. {
  18322. if (exc.name == "NS_NOINTERFACE")
  18323. {
  18324. if (FBTrace.DBG_SPY)
  18325. FBTrace.sysout("spy.getXHR; Request is not nsIXMLHttpRequest: " +
  18326. safeGetRequestName(request));
  18327. }
  18328. }
  18329. return null;
  18330. }
  18331. });
  18332. // ************************************************************************************************
  18333. /*
  18334. function getSpyForXHR(request, xhrRequest, context, noCreate)
  18335. {
  18336. var spy = null;
  18337. // Iterate all existing spy objects in this context and look for one that is
  18338. // already created for this request.
  18339. var length = context.spies.length;
  18340. for (var i=0; i<length; i++)
  18341. {
  18342. spy = context.spies[i];
  18343. if (spy.request == request)
  18344. return spy;
  18345. }
  18346. if (noCreate)
  18347. return null;
  18348. spy = new Firebug.Spy.XMLHttpRequestSpy(request, xhrRequest, context);
  18349. context.spies.push(spy);
  18350. var name = request.URI.asciiSpec;
  18351. var origName = request.originalURI.asciiSpec;
  18352. // Attach spy only to the original request. Notice that there can be more network requests
  18353. // made by the same XHR if redirects are involved.
  18354. if (name == origName)
  18355. spy.attach();
  18356. if (FBTrace.DBG_SPY)
  18357. FBTrace.sysout("spy.getSpyForXHR; New spy object created (" +
  18358. (name == origName ? "new XHR" : "redirected XHR") + ") for: " + name, spy);
  18359. return spy;
  18360. }
  18361. /**/
  18362. // ************************************************************************************************
  18363. /**
  18364. * @class This class represents a Spy object that is attached to XHR. This object
  18365. * registers various listeners into the XHR in order to monitor various events fired
  18366. * during the request process (onLoad, onAbort, etc.)
  18367. */
  18368. /*
  18369. Firebug.Spy.XMLHttpRequestSpy = function(request, xhrRequest, context)
  18370. {
  18371. this.request = request;
  18372. this.xhrRequest = xhrRequest;
  18373. this.context = context;
  18374. this.responseText = "";
  18375. // For compatibility with the Net templates.
  18376. this.isXHR = true;
  18377. // Support for activity-observer
  18378. this.transactionStarted = false;
  18379. this.transactionClosed = false;
  18380. };
  18381. /**/
  18382. //Firebug.Spy.XMLHttpRequestSpy.prototype =
  18383. /** @lends Firebug.Spy.XMLHttpRequestSpy */
  18384. /*
  18385. {
  18386. attach: function()
  18387. {
  18388. var spy = this;
  18389. this.onReadyStateChange = function(event) { onHTTPSpyReadyStateChange(spy, event); };
  18390. this.onLoad = function() { onHTTPSpyLoad(spy); };
  18391. this.onError = function() { onHTTPSpyError(spy); };
  18392. this.onAbort = function() { onHTTPSpyAbort(spy); };
  18393. // xxxHonza: #502959 is still failing on Fx 3.5
  18394. // Use activity distributor to identify 3.6
  18395. if (SpyHttpActivityObserver.getActivityDistributor())
  18396. {
  18397. this.onreadystatechange = this.xhrRequest.onreadystatechange;
  18398. this.xhrRequest.onreadystatechange = this.onReadyStateChange;
  18399. }
  18400. this.xhrRequest.addEventListener("load", this.onLoad, false);
  18401. this.xhrRequest.addEventListener("error", this.onError, false);
  18402. this.xhrRequest.addEventListener("abort", this.onAbort, false);
  18403. // xxxHonza: should be removed from FB 3.6
  18404. if (!SpyHttpActivityObserver.getActivityDistributor())
  18405. this.context.sourceCache.addListener(this);
  18406. },
  18407. detach: function()
  18408. {
  18409. // Bubble out if already detached.
  18410. if (!this.onLoad)
  18411. return;
  18412. // If the activity distributor is available, let's detach it when the XHR
  18413. // transaction is closed. Since, in case of multipart XHRs the onLoad method
  18414. // (readyState == 4) can be called mutliple times.
  18415. // Keep in mind:
  18416. // 1) It can happen that that the TRANSACTION_CLOSE event comes before
  18417. // the onLoad (if the XHR is made as part of the page load) so, detach if
  18418. // it's already closed.
  18419. // 2) In case of immediate cache responses, the transaction doesn't have to
  18420. // be started at all (or the activity observer is no available in Firefox 3.5).
  18421. // So, also detach in this case.
  18422. if (this.transactionStarted && !this.transactionClosed)
  18423. return;
  18424. if (FBTrace.DBG_SPY)
  18425. FBTrace.sysout("spy.detach; " + this.href);
  18426. // Remove itself from the list of active spies.
  18427. remove(this.context.spies, this);
  18428. if (this.onreadystatechange)
  18429. this.xhrRequest.onreadystatechange = this.onreadystatechange;
  18430. try { this.xhrRequest.removeEventListener("load", this.onLoad, false); } catch (e) {}
  18431. try { this.xhrRequest.removeEventListener("error", this.onError, false); } catch (e) {}
  18432. try { this.xhrRequest.removeEventListener("abort", this.onAbort, false); } catch (e) {}
  18433. this.onreadystatechange = null;
  18434. this.onLoad = null;
  18435. this.onError = null;
  18436. this.onAbort = null;
  18437. // xxxHonza: shouuld be removed from FB 1.6
  18438. if (!SpyHttpActivityObserver.getActivityDistributor())
  18439. this.context.sourceCache.removeListener(this);
  18440. },
  18441. getURL: function()
  18442. {
  18443. return this.xhrRequest.channel ? this.xhrRequest.channel.name : this.href;
  18444. },
  18445. // Cache listener
  18446. onStopRequest: function(context, request, responseText)
  18447. {
  18448. if (!responseText)
  18449. return;
  18450. if (request == this.request)
  18451. this.responseText = responseText;
  18452. },
  18453. };
  18454. /**/
  18455. // ************************************************************************************************
  18456. /*
  18457. function onHTTPSpyReadyStateChange(spy, event)
  18458. {
  18459. if (FBTrace.DBG_SPY)
  18460. FBTrace.sysout("spy.onHTTPSpyReadyStateChange " + spy.xhrRequest.readyState +
  18461. " (multipart: " + spy.xhrRequest.multipart + ")");
  18462. // Remember just in case spy is detached (readyState == 4).
  18463. var originalHandler = spy.onreadystatechange;
  18464. // Force response text to be updated in the UI (in case the console entry
  18465. // has been already expanded and the response tab selected).
  18466. if (spy.logRow && spy.xhrRequest.readyState >= 3)
  18467. {
  18468. var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
  18469. if (netInfoBox)
  18470. {
  18471. netInfoBox.htmlPresented = false;
  18472. netInfoBox.responsePresented = false;
  18473. }
  18474. }
  18475. // If the request is loading update the end time.
  18476. if (spy.xhrRequest.readyState == 3)
  18477. {
  18478. spy.responseTime = spy.endTime - spy.sendTime;
  18479. updateTime(spy);
  18480. }
  18481. // Request loaded. Get all the info from the request now, just in case the
  18482. // XHR would be aborted in the original onReadyStateChange handler.
  18483. if (spy.xhrRequest.readyState == 4)
  18484. {
  18485. // Cumulate response so, multipart response content is properly displayed.
  18486. if (SpyHttpActivityObserver.getActivityDistributor())
  18487. spy.responseText += spy.xhrRequest.responseText;
  18488. else
  18489. {
  18490. // xxxHonza: remove from FB 1.6
  18491. if (!spy.responseText)
  18492. spy.responseText = spy.xhrRequest.responseText;
  18493. }
  18494. // The XHR is loaded now (used also by the activity observer).
  18495. spy.loaded = true;
  18496. // Update UI.
  18497. updateHttpSpyInfo(spy);
  18498. // Notify Net pane about a request beeing loaded.
  18499. // xxxHonza: I don't think this is necessary.
  18500. var netProgress = spy.context.netProgress;
  18501. if (netProgress)
  18502. netProgress.post(netProgress.stopFile, [spy.request, spy.endTime, spy.postText, spy.responseText]);
  18503. // Notify registered listeners about finish of the XHR.
  18504. dispatch(Firebug.Spy.fbListeners, "onLoad", [spy.context, spy]);
  18505. }
  18506. // Pass the event to the original page handler.
  18507. callPageHandler(spy, event, originalHandler);
  18508. }
  18509. function onHTTPSpyLoad(spy)
  18510. {
  18511. if (FBTrace.DBG_SPY)
  18512. FBTrace.sysout("spy.onHTTPSpyLoad: " + spy.href, spy);
  18513. // Detach must be done in onLoad (not in onreadystatechange) otherwise
  18514. // onAbort would not be handled.
  18515. spy.detach();
  18516. // xxxHonza: Still needed for Fx 3.5 (#502959)
  18517. if (!SpyHttpActivityObserver.getActivityDistributor())
  18518. onHTTPSpyReadyStateChange(spy, null);
  18519. }
  18520. function onHTTPSpyError(spy)
  18521. {
  18522. if (FBTrace.DBG_SPY)
  18523. FBTrace.sysout("spy.onHTTPSpyError; " + spy.href, spy);
  18524. spy.detach();
  18525. spy.loaded = true;
  18526. if (spy.logRow)
  18527. {
  18528. removeClass(spy.logRow, "loading");
  18529. setClass(spy.logRow, "error");
  18530. }
  18531. }
  18532. function onHTTPSpyAbort(spy)
  18533. {
  18534. if (FBTrace.DBG_SPY)
  18535. FBTrace.sysout("spy.onHTTPSpyAbort: " + spy.href, spy);
  18536. spy.detach();
  18537. spy.loaded = true;
  18538. if (spy.logRow)
  18539. {
  18540. removeClass(spy.logRow, "loading");
  18541. setClass(spy.logRow, "error");
  18542. }
  18543. spy.statusText = "Aborted";
  18544. updateLogRow(spy);
  18545. // Notify Net pane about a request beeing aborted.
  18546. // xxxHonza: the net panel shoud find out this itself.
  18547. var netProgress = spy.context.netProgress;
  18548. if (netProgress)
  18549. netProgress.post(netProgress.abortFile, [spy.request, spy.endTime, spy.postText, spy.responseText]);
  18550. }
  18551. /**/
  18552. // ************************************************************************************************
  18553. /**
  18554. * @domplate Represents a template for XHRs logged in the Console panel. The body of the
  18555. * log (displayed when expanded) is rendered using {@link Firebug.NetMonitor.NetInfoBody}.
  18556. */
  18557. Firebug.Spy.XHR = domplate(Firebug.Rep,
  18558. /** @lends Firebug.Spy.XHR */
  18559. {
  18560. tag:
  18561. DIV({"class": "spyHead", _repObject: "$object"},
  18562. TABLE({"class": "spyHeadTable focusRow outerFocusRow", cellpadding: 0, cellspacing: 0,
  18563. "role": "listitem", "aria-expanded": "false"},
  18564. TBODY({"role": "presentation"},
  18565. TR({"class": "spyRow"},
  18566. TD({"class": "spyTitleCol spyCol", onclick: "$onToggleBody"},
  18567. DIV({"class": "spyTitle"},
  18568. "$object|getCaption"
  18569. ),
  18570. DIV({"class": "spyFullTitle spyTitle"},
  18571. "$object|getFullUri"
  18572. )
  18573. ),
  18574. TD({"class": "spyCol"},
  18575. DIV({"class": "spyStatus"}, "$object|getStatus")
  18576. ),
  18577. TD({"class": "spyCol"},
  18578. SPAN({"class": "spyIcon"})
  18579. ),
  18580. TD({"class": "spyCol"},
  18581. SPAN({"class": "spyTime"})
  18582. ),
  18583. TD({"class": "spyCol"},
  18584. TAG(FirebugReps.SourceLink.tag, {object: "$object.sourceLink"})
  18585. )
  18586. )
  18587. )
  18588. )
  18589. ),
  18590. getCaption: function(spy)
  18591. {
  18592. return spy.method.toUpperCase() + " " + cropString(spy.getURL(), 100);
  18593. },
  18594. getFullUri: function(spy)
  18595. {
  18596. return spy.method.toUpperCase() + " " + spy.getURL();
  18597. },
  18598. getStatus: function(spy)
  18599. {
  18600. var text = "";
  18601. if (spy.statusCode)
  18602. text += spy.statusCode + " ";
  18603. if (spy.statusText)
  18604. return text += spy.statusText;
  18605. return text;
  18606. },
  18607. onToggleBody: function(event)
  18608. {
  18609. var target = event.currentTarget || event.srcElement;
  18610. var logRow = getAncestorByClass(target, "logRow-spy");
  18611. if (isLeftClick(event))
  18612. {
  18613. toggleClass(logRow, "opened");
  18614. var spy = getChildByClass(logRow, "spyHead").repObject;
  18615. var spyHeadTable = getAncestorByClass(target, "spyHeadTable");
  18616. if (hasClass(logRow, "opened"))
  18617. {
  18618. updateHttpSpyInfo(spy, logRow);
  18619. if (spyHeadTable)
  18620. spyHeadTable.setAttribute('aria-expanded', 'true');
  18621. }
  18622. else
  18623. {
  18624. //var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
  18625. //dispatch(Firebug.NetMonitor.NetInfoBody.fbListeners, "destroyTabBody", [netInfoBox, spy]);
  18626. //if (spyHeadTable)
  18627. // spyHeadTable.setAttribute('aria-expanded', 'false');
  18628. }
  18629. }
  18630. },
  18631. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18632. copyURL: function(spy)
  18633. {
  18634. copyToClipboard(spy.getURL());
  18635. },
  18636. copyParams: function(spy)
  18637. {
  18638. var text = spy.postText;
  18639. if (!text)
  18640. return;
  18641. var url = reEncodeURL(spy, text, true);
  18642. copyToClipboard(url);
  18643. },
  18644. copyResponse: function(spy)
  18645. {
  18646. copyToClipboard(spy.responseText);
  18647. },
  18648. openInTab: function(spy)
  18649. {
  18650. openNewTab(spy.getURL(), spy.postText);
  18651. },
  18652. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  18653. supportsObject: function(object)
  18654. {
  18655. // TODO: xxxpedro spy xhr
  18656. return false;
  18657. return object instanceof Firebug.Spy.XMLHttpRequestSpy;
  18658. },
  18659. browseObject: function(spy, context)
  18660. {
  18661. var url = spy.getURL();
  18662. openNewTab(url);
  18663. return true;
  18664. },
  18665. getRealObject: function(spy, context)
  18666. {
  18667. return spy.xhrRequest;
  18668. },
  18669. getContextMenuItems: function(spy)
  18670. {
  18671. var items = [
  18672. {label: "CopyLocation", command: bindFixed(this.copyURL, this, spy) }
  18673. ];
  18674. if (spy.postText)
  18675. {
  18676. items.push(
  18677. {label: "CopyLocationParameters", command: bindFixed(this.copyParams, this, spy) }
  18678. );
  18679. }
  18680. items.push(
  18681. {label: "CopyResponse", command: bindFixed(this.copyResponse, this, spy) },
  18682. "-",
  18683. {label: "OpenInTab", command: bindFixed(this.openInTab, this, spy) }
  18684. );
  18685. return items;
  18686. }
  18687. });
  18688. // ************************************************************************************************
  18689. function updateTime(spy)
  18690. {
  18691. var timeBox = spy.logRow.getElementsByClassName("spyTime").item(0);
  18692. if (spy.responseTime)
  18693. timeBox.textContent = " " + formatTime(spy.responseTime);
  18694. }
  18695. function updateLogRow(spy)
  18696. {
  18697. updateTime(spy);
  18698. var statusBox = spy.logRow.getElementsByClassName("spyStatus").item(0);
  18699. statusBox.textContent = Firebug.Spy.XHR.getStatus(spy);
  18700. removeClass(spy.logRow, "loading");
  18701. setClass(spy.logRow, "loaded");
  18702. try
  18703. {
  18704. var errorRange = Math.floor(spy.xhrRequest.status/100);
  18705. if (errorRange == 4 || errorRange == 5)
  18706. setClass(spy.logRow, "error");
  18707. }
  18708. catch (exc)
  18709. {
  18710. }
  18711. }
  18712. var updateHttpSpyInfo = function updateHttpSpyInfo(spy, logRow)
  18713. {
  18714. if (!spy.logRow && logRow)
  18715. spy.logRow = logRow;
  18716. if (!spy.logRow || !hasClass(spy.logRow, "opened"))
  18717. return;
  18718. if (!spy.params)
  18719. //spy.params = parseURLParams(spy.href+"");
  18720. spy.params = parseURLParams(spy.href+"");
  18721. if (!spy.requestHeaders)
  18722. spy.requestHeaders = getRequestHeaders(spy);
  18723. if (!spy.responseHeaders && spy.loaded)
  18724. spy.responseHeaders = getResponseHeaders(spy);
  18725. var template = Firebug.NetMonitor.NetInfoBody;
  18726. var netInfoBox = getChildByClass(spy.logRow, "spyHead", "netInfoBody");
  18727. if (!netInfoBox)
  18728. {
  18729. var head = getChildByClass(spy.logRow, "spyHead");
  18730. netInfoBox = template.tag.append({"file": spy}, head);
  18731. dispatch(template.fbListeners, "initTabBody", [netInfoBox, spy]);
  18732. template.selectTabByName(netInfoBox, "Response");
  18733. }
  18734. else
  18735. {
  18736. template.updateInfo(netInfoBox, spy, spy.context);
  18737. }
  18738. };
  18739. // ************************************************************************************************
  18740. function getRequestHeaders(spy)
  18741. {
  18742. var headers = [];
  18743. var channel = spy.xhrRequest.channel;
  18744. if (channel instanceof Ci.nsIHttpChannel)
  18745. {
  18746. channel.visitRequestHeaders({
  18747. visitHeader: function(name, value)
  18748. {
  18749. headers.push({name: name, value: value});
  18750. }
  18751. });
  18752. }
  18753. return headers;
  18754. }
  18755. function getResponseHeaders(spy)
  18756. {
  18757. var headers = [];
  18758. try
  18759. {
  18760. var channel = spy.xhrRequest.channel;
  18761. if (channel instanceof Ci.nsIHttpChannel)
  18762. {
  18763. channel.visitResponseHeaders({
  18764. visitHeader: function(name, value)
  18765. {
  18766. headers.push({name: name, value: value});
  18767. }
  18768. });
  18769. }
  18770. }
  18771. catch (exc)
  18772. {
  18773. if (FBTrace.DBG_SPY || FBTrace.DBG_ERRORS)
  18774. FBTrace.sysout("spy.getResponseHeaders; EXCEPTION " +
  18775. safeGetRequestName(spy.request), exc);
  18776. }
  18777. return headers;
  18778. }
  18779. // ************************************************************************************************
  18780. // Registration
  18781. Firebug.registerModule(Firebug.Spy);
  18782. //Firebug.registerRep(Firebug.Spy.XHR);
  18783. // ************************************************************************************************
  18784. }});
  18785. /* See license.txt for terms of usage */
  18786. FBL.ns(function() { with (FBL) {
  18787. // ************************************************************************************************
  18788. // List of JSON content types.
  18789. var contentTypes =
  18790. {
  18791. "text/plain": 1,
  18792. "text/javascript": 1,
  18793. "text/x-javascript": 1,
  18794. "text/json": 1,
  18795. "text/x-json": 1,
  18796. "application/json": 1,
  18797. "application/x-json": 1,
  18798. "application/javascript": 1,
  18799. "application/x-javascript": 1,
  18800. "application/json-rpc": 1
  18801. };
  18802. // ************************************************************************************************
  18803. // Model implementation
  18804. Firebug.JSONViewerModel = extend(Firebug.Module,
  18805. {
  18806. dispatchName: "jsonViewer",
  18807. initialize: function()
  18808. {
  18809. Firebug.NetMonitor.NetInfoBody.addListener(this);
  18810. // Used by Firebug.DOMPanel.DirTable domplate.
  18811. this.toggles = {};
  18812. },
  18813. shutdown: function()
  18814. {
  18815. Firebug.NetMonitor.NetInfoBody.removeListener(this);
  18816. },
  18817. initTabBody: function(infoBox, file)
  18818. {
  18819. if (FBTrace.DBG_JSONVIEWER)
  18820. FBTrace.sysout("jsonviewer.initTabBody", infoBox);
  18821. // Let listeners to parse the JSON.
  18822. dispatch(this.fbListeners, "onParseJSON", [file]);
  18823. // The JSON is still no there, try to parse most common cases.
  18824. if (!file.jsonObject)
  18825. {
  18826. ///if (this.isJSON(safeGetContentType(file.request), file.responseText))
  18827. if (this.isJSON(file.mimeType, file.responseText))
  18828. file.jsonObject = this.parseJSON(file);
  18829. }
  18830. // The jsonObject is created so, the JSON tab can be displayed.
  18831. if (file.jsonObject && hasProperties(file.jsonObject))
  18832. {
  18833. Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "JSON",
  18834. ///$STR("jsonviewer.tab.JSON"));
  18835. $STR("JSON"));
  18836. if (FBTrace.DBG_JSONVIEWER)
  18837. FBTrace.sysout("jsonviewer.initTabBody; JSON object available " +
  18838. (typeof(file.jsonObject) != "undefined"), file.jsonObject);
  18839. }
  18840. },
  18841. isJSON: function(contentType, data)
  18842. {
  18843. // Workaround for JSON responses without proper content type
  18844. // Let's consider all responses starting with "{" as JSON. In the worst
  18845. // case there will be an exception when parsing. This means that no-JSON
  18846. // responses (and post data) (with "{") can be parsed unnecessarily,
  18847. // which represents a little overhead, but this happens only if the request
  18848. // is actually expanded by the user in the UI (Net & Console panels).
  18849. ///var responseText = data ? trimLeft(data) : null;
  18850. ///if (responseText && responseText.indexOf("{") == 0)
  18851. /// return true;
  18852. var responseText = data ? trim(data) : null;
  18853. if (responseText && responseText.indexOf("{") == 0)
  18854. return true;
  18855. if (!contentType)
  18856. return false;
  18857. contentType = contentType.split(";")[0];
  18858. contentType = trim(contentType);
  18859. return contentTypes[contentType];
  18860. },
  18861. // Update listener for TabView
  18862. updateTabBody: function(infoBox, file, context)
  18863. {
  18864. var tab = infoBox.selectedTab;
  18865. ///var tabBody = infoBox.getElementsByClassName("netInfoJSONText").item(0);
  18866. var tabBody = $$(".netInfoJSONText", infoBox)[0];
  18867. if (!hasClass(tab, "netInfoJSONTab") || tabBody.updated)
  18868. return;
  18869. tabBody.updated = true;
  18870. if (file.jsonObject) {
  18871. Firebug.DOMPanel.DirTable.tag.replace(
  18872. {object: file.jsonObject, toggles: this.toggles}, tabBody);
  18873. }
  18874. },
  18875. parseJSON: function(file)
  18876. {
  18877. var jsonString = new String(file.responseText);
  18878. ///return parseJSONString(jsonString, "http://" + file.request.originalURI.host);
  18879. return parseJSONString(jsonString);
  18880. }
  18881. });
  18882. // ************************************************************************************************
  18883. // Registration
  18884. Firebug.registerModule(Firebug.JSONViewerModel);
  18885. // ************************************************************************************************
  18886. }});
  18887. /* See license.txt for terms of usage */
  18888. FBL.ns(function() { with (FBL) {
  18889. // ************************************************************************************************
  18890. // Constants
  18891. // List of XML related content types.
  18892. var xmlContentTypes =
  18893. [
  18894. "text/xml",
  18895. "application/xml",
  18896. "application/xhtml+xml",
  18897. "application/rss+xml",
  18898. "application/atom+xml",,
  18899. "application/vnd.mozilla.maybe.feed",
  18900. "application/rdf+xml",
  18901. "application/vnd.mozilla.xul+xml"
  18902. ];
  18903. // ************************************************************************************************
  18904. // Model implementation
  18905. /**
  18906. * @module Implements viewer for XML based network responses. In order to create a new
  18907. * tab wihin network request detail, a listener is registered into
  18908. * <code>Firebug.NetMonitor.NetInfoBody</code> object.
  18909. */
  18910. Firebug.XMLViewerModel = extend(Firebug.Module,
  18911. {
  18912. dispatchName: "xmlViewer",
  18913. initialize: function()
  18914. {
  18915. ///Firebug.ActivableModule.initialize.apply(this, arguments);
  18916. Firebug.Module.initialize.apply(this, arguments);
  18917. Firebug.NetMonitor.NetInfoBody.addListener(this);
  18918. },
  18919. shutdown: function()
  18920. {
  18921. ///Firebug.ActivableModule.shutdown.apply(this, arguments);
  18922. Firebug.Module.shutdown.apply(this, arguments);
  18923. Firebug.NetMonitor.NetInfoBody.removeListener(this);
  18924. },
  18925. /**
  18926. * Check response's content-type and if it's a XML, create a new tab with XML preview.
  18927. */
  18928. initTabBody: function(infoBox, file)
  18929. {
  18930. if (FBTrace.DBG_XMLVIEWER)
  18931. FBTrace.sysout("xmlviewer.initTabBody", infoBox);
  18932. // If the response is XML let's display a pretty preview.
  18933. ///if (this.isXML(safeGetContentType(file.request)))
  18934. if (this.isXML(file.mimeType, file.responseText))
  18935. {
  18936. Firebug.NetMonitor.NetInfoBody.appendTab(infoBox, "XML",
  18937. ///$STR("xmlviewer.tab.XML"));
  18938. $STR("XML"));
  18939. if (FBTrace.DBG_XMLVIEWER)
  18940. FBTrace.sysout("xmlviewer.initTabBody; XML response available");
  18941. }
  18942. },
  18943. isXML: function(contentType)
  18944. {
  18945. if (!contentType)
  18946. return false;
  18947. // Look if the response is XML based.
  18948. for (var i=0; i<xmlContentTypes.length; i++)
  18949. {
  18950. if (contentType.indexOf(xmlContentTypes[i]) == 0)
  18951. return true;
  18952. }
  18953. return false;
  18954. },
  18955. /**
  18956. * Parse XML response and render pretty printed preview.
  18957. */
  18958. updateTabBody: function(infoBox, file, context)
  18959. {
  18960. var tab = infoBox.selectedTab;
  18961. ///var tabBody = infoBox.getElementsByClassName("netInfoXMLText").item(0);
  18962. var tabBody = $$(".netInfoXMLText", infoBox)[0];
  18963. if (!hasClass(tab, "netInfoXMLTab") || tabBody.updated)
  18964. return;
  18965. tabBody.updated = true;
  18966. this.insertXML(tabBody, Firebug.NetMonitor.Utils.getResponseText(file, context));
  18967. },
  18968. insertXML: function(parentNode, text)
  18969. {
  18970. var xmlText = text.replace(/^\s*<?.+?>\s*/, "");
  18971. var div = parentNode.ownerDocument.createElement("div");
  18972. div.innerHTML = xmlText;
  18973. var root = div.getElementsByTagName("*")[0];
  18974. /***
  18975. var parser = CCIN("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
  18976. var doc = parser.parseFromString(text, "text/xml");
  18977. var root = doc.documentElement;
  18978. // Error handling
  18979. var nsURI = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
  18980. if (root.namespaceURI == nsURI && root.nodeName == "parsererror")
  18981. {
  18982. this.ParseError.tag.replace({error: {
  18983. message: root.firstChild.nodeValue,
  18984. source: root.lastChild.textContent
  18985. }}, parentNode);
  18986. return;
  18987. }
  18988. /**/
  18989. if (FBTrace.DBG_XMLVIEWER)
  18990. FBTrace.sysout("xmlviewer.updateTabBody; XML response parsed", doc);
  18991. // Override getHidden in these templates. The parsed XML documen is
  18992. // hidden, but we want to display it using 'visible' styling.
  18993. /*
  18994. var templates = [
  18995. Firebug.HTMLPanel.CompleteElement,
  18996. Firebug.HTMLPanel.Element,
  18997. Firebug.HTMLPanel.TextElement,
  18998. Firebug.HTMLPanel.EmptyElement,
  18999. Firebug.HTMLPanel.XEmptyElement,
  19000. ];
  19001. var originals = [];
  19002. for (var i=0; i<templates.length; i++)
  19003. {
  19004. originals[i] = templates[i].getHidden;
  19005. templates[i].getHidden = function() {
  19006. return "";
  19007. }
  19008. }
  19009. /**/
  19010. // Generate XML preview.
  19011. ///Firebug.HTMLPanel.CompleteElement.tag.replace({object: doc.documentElement}, parentNode);
  19012. // TODO: xxxpedro html3
  19013. ///Firebug.HTMLPanel.CompleteElement.tag.replace({object: root}, parentNode);
  19014. var html = [];
  19015. Firebug.Reps.appendNode(root, html);
  19016. parentNode.innerHTML = html.join("");
  19017. /*
  19018. for (var i=0; i<originals.length; i++)
  19019. templates[i].getHidden = originals[i];/**/
  19020. }
  19021. });
  19022. // ************************************************************************************************
  19023. // Domplate
  19024. /**
  19025. * @domplate Represents a template for displaying XML parser errors. Used by
  19026. * <code>Firebug.XMLViewerModel</code>.
  19027. */
  19028. Firebug.XMLViewerModel.ParseError = domplate(Firebug.Rep,
  19029. {
  19030. tag:
  19031. DIV({"class": "xmlInfoError"},
  19032. DIV({"class": "xmlInfoErrorMsg"}, "$error.message"),
  19033. PRE({"class": "xmlInfoErrorSource"}, "$error|getSource")
  19034. ),
  19035. getSource: function(error)
  19036. {
  19037. var parts = error.source.split("\n");
  19038. if (parts.length != 2)
  19039. return error.source;
  19040. var limit = 50;
  19041. var column = parts[1].length;
  19042. if (column >= limit) {
  19043. parts[0] = "..." + parts[0].substr(column - limit);
  19044. parts[1] = "..." + parts[1].substr(column - limit);
  19045. }
  19046. if (parts[0].length > 80)
  19047. parts[0] = parts[0].substr(0, 80) + "...";
  19048. return parts.join("\n");
  19049. }
  19050. });
  19051. // ************************************************************************************************
  19052. // Registration
  19053. Firebug.registerModule(Firebug.XMLViewerModel);
  19054. }});
  19055. /* See license.txt for terms of usage */
  19056. FBL.ns(function() { with (FBL) {
  19057. // ************************************************************************************************
  19058. // ************************************************************************************************
  19059. // Globals
  19060. var ElementCache = Firebug.Lite.Cache.Element;
  19061. var cacheID = Firebug.Lite.Cache.ID;
  19062. var ignoreHTMLProps =
  19063. {
  19064. // ignores the attributes injected by Sizzle, otherwise it will
  19065. // be visible on IE (when enumerating element.attributes)
  19066. sizcache: 1,
  19067. sizset: 1
  19068. };
  19069. // ignores also the cache property injected by firebug
  19070. ignoreHTMLProps[cacheID] = 1;
  19071. // ************************************************************************************************
  19072. // HTML Module
  19073. Firebug.HTML = extend(Firebug.Module,
  19074. {
  19075. appendTreeNode: function(nodeArray, html)
  19076. {
  19077. var reTrim = /^\s+|\s+$/g;
  19078. if (!nodeArray.length) nodeArray = [nodeArray];
  19079. for (var n=0, node; node=nodeArray[n]; n++)
  19080. {
  19081. if (node.nodeType == 1)
  19082. {
  19083. if (Firebug.ignoreFirebugElements && node.firebugIgnore) continue;
  19084. var uid = ElementCache(node);
  19085. var child = node.childNodes;
  19086. var childLength = child.length;
  19087. var nodeName = node.nodeName.toLowerCase();
  19088. var nodeVisible = isVisible(node);
  19089. var hasSingleTextChild = childLength == 1 && node.firstChild.nodeType == 3 &&
  19090. nodeName != "script" && nodeName != "style";
  19091. var nodeControl = !hasSingleTextChild && childLength > 0 ?
  19092. ('<div class="nodeControl"></div>') : '';
  19093. var isIE = false;
  19094. if(isIE && nodeControl)
  19095. html.push(nodeControl);
  19096. if (typeof uid != 'undefined')
  19097. html.push(
  19098. '<div class="objectBox-element" ',
  19099. 'id="', uid,
  19100. '">',
  19101. !isIE && nodeControl ? nodeControl: "",
  19102. '<span ',
  19103. cacheID,
  19104. '="', uid,
  19105. '" class="nodeBox',
  19106. nodeVisible ? "" : " nodeHidden",
  19107. '">&lt;<span class="nodeTag">', nodeName, '</span>'
  19108. );
  19109. else
  19110. html.push(
  19111. '<div class="objectBox-element"><span class="nodeBox',
  19112. nodeVisible ? "" : " nodeHidden",
  19113. '">&lt;<span class="nodeTag">',
  19114. nodeName, '</span>'
  19115. );
  19116. for (var i = 0; i < node.attributes.length; ++i)
  19117. {
  19118. var attr = node.attributes[i];
  19119. if (!attr.specified || Firebug.ignoreFirebugElements &&
  19120. ignoreHTMLProps.hasOwnProperty(attr.nodeName))
  19121. continue;
  19122. var name = attr.nodeName.toLowerCase();
  19123. var value = name == "style" ? formatStyles(node.style.cssText) : attr.nodeValue;
  19124. html.push('&nbsp;<span class="nodeName">', name,
  19125. '</span>=&quot;<span class="nodeValue">', escapeHTML(value),
  19126. '</span>&quot;')
  19127. }
  19128. /*
  19129. // source code nodes
  19130. if (nodeName == 'script' || nodeName == 'style')
  19131. {
  19132. if(document.all){
  19133. var src = node.innerHTML+'\n';
  19134. }else {
  19135. var src = '\n'+node.innerHTML+'\n';
  19136. }
  19137. var match = src.match(/\n/g);
  19138. var num = match ? match.length : 0;
  19139. var s = [], sl = 0;
  19140. for(var c=1; c<num; c++){
  19141. s[sl++] = '<div line="'+c+'">' + c + '</div>';
  19142. }
  19143. html.push('&gt;</div><div class="nodeGroup"><div class="nodeChildren"><div class="lineNo">',
  19144. s.join(''),
  19145. '</div><pre class="nodeCode">',
  19146. escapeHTML(src),
  19147. '</pre>',
  19148. '</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
  19149. nodeName,
  19150. '</span>&gt;</div>',
  19151. '</div>'
  19152. );
  19153. }/**/
  19154. // Just a single text node child
  19155. if (hasSingleTextChild)
  19156. {
  19157. var value = child[0].nodeValue.replace(reTrim, '');
  19158. if(value)
  19159. {
  19160. html.push(
  19161. '&gt;<span class="nodeText">',
  19162. escapeHTML(value),
  19163. '</span>&lt;/<span class="nodeTag">',
  19164. nodeName,
  19165. '</span>&gt;</span></div>'
  19166. );
  19167. }
  19168. else
  19169. html.push('/&gt;</span></div>'); // blank text, print as childless node
  19170. }
  19171. else if (childLength > 0)
  19172. {
  19173. html.push('&gt;</span></div>');
  19174. }
  19175. else
  19176. html.push('/&gt;</span></div>');
  19177. }
  19178. else if (node.nodeType == 3)
  19179. {
  19180. if ( node.parentNode && ( node.parentNode.nodeName.toLowerCase() == "script" ||
  19181. node.parentNode.nodeName.toLowerCase() == "style" ) )
  19182. {
  19183. var value = node.nodeValue.replace(reTrim, '');
  19184. if(isIE){
  19185. var src = value+'\n';
  19186. }else {
  19187. var src = '\n'+value+'\n';
  19188. }
  19189. var match = src.match(/\n/g);
  19190. var num = match ? match.length : 0;
  19191. var s = [], sl = 0;
  19192. for(var c=1; c<num; c++){
  19193. s[sl++] = '<div line="'+c+'">' + c + '</div>';
  19194. }
  19195. html.push('<div class="lineNo">',
  19196. s.join(''),
  19197. '</div><pre class="sourceCode">',
  19198. escapeHTML(src),
  19199. '</pre>'
  19200. );
  19201. }
  19202. else
  19203. {
  19204. var value = node.nodeValue.replace(reTrim, '');
  19205. if (value)
  19206. html.push('<div class="nodeText">', escapeHTML(value),'</div>');
  19207. }
  19208. }
  19209. }
  19210. },
  19211. appendTreeChildren: function(treeNode)
  19212. {
  19213. var doc = Firebug.chrome.document;
  19214. var uid = treeNode.id;
  19215. var parentNode = ElementCache.get(uid);
  19216. if (parentNode.childNodes.length == 0) return;
  19217. var treeNext = treeNode.nextSibling;
  19218. var treeParent = treeNode.parentNode;
  19219. var isIE = false;
  19220. var control = isIE ? treeNode.previousSibling : treeNode.firstChild;
  19221. control.className = 'nodeControl nodeMaximized';
  19222. var html = [];
  19223. var children = doc.createElement("div");
  19224. children.className = "nodeChildren";
  19225. this.appendTreeNode(parentNode.childNodes, html);
  19226. children.innerHTML = html.join("");
  19227. treeParent.insertBefore(children, treeNext);
  19228. var closeElement = doc.createElement("div");
  19229. closeElement.className = "objectBox-element";
  19230. closeElement.innerHTML = '&lt;/<span class="nodeTag">' +
  19231. parentNode.nodeName.toLowerCase() + '&gt;</span>'
  19232. treeParent.insertBefore(closeElement, treeNext);
  19233. },
  19234. removeTreeChildren: function(treeNode)
  19235. {
  19236. var children = treeNode.nextSibling;
  19237. var closeTag = children.nextSibling;
  19238. var isIE = false;
  19239. var control = isIE ? treeNode.previousSibling : treeNode.firstChild;
  19240. control.className = 'nodeControl';
  19241. children.parentNode.removeChild(children);
  19242. closeTag.parentNode.removeChild(closeTag);
  19243. },
  19244. isTreeNodeVisible: function(id)
  19245. {
  19246. return $(id);
  19247. },
  19248. select: function(el)
  19249. {
  19250. var id = el && ElementCache(el);
  19251. if (id)
  19252. this.selectTreeNode(id);
  19253. },
  19254. selectTreeNode: function(id)
  19255. {
  19256. id = ""+id;
  19257. var node, stack = [];
  19258. while(id && !this.isTreeNodeVisible(id))
  19259. {
  19260. stack.push(id);
  19261. var node = ElementCache.get(id).parentNode;
  19262. if (node)
  19263. id = ElementCache(node);
  19264. else
  19265. break;
  19266. }
  19267. stack.push(id);
  19268. while(stack.length > 0)
  19269. {
  19270. id = stack.pop();
  19271. node = $(id);
  19272. if (stack.length > 0 && ElementCache.get(id).childNodes.length > 0)
  19273. this.appendTreeChildren(node);
  19274. }
  19275. selectElement(node);
  19276. // TODO: xxxpedro
  19277. if (fbPanel1)
  19278. fbPanel1.scrollTop = Math.round(node.offsetTop - fbPanel1.clientHeight/2);
  19279. }
  19280. });
  19281. Firebug.registerModule(Firebug.HTML);
  19282. // ************************************************************************************************
  19283. // HTML Panel
  19284. function HTMLPanel(){};
  19285. HTMLPanel.prototype = extend(Firebug.Panel,
  19286. {
  19287. name: "HTML",
  19288. title: "HTML",
  19289. options: {
  19290. hasSidePanel: true,
  19291. //hasToolButtons: true,
  19292. isPreRendered: true,
  19293. innerHTMLSync: true
  19294. },
  19295. create: function(){
  19296. Firebug.Panel.create.apply(this, arguments);
  19297. this.panelNode.style.padding = "4px 3px 1px 15px";
  19298. this.panelNode.style.minWidth = "500px";
  19299. if (Env.Options.enablePersistent || Firebug.chrome.type != "popup")
  19300. this.createUI();
  19301. if(!this.sidePanelBar.selectedPanel)
  19302. {
  19303. this.sidePanelBar.selectPanel("css");
  19304. }
  19305. },
  19306. destroy: function()
  19307. {
  19308. selectedElement = null
  19309. fbPanel1 = null;
  19310. selectedSidePanelTS = null;
  19311. selectedSidePanelTimer = null;
  19312. Firebug.Panel.destroy.apply(this, arguments);
  19313. },
  19314. createUI: function()
  19315. {
  19316. var rootNode = Firebug.browser.document.documentElement;
  19317. var html = [];
  19318. Firebug.HTML.appendTreeNode(rootNode, html);
  19319. this.panelNode.innerHTML = html.join("");
  19320. },
  19321. initialize: function()
  19322. {
  19323. Firebug.Panel.initialize.apply(this, arguments);
  19324. addEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick);
  19325. fbPanel1 = $("fbPanel1");
  19326. if(!selectedElement)
  19327. {
  19328. Firebug.HTML.selectTreeNode(ElementCache(Firebug.browser.document.body));
  19329. }
  19330. // TODO: xxxpedro
  19331. addEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove);
  19332. addEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove);
  19333. addEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove);
  19334. },
  19335. shutdown: function()
  19336. {
  19337. // TODO: xxxpedro
  19338. removeEvent(fbPanel1, 'mousemove', Firebug.HTML.onListMouseMove);
  19339. removeEvent($("fbContent"), 'mouseout', Firebug.HTML.onListMouseMove);
  19340. removeEvent(Firebug.chrome.node, 'mouseout', Firebug.HTML.onListMouseMove);
  19341. removeEvent(this.panelNode, 'click', Firebug.HTML.onTreeClick);
  19342. fbPanel1 = null;
  19343. Firebug.Panel.shutdown.apply(this, arguments);
  19344. },
  19345. reattach: function()
  19346. {
  19347. // TODO: panel reattach
  19348. if(FirebugChrome.selectedHTMLElementId)
  19349. Firebug.HTML.selectTreeNode(FirebugChrome.selectedHTMLElementId);
  19350. },
  19351. updateSelection: function(object)
  19352. {
  19353. var id = ElementCache(object);
  19354. if (id)
  19355. {
  19356. Firebug.HTML.selectTreeNode(id);
  19357. }
  19358. }
  19359. });
  19360. Firebug.registerPanel(HTMLPanel);
  19361. // ************************************************************************************************
  19362. var formatStyles = function(styles)
  19363. {
  19364. return isIE ?
  19365. // IE return CSS property names in upper case, so we need to convert them
  19366. styles.replace(/([^\s]+)\s*:/g, function(m,g){return g.toLowerCase()+":"}) :
  19367. // other browsers are just fine
  19368. styles;
  19369. };
  19370. // ************************************************************************************************
  19371. var selectedElement = null
  19372. var fbPanel1 = null;
  19373. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19374. var selectedSidePanelTS, selectedSidePanelTimer;
  19375. var selectElement= function selectElement(e)
  19376. {
  19377. if (e != selectedElement)
  19378. {
  19379. if (selectedElement)
  19380. selectedElement.className = "objectBox-element";
  19381. e.className = e.className + " selectedElement";
  19382. if (FBL.isFirefox)
  19383. e.style.MozBorderRadius = "2px";
  19384. else if (FBL.isSafari)
  19385. e.style.WebkitBorderRadius = "2px";
  19386. selectedElement = e;
  19387. FirebugChrome.selectedHTMLElementId = e.id;
  19388. var target = ElementCache.get(e.id);
  19389. var selectedSidePanel = Firebug.chrome.getPanel("HTML").sidePanelBar.selectedPanel;
  19390. var stack = FirebugChrome.htmlSelectionStack;
  19391. stack.unshift(target);
  19392. if (stack.length > 2)
  19393. stack.pop();
  19394. var lazySelect = function()
  19395. {
  19396. selectedSidePanelTS = new Date().getTime();
  19397. selectedSidePanel.select(target, true);
  19398. };
  19399. if (selectedSidePanelTimer)
  19400. {
  19401. clearTimeout(selectedSidePanelTimer);
  19402. selectedSidePanelTimer = null;
  19403. }
  19404. if (new Date().getTime() - selectedSidePanelTS > 100)
  19405. setTimeout(lazySelect, 0)
  19406. else
  19407. selectedSidePanelTimer = setTimeout(lazySelect, 150);
  19408. }
  19409. }
  19410. // ************************************************************************************************
  19411. // *** TODO: REFACTOR **************************************************************************
  19412. // ************************************************************************************************
  19413. Firebug.HTML.onTreeClick = function (e)
  19414. {
  19415. e = e || event;
  19416. var targ;
  19417. if (e.target) targ = e.target;
  19418. else if (e.srcElement) targ = e.srcElement;
  19419. if (targ.nodeType == 3) // defeat Safari bug
  19420. targ = targ.parentNode;
  19421. if (targ.className.indexOf('nodeControl') != -1 || targ.className == 'nodeTag')
  19422. {
  19423. var isIE = false;
  19424. if(targ.className == 'nodeTag')
  19425. {
  19426. var control = isIE ? (targ.parentNode.previousSibling || targ) :
  19427. (targ.parentNode.previousSibling || targ);
  19428. selectElement(targ.parentNode.parentNode);
  19429. if (control.className.indexOf('nodeControl') == -1)
  19430. return;
  19431. } else
  19432. control = targ;
  19433. FBL.cancelEvent(e);
  19434. var treeNode = isIE ? control.nextSibling : control.parentNode;
  19435. //FBL.Firebug.Console.log(treeNode);
  19436. if (control.className.indexOf(' nodeMaximized') != -1) {
  19437. FBL.Firebug.HTML.removeTreeChildren(treeNode);
  19438. } else {
  19439. FBL.Firebug.HTML.appendTreeChildren(treeNode);
  19440. }
  19441. }
  19442. else if (targ.className == 'nodeValue' || targ.className == 'nodeName')
  19443. {
  19444. /*
  19445. var input = FBL.Firebug.chrome.document.getElementById('treeInput');
  19446. input.style.display = "block";
  19447. input.style.left = targ.offsetLeft + 'px';
  19448. input.style.top = FBL.topHeight + targ.offsetTop - FBL.fbPanel1.scrollTop + 'px';
  19449. input.style.width = targ.offsetWidth + 6 + 'px';
  19450. input.value = targ.textContent || targ.innerText;
  19451. input.focus();
  19452. /**/
  19453. }
  19454. }
  19455. function onListMouseOut(e)
  19456. {
  19457. e = e || event || window;
  19458. var targ;
  19459. if (e.target) targ = e.target;
  19460. else if (e.srcElement) targ = e.srcElement;
  19461. if (targ.nodeType == 3) // defeat Safari bug
  19462. targ = targ.parentNode;
  19463. if (hasClass(targ, "fbPanel")) {
  19464. FBL.Firebug.Inspector.hideBoxModel();
  19465. hoverElement = null;
  19466. }
  19467. };
  19468. var hoverElement = null;
  19469. var hoverElementTS = 0;
  19470. Firebug.HTML.onListMouseMove = function onListMouseMove(e)
  19471. {
  19472. try
  19473. {
  19474. e = e || event || window;
  19475. var targ;
  19476. if (e.target) targ = e.target;
  19477. else if (e.srcElement) targ = e.srcElement;
  19478. if (targ.nodeType == 3) // defeat Safari bug
  19479. targ = targ.parentNode;
  19480. var found = false;
  19481. while (targ && !found) {
  19482. if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " "))
  19483. targ = targ.parentNode;
  19484. else
  19485. found = true;
  19486. }
  19487. if (!targ)
  19488. {
  19489. FBL.Firebug.Inspector.hideBoxModel();
  19490. hoverElement = null;
  19491. return;
  19492. }
  19493. /*
  19494. if (typeof targ.attributes[cacheID] == 'undefined') return;
  19495. var uid = targ.attributes[cacheID];
  19496. if (!uid) return;
  19497. /**/
  19498. if (typeof targ.attributes[cacheID] == 'undefined') return;
  19499. var uid = targ.attributes[cacheID];
  19500. if (!uid) return;
  19501. var el = ElementCache.get(uid.value);
  19502. var nodeName = el.nodeName.toLowerCase();
  19503. if (FBL.isIE && " meta title script link ".indexOf(" "+nodeName+" ") != -1)
  19504. return;
  19505. if (!/\snodeBox\s|\sobjectBox-selector\s/.test(" " + targ.className + " ")) return;
  19506. if (el.id == "FirebugUI" || " html head body br script link iframe ".indexOf(" "+nodeName+" ") != -1) {
  19507. FBL.Firebug.Inspector.hideBoxModel();
  19508. hoverElement = null;
  19509. return;
  19510. }
  19511. if ((new Date().getTime() - hoverElementTS > 40) && hoverElement != el) {
  19512. hoverElementTS = new Date().getTime();
  19513. hoverElement = el;
  19514. FBL.Firebug.Inspector.drawBoxModel(el);
  19515. }
  19516. }
  19517. catch(E)
  19518. {
  19519. }
  19520. }
  19521. // ************************************************************************************************
  19522. Firebug.Reps = {
  19523. appendText: function(object, html)
  19524. {
  19525. html.push(escapeHTML(objectToString(object)));
  19526. },
  19527. appendNull: function(object, html)
  19528. {
  19529. html.push('<span class="objectBox-null">', escapeHTML(objectToString(object)), '</span>');
  19530. },
  19531. appendString: function(object, html)
  19532. {
  19533. html.push('<span class="objectBox-string">&quot;', escapeHTML(objectToString(object)),
  19534. '&quot;</span>');
  19535. },
  19536. appendInteger: function(object, html)
  19537. {
  19538. html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
  19539. },
  19540. appendFloat: function(object, html)
  19541. {
  19542. html.push('<span class="objectBox-number">', escapeHTML(objectToString(object)), '</span>');
  19543. },
  19544. appendFunction: function(object, html)
  19545. {
  19546. var reName = /function ?(.*?)\(/;
  19547. var m = reName.exec(objectToString(object));
  19548. var name = m && m[1] ? m[1] : "function";
  19549. html.push('<span class="objectBox-function">', escapeHTML(name), '()</span>');
  19550. },
  19551. appendObject: function(object, html)
  19552. {
  19553. /*
  19554. var rep = Firebug.getRep(object);
  19555. var outputs = [];
  19556. rep.tag.tag.compile();
  19557. var str = rep.tag.renderHTML({object: object}, outputs);
  19558. html.push(str);
  19559. /**/
  19560. try
  19561. {
  19562. if (object == undefined)
  19563. this.appendNull("undefined", html);
  19564. else if (object == null)
  19565. this.appendNull("null", html);
  19566. else if (typeof object == "string")
  19567. this.appendString(object, html);
  19568. else if (typeof object == "number")
  19569. this.appendInteger(object, html);
  19570. else if (typeof object == "boolean")
  19571. this.appendInteger(object, html);
  19572. else if (typeof object == "function")
  19573. this.appendFunction(object, html);
  19574. else if (object.nodeType == 1)
  19575. this.appendSelector(object, html);
  19576. else if (typeof object == "object")
  19577. {
  19578. if (typeof object.length != "undefined")
  19579. this.appendArray(object, html);
  19580. else
  19581. this.appendObjectFormatted(object, html);
  19582. }
  19583. else
  19584. this.appendText(object, html);
  19585. }
  19586. catch (exc)
  19587. {
  19588. }
  19589. /**/
  19590. },
  19591. appendObjectFormatted: function(object, html)
  19592. {
  19593. var text = objectToString(object);
  19594. var reObject = /\[object (.*?)\]/;
  19595. var m = reObject.exec(text);
  19596. html.push('<span class="objectBox-object">', m ? m[1] : text, '</span>')
  19597. },
  19598. appendSelector: function(object, html)
  19599. {
  19600. var uid = ElementCache(object);
  19601. var uidString = uid ? [cacheID, '="', uid, '"'].join("") : "";
  19602. html.push('<span class="objectBox-selector"', uidString, '>');
  19603. html.push('<span class="selectorTag">', escapeHTML(object.nodeName.toLowerCase()), '</span>');
  19604. if (object.id)
  19605. html.push('<span class="selectorId">#', escapeHTML(object.id), '</span>');
  19606. if (object.className)
  19607. html.push('<span class="selectorClass">.', escapeHTML(object.className), '</span>');
  19608. html.push('</span>');
  19609. },
  19610. appendNode: function(node, html)
  19611. {
  19612. if (node.nodeType == 1)
  19613. {
  19614. var uid = ElementCache(node);
  19615. var uidString = uid ? [cacheID, '="', uid, '"'].join("") : "";
  19616. html.push(
  19617. '<div class="objectBox-element"', uidString, '">',
  19618. '<span ', cacheID, '="', uid, '" class="nodeBox">',
  19619. '&lt;<span class="nodeTag">', node.nodeName.toLowerCase(), '</span>');
  19620. for (var i = 0; i < node.attributes.length; ++i)
  19621. {
  19622. var attr = node.attributes[i];
  19623. if (!attr.specified || attr.nodeName == cacheID)
  19624. continue;
  19625. var name = attr.nodeName.toLowerCase();
  19626. var value = name == "style" ? node.style.cssText : attr.nodeValue;
  19627. html.push('&nbsp;<span class="nodeName">', name,
  19628. '</span>=&quot;<span class="nodeValue">', escapeHTML(value),
  19629. '</span>&quot;')
  19630. }
  19631. if (node.firstChild)
  19632. {
  19633. html.push('&gt;</div><div class="nodeChildren">');
  19634. for (var child = node.firstChild; child; child = child.nextSibling)
  19635. this.appendNode(child, html);
  19636. html.push('</div><div class="objectBox-element">&lt;/<span class="nodeTag">',
  19637. node.nodeName.toLowerCase(), '&gt;</span></span></div>');
  19638. }
  19639. else
  19640. html.push('/&gt;</span></div>');
  19641. }
  19642. else if (node.nodeType == 3)
  19643. {
  19644. var value = trim(node.nodeValue);
  19645. if (value)
  19646. html.push('<div class="nodeText">', escapeHTML(value),'</div>');
  19647. }
  19648. },
  19649. appendArray: function(object, html)
  19650. {
  19651. html.push('<span class="objectBox-array"><b>[</b> ');
  19652. for (var i = 0, l = object.length, obj; i < l; ++i)
  19653. {
  19654. this.appendObject(object[i], html);
  19655. if (i < l-1)
  19656. html.push(', ');
  19657. }
  19658. html.push(' <b>]</b></span>');
  19659. }
  19660. };
  19661. // ************************************************************************************************
  19662. }});
  19663. /* See license.txt for terms of usage */
  19664. /*
  19665. Hack:
  19666. Firebug.chrome.currentPanel = Firebug.chrome.selectedPanel;
  19667. Firebug.showInfoTips = true;
  19668. Firebug.InfoTip.initializeBrowser(Firebug.chrome);
  19669. /**/
  19670. FBL.ns(function() { with (FBL) {
  19671. // ************************************************************************************************
  19672. // Constants
  19673. var maxWidth = 100, maxHeight = 80;
  19674. var infoTipMargin = 10;
  19675. var infoTipWindowPadding = 25;
  19676. // ************************************************************************************************
  19677. Firebug.InfoTip = extend(Firebug.Module,
  19678. {
  19679. dispatchName: "infoTip",
  19680. tags: domplate(
  19681. {
  19682. infoTipTag: DIV({"class": "infoTip"}),
  19683. colorTag:
  19684. DIV({style: "background: $rgbValue; width: 100px; height: 40px"}, "&nbsp;"),
  19685. imgTag:
  19686. DIV({"class": "infoTipImageBox infoTipLoading"},
  19687. IMG({"class": "infoTipImage", src: "$urlValue", repeat: "$repeat",
  19688. onload: "$onLoadImage"}),
  19689. IMG({"class": "infoTipBgImage", collapsed: true, src: "blank.gif"}),
  19690. DIV({"class": "infoTipCaption"})
  19691. ),
  19692. onLoadImage: function(event)
  19693. {
  19694. var img = event.currentTarget || event.srcElement;
  19695. ///var bgImg = img.nextSibling;
  19696. ///if (!bgImg)
  19697. /// return; // Sometimes gets called after element is dead
  19698. ///var caption = bgImg.nextSibling;
  19699. var innerBox = img.parentNode;
  19700. /// TODO: xxxpedro infoTip hack
  19701. var caption = getElementByClass(innerBox, "infoTipCaption");
  19702. var bgImg = getElementByClass(innerBox, "infoTipBgImage");
  19703. if (!bgImg)
  19704. return; // Sometimes gets called after element is dead
  19705. // TODO: xxxpedro infoTip IE and timing issue
  19706. // TODO: use offline document to avoid flickering
  19707. if (isIE)
  19708. removeClass(innerBox, "infoTipLoading");
  19709. var updateInfoTip = function(){
  19710. var w = img.naturalWidth || img.width || 10,
  19711. h = img.naturalHeight || img.height || 10;
  19712. var repeat = img.getAttribute("repeat");
  19713. if (repeat == "repeat-x" || (w == 1 && h > 1))
  19714. {
  19715. collapse(img, true);
  19716. collapse(bgImg, false);
  19717. bgImg.style.background = "url(" + img.src + ") repeat-x";
  19718. bgImg.style.width = maxWidth + "px";
  19719. if (h > maxHeight)
  19720. bgImg.style.height = maxHeight + "px";
  19721. else
  19722. bgImg.style.height = h + "px";
  19723. }
  19724. else if (repeat == "repeat-y" || (h == 1 && w > 1))
  19725. {
  19726. collapse(img, true);
  19727. collapse(bgImg, false);
  19728. bgImg.style.background = "url(" + img.src + ") repeat-y";
  19729. bgImg.style.height = maxHeight + "px";
  19730. if (w > maxWidth)
  19731. bgImg.style.width = maxWidth + "px";
  19732. else
  19733. bgImg.style.width = w + "px";
  19734. }
  19735. else if (repeat == "repeat" || (w == 1 && h == 1))
  19736. {
  19737. collapse(img, true);
  19738. collapse(bgImg, false);
  19739. bgImg.style.background = "url(" + img.src + ") repeat";
  19740. bgImg.style.width = maxWidth + "px";
  19741. bgImg.style.height = maxHeight + "px";
  19742. }
  19743. else
  19744. {
  19745. if (w > maxWidth || h > maxHeight)
  19746. {
  19747. if (w > h)
  19748. {
  19749. img.style.width = maxWidth + "px";
  19750. img.style.height = Math.round((h / w) * maxWidth) + "px";
  19751. }
  19752. else
  19753. {
  19754. img.style.width = Math.round((w / h) * maxHeight) + "px";
  19755. img.style.height = maxHeight + "px";
  19756. }
  19757. }
  19758. }
  19759. //caption.innerHTML = $STRF("Dimensions", [w, h]);
  19760. caption.innerHTML = $STRF(w + " x " + h);
  19761. };
  19762. if (isIE)
  19763. setTimeout(updateInfoTip, 0);
  19764. else
  19765. {
  19766. updateInfoTip();
  19767. removeClass(innerBox, "infoTipLoading");
  19768. }
  19769. ///
  19770. }
  19771. /*
  19772. /// onLoadImage original
  19773. onLoadImage: function(event)
  19774. {
  19775. var img = event.currentTarget;
  19776. var bgImg = img.nextSibling;
  19777. if (!bgImg)
  19778. return; // Sometimes gets called after element is dead
  19779. var caption = bgImg.nextSibling;
  19780. var innerBox = img.parentNode;
  19781. var w = img.naturalWidth, h = img.naturalHeight;
  19782. var repeat = img.getAttribute("repeat");
  19783. if (repeat == "repeat-x" || (w == 1 && h > 1))
  19784. {
  19785. collapse(img, true);
  19786. collapse(bgImg, false);
  19787. bgImg.style.background = "url(" + img.src + ") repeat-x";
  19788. bgImg.style.width = maxWidth + "px";
  19789. if (h > maxHeight)
  19790. bgImg.style.height = maxHeight + "px";
  19791. else
  19792. bgImg.style.height = h + "px";
  19793. }
  19794. else if (repeat == "repeat-y" || (h == 1 && w > 1))
  19795. {
  19796. collapse(img, true);
  19797. collapse(bgImg, false);
  19798. bgImg.style.background = "url(" + img.src + ") repeat-y";
  19799. bgImg.style.height = maxHeight + "px";
  19800. if (w > maxWidth)
  19801. bgImg.style.width = maxWidth + "px";
  19802. else
  19803. bgImg.style.width = w + "px";
  19804. }
  19805. else if (repeat == "repeat" || (w == 1 && h == 1))
  19806. {
  19807. collapse(img, true);
  19808. collapse(bgImg, false);
  19809. bgImg.style.background = "url(" + img.src + ") repeat";
  19810. bgImg.style.width = maxWidth + "px";
  19811. bgImg.style.height = maxHeight + "px";
  19812. }
  19813. else
  19814. {
  19815. if (w > maxWidth || h > maxHeight)
  19816. {
  19817. if (w > h)
  19818. {
  19819. img.style.width = maxWidth + "px";
  19820. img.style.height = Math.round((h / w) * maxWidth) + "px";
  19821. }
  19822. else
  19823. {
  19824. img.style.width = Math.round((w / h) * maxHeight) + "px";
  19825. img.style.height = maxHeight + "px";
  19826. }
  19827. }
  19828. }
  19829. caption.innerHTML = $STRF("Dimensions", [w, h]);
  19830. removeClass(innerBox, "infoTipLoading");
  19831. }
  19832. /**/
  19833. }),
  19834. initializeBrowser: function(browser)
  19835. {
  19836. browser.onInfoTipMouseOut = bind(this.onMouseOut, this, browser);
  19837. browser.onInfoTipMouseMove = bind(this.onMouseMove, this, browser);
  19838. ///var doc = browser.contentDocument;
  19839. var doc = browser.document;
  19840. if (!doc)
  19841. return;
  19842. ///doc.addEventListener("mouseover", browser.onInfoTipMouseMove, true);
  19843. ///doc.addEventListener("mouseout", browser.onInfoTipMouseOut, true);
  19844. ///doc.addEventListener("mousemove", browser.onInfoTipMouseMove, true);
  19845. addEvent(doc, "mouseover", browser.onInfoTipMouseMove);
  19846. addEvent(doc, "mouseout", browser.onInfoTipMouseOut);
  19847. addEvent(doc, "mousemove", browser.onInfoTipMouseMove);
  19848. return browser.infoTip = this.tags.infoTipTag.append({}, getBody(doc));
  19849. },
  19850. uninitializeBrowser: function(browser)
  19851. {
  19852. if (browser.infoTip)
  19853. {
  19854. ///var doc = browser.contentDocument;
  19855. var doc = browser.document;
  19856. ///doc.removeEventListener("mouseover", browser.onInfoTipMouseMove, true);
  19857. ///doc.removeEventListener("mouseout", browser.onInfoTipMouseOut, true);
  19858. ///doc.removeEventListener("mousemove", browser.onInfoTipMouseMove, true);
  19859. removeEvent(doc, "mouseover", browser.onInfoTipMouseMove);
  19860. removeEvent(doc, "mouseout", browser.onInfoTipMouseOut);
  19861. removeEvent(doc, "mousemove", browser.onInfoTipMouseMove);
  19862. browser.infoTip.parentNode.removeChild(browser.infoTip);
  19863. delete browser.infoTip;
  19864. delete browser.onInfoTipMouseMove;
  19865. }
  19866. },
  19867. showInfoTip: function(infoTip, panel, target, x, y, rangeParent, rangeOffset)
  19868. {
  19869. if (!Firebug.showInfoTips)
  19870. return;
  19871. var scrollParent = getOverflowParent(target);
  19872. var scrollX = x + (scrollParent ? scrollParent.scrollLeft : 0);
  19873. if (panel.showInfoTip(infoTip, target, scrollX, y, rangeParent, rangeOffset))
  19874. {
  19875. var htmlElt = infoTip.ownerDocument.documentElement;
  19876. var panelWidth = htmlElt.clientWidth;
  19877. var panelHeight = htmlElt.clientHeight;
  19878. if (x+infoTip.offsetWidth+infoTipMargin > panelWidth)
  19879. {
  19880. infoTip.style.left = Math.max(0, panelWidth-(infoTip.offsetWidth+infoTipMargin)) + "px";
  19881. infoTip.style.right = "auto";
  19882. }
  19883. else
  19884. {
  19885. infoTip.style.left = (x+infoTipMargin) + "px";
  19886. infoTip.style.right = "auto";
  19887. }
  19888. if (y+infoTip.offsetHeight+infoTipMargin > panelHeight)
  19889. {
  19890. infoTip.style.top = Math.max(0, panelHeight-(infoTip.offsetHeight+infoTipMargin)) + "px";
  19891. infoTip.style.bottom = "auto";
  19892. }
  19893. else
  19894. {
  19895. infoTip.style.top = (y+infoTipMargin) + "px";
  19896. infoTip.style.bottom = "auto";
  19897. }
  19898. if (FBTrace.DBG_INFOTIP)
  19899. FBTrace.sysout("infotip.showInfoTip; top: " + infoTip.style.top +
  19900. ", left: " + infoTip.style.left + ", bottom: " + infoTip.style.bottom +
  19901. ", right:" + infoTip.style.right + ", offsetHeight: " + infoTip.offsetHeight +
  19902. ", offsetWidth: " + infoTip.offsetWidth +
  19903. ", x: " + x + ", panelWidth: " + panelWidth +
  19904. ", y: " + y + ", panelHeight: " + panelHeight);
  19905. infoTip.setAttribute("active", "true");
  19906. }
  19907. else
  19908. this.hideInfoTip(infoTip);
  19909. },
  19910. hideInfoTip: function(infoTip)
  19911. {
  19912. if (infoTip)
  19913. infoTip.removeAttribute("active");
  19914. },
  19915. onMouseOut: function(event, browser)
  19916. {
  19917. if (!event.relatedTarget)
  19918. this.hideInfoTip(browser.infoTip);
  19919. },
  19920. onMouseMove: function(event, browser)
  19921. {
  19922. // Ignore if the mouse is moving over the existing info tip.
  19923. if (getAncestorByClass(event.target, "infoTip"))
  19924. return;
  19925. if (browser.currentPanel)
  19926. {
  19927. var x = event.clientX, y = event.clientY, target = event.target || event.srcElement;
  19928. this.showInfoTip(browser.infoTip, browser.currentPanel, target, x, y, event.rangeParent, event.rangeOffset);
  19929. }
  19930. else
  19931. this.hideInfoTip(browser.infoTip);
  19932. },
  19933. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19934. populateColorInfoTip: function(infoTip, color)
  19935. {
  19936. this.tags.colorTag.replace({rgbValue: color}, infoTip);
  19937. return true;
  19938. },
  19939. populateImageInfoTip: function(infoTip, url, repeat)
  19940. {
  19941. if (!repeat)
  19942. repeat = "no-repeat";
  19943. this.tags.imgTag.replace({urlValue: url, repeat: repeat}, infoTip);
  19944. return true;
  19945. },
  19946. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  19947. // extends Module
  19948. disable: function()
  19949. {
  19950. // XXXjoe For each browser, call uninitializeBrowser
  19951. },
  19952. showPanel: function(browser, panel)
  19953. {
  19954. if (panel)
  19955. {
  19956. var infoTip = panel.panelBrowser.infoTip;
  19957. if (!infoTip)
  19958. infoTip = this.initializeBrowser(panel.panelBrowser);
  19959. this.hideInfoTip(infoTip);
  19960. }
  19961. },
  19962. showSidePanel: function(browser, panel)
  19963. {
  19964. this.showPanel(browser, panel);
  19965. }
  19966. });
  19967. // ************************************************************************************************
  19968. Firebug.registerModule(Firebug.InfoTip);
  19969. // ************************************************************************************************
  19970. }});
  19971. /* See license.txt for terms of usage */
  19972. // move to FBL
  19973. (function() {
  19974. // ************************************************************************************************
  19975. // XPath
  19976. /**
  19977. * Gets an XPath for an element which describes its hierarchical location.
  19978. */
  19979. this.getElementXPath = function(element)
  19980. {
  19981. if (element && element.id)
  19982. return '//*[@id="' + element.id + '"]';
  19983. else
  19984. return this.getElementTreeXPath(element);
  19985. };
  19986. this.getElementTreeXPath = function(element)
  19987. {
  19988. var paths = [];
  19989. for (; element && element.nodeType == 1; element = element.parentNode)
  19990. {
  19991. var index = 0;
  19992. for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling)
  19993. {
  19994. if (sibling.nodeName == element.nodeName)
  19995. ++index;
  19996. }
  19997. var tagName = element.nodeName.toLowerCase();
  19998. var pathIndex = (index ? "[" + (index+1) + "]" : "");
  19999. paths.splice(0, 0, tagName + pathIndex);
  20000. }
  20001. return paths.length ? "/" + paths.join("/") : null;
  20002. };
  20003. this.getElementsByXPath = function(doc, xpath)
  20004. {
  20005. var nodes = [];
  20006. try {
  20007. var result = doc.evaluate(xpath, doc, null, XPathResult.ANY_TYPE, null);
  20008. for (var item = result.iterateNext(); item; item = result.iterateNext())
  20009. nodes.push(item);
  20010. }
  20011. catch (exc)
  20012. {
  20013. // Invalid xpath expressions make their way here sometimes. If that happens,
  20014. // we still want to return an empty set without an exception.
  20015. }
  20016. return nodes;
  20017. };
  20018. this.getRuleMatchingElements = function(rule, doc)
  20019. {
  20020. var css = rule.selectorText;
  20021. var xpath = this.cssToXPath(css);
  20022. return this.getElementsByXPath(doc, xpath);
  20023. };
  20024. }).call(FBL);
  20025. FBL.ns(function() { with (FBL) {
  20026. // ************************************************************************************************
  20027. // ************************************************************************************************
  20028. // ************************************************************************************************
  20029. // ************************************************************************************************
  20030. // ************************************************************************************************
  20031. var toCamelCase = function toCamelCase(s)
  20032. {
  20033. return s.replace(reSelectorCase, toCamelCaseReplaceFn);
  20034. };
  20035. var toSelectorCase = function toSelectorCase(s)
  20036. {
  20037. return s.replace(reCamelCase, "-$1").toLowerCase();
  20038. };
  20039. var reCamelCase = /([A-Z])/g;
  20040. var reSelectorCase = /\-(.)/g;
  20041. var toCamelCaseReplaceFn = function toCamelCaseReplaceFn(m,g)
  20042. {
  20043. return g.toUpperCase();
  20044. };
  20045. // ************************************************************************************************
  20046. var ElementCache = Firebug.Lite.Cache.Element;
  20047. var StyleSheetCache = Firebug.Lite.Cache.StyleSheet;
  20048. var globalCSSRuleIndex;
  20049. var externalStyleSheetURLs = [];
  20050. var externalStyleSheetWarning = domplate(Firebug.Rep,
  20051. {
  20052. tag:
  20053. DIV({"class": "warning focusRow", style: "font-weight:normal;", role: 'listitem'},
  20054. SPAN("$object|STR"),
  20055. A({"href": "$href", target:"_blank"}, "$link|STR")
  20056. )
  20057. });
  20058. var processAllStyleSheetsTimeout = null;
  20059. var loadExternalStylesheet = function(doc, styleSheetIterator, styleSheet)
  20060. {
  20061. var url = styleSheet.href;
  20062. styleSheet.firebugIgnore = true;
  20063. var source = Firebug.Lite.Proxy.load(url);
  20064. // TODO: check for null and error responses
  20065. // remove comments
  20066. //var reMultiComment = /(\/\*([^\*]|\*(?!\/))*\*\/)/g;
  20067. //source = source.replace(reMultiComment, "");
  20068. // convert relative addresses to absolute ones
  20069. source = source.replace(/url\(([^\)]+)\)/g, function(a,name){
  20070. var hasDomain = /\w+:\/\/./.test(name);
  20071. if (!hasDomain)
  20072. {
  20073. name = name.replace(/^(["'])(.+)\1$/, "$2");
  20074. var first = name.charAt(0);
  20075. // relative path, based on root
  20076. if (first == "/")
  20077. {
  20078. // TODO: xxxpedro move to lib or Firebug.Lite.something
  20079. // getURLRoot
  20080. var m = /^([^:]+:\/{1,3}[^\/]+)/.exec(url);
  20081. return m ?
  20082. "url(" + m[1] + name + ")" :
  20083. "url(" + name + ")";
  20084. }
  20085. // relative path, based on current location
  20086. else
  20087. {
  20088. // TODO: xxxpedro move to lib or Firebug.Lite.something
  20089. // getURLPath
  20090. var path = url.replace(/[^\/]+\.[\w\d]+(\?.+|#.+)?$/g, "");
  20091. path = path + name;
  20092. var reBack = /[^\/]+\/\.\.\//;
  20093. while(reBack.test(path))
  20094. {
  20095. path = path.replace(reBack, "");
  20096. }
  20097. //console.log("url(" + path + ")");
  20098. return "url(" + path + ")";
  20099. }
  20100. }
  20101. // if it is an absolute path, there is nothing to do
  20102. return a;
  20103. });
  20104. var oldStyle = styleSheet.ownerNode;
  20105. if (!oldStyle) return;
  20106. if (!oldStyle.parentNode) return;
  20107. var style = createGlobalElement("style");
  20108. style.setAttribute("charset","utf-8");
  20109. style.setAttribute("type", "text/css");
  20110. style.innerHTML = source;
  20111. //debugger;
  20112. oldStyle.parentNode.insertBefore(style, oldStyle.nextSibling);
  20113. oldStyle.parentNode.removeChild(oldStyle);
  20114. //doc.getElementsByTagName("head")[0].appendChild(style);
  20115. doc.styleSheets[doc.styleSheets.length-1].externalURL = url;
  20116. console.log(url, "call " + externalStyleSheetURLs.length, source);
  20117. externalStyleSheetURLs.pop();
  20118. if (processAllStyleSheetsTimeout)
  20119. {
  20120. clearTimeout(processAllStyleSheetsTimeout);
  20121. }
  20122. processAllStyleSheetsTimeout = setTimeout(function(){
  20123. console.log("processing");
  20124. FBL.processAllStyleSheets(doc, styleSheetIterator);
  20125. processAllStyleSheetsTimeout = null;
  20126. },200);
  20127. };
  20128. FBL.processAllStyleSheets = function(doc, styleSheetIterator)
  20129. {
  20130. styleSheetIterator = styleSheetIterator || processStyleSheet;
  20131. globalCSSRuleIndex = -1;
  20132. var styleSheets = doc.styleSheets;
  20133. var importedStyleSheets = [];
  20134. if (FBTrace.DBG_CSS)
  20135. var start = new Date().getTime();
  20136. for(var i=0, length=styleSheets.length; i<length; i++)
  20137. {
  20138. try
  20139. {
  20140. var styleSheet = styleSheets[i];
  20141. if ("firebugIgnore" in styleSheet) continue;
  20142. // we must read the length to make sure we have permission to read
  20143. // the stylesheet's content. If an error occurs here, we cannot
  20144. // read the stylesheet due to access restriction policy
  20145. var rules = isIE ? styleSheet.rules : styleSheet.cssRules;
  20146. rules.length;
  20147. }
  20148. catch(e)
  20149. {
  20150. externalStyleSheetURLs.push(styleSheet.href);
  20151. styleSheet.restricted = true;
  20152. var ssid = StyleSheetCache(styleSheet);
  20153. /// TODO: xxxpedro external css
  20154. //loadExternalStylesheet(doc, styleSheetIterator, styleSheet);
  20155. }
  20156. // process internal and external styleSheets
  20157. styleSheetIterator(doc, styleSheet);
  20158. var importedStyleSheet, importedRules;
  20159. // process imported styleSheets in IE
  20160. if (isIE)
  20161. {
  20162. var imports = styleSheet.imports;
  20163. for(var j=0, importsLength=imports.length; j<importsLength; j++)
  20164. {
  20165. try
  20166. {
  20167. importedStyleSheet = imports[j];
  20168. // we must read the length to make sure we have permission
  20169. // to read the imported stylesheet's content.
  20170. importedRules = importedStyleSheet.rules;
  20171. importedRules.length;
  20172. }
  20173. catch(e)
  20174. {
  20175. externalStyleSheetURLs.push(styleSheet.href);
  20176. importedStyleSheet.restricted = true;
  20177. var ssid = StyleSheetCache(importedStyleSheet);
  20178. }
  20179. styleSheetIterator(doc, importedStyleSheet);
  20180. }
  20181. }
  20182. // process imported styleSheets in other browsers
  20183. else if (rules)
  20184. {
  20185. for(var j=0, rulesLength=rules.length; j<rulesLength; j++)
  20186. {
  20187. try
  20188. {
  20189. var rule = rules[j];
  20190. importedStyleSheet = rule.styleSheet;
  20191. if (importedStyleSheet)
  20192. {
  20193. // we must read the length to make sure we have permission
  20194. // to read the imported stylesheet's content.
  20195. importedRules = importedStyleSheet.cssRules;
  20196. importedRules.length;
  20197. }
  20198. else
  20199. break;
  20200. }
  20201. catch(e)
  20202. {
  20203. externalStyleSheetURLs.push(styleSheet.href);
  20204. importedStyleSheet.restricted = true;
  20205. var ssid = StyleSheetCache(importedStyleSheet);
  20206. }
  20207. styleSheetIterator(doc, importedStyleSheet);
  20208. }
  20209. }
  20210. };
  20211. if (FBTrace.DBG_CSS)
  20212. {
  20213. FBTrace.sysout("FBL.processAllStyleSheets", "all stylesheet rules processed in " + (new Date().getTime() - start) + "ms");
  20214. }
  20215. };
  20216. var CSSRuleMap = {};
  20217. var ElementCSSRulesMap = {};
  20218. var processStyleSheet = function(doc, styleSheet)
  20219. {
  20220. if (styleSheet.restricted)
  20221. return;
  20222. var rules = isIE ? styleSheet.rules : styleSheet.cssRules;
  20223. var ssid = StyleSheetCache(styleSheet);
  20224. for (var i=0, length=rules.length; i<length; i++)
  20225. {
  20226. var rid = ssid + ":" + i;
  20227. var rule = rules[i];
  20228. var selector = rule.selectorText;
  20229. if (isIE)
  20230. {
  20231. selector = selector.replace(reSelectorTag, function(s){return s.toLowerCase();});
  20232. }
  20233. // TODO: xxxpedro break grouped rules (,) into individual rules, otherwise
  20234. // it will result in a overestimated value for getCSSRuleSpecificity
  20235. CSSRuleMap[rid] =
  20236. {
  20237. styleSheetId: ssid,
  20238. styleSheetIndex: i,
  20239. order: ++globalCSSRuleIndex,
  20240. // if it is a grouped selector, do not calculate the specificity
  20241. // because the correct value will depend of the matched element.
  20242. // The proper specificity value for grouped selectors are calculated
  20243. // via getElementCSSRules(element)
  20244. specificity: selector && selector.indexOf(",") != -1 ?
  20245. getCSSRuleSpecificity(selector) :
  20246. 0,
  20247. rule: rule,
  20248. selector: selector,
  20249. cssText: rule.style ? rule.style.cssText : rule.cssText ? rule.cssText : ""
  20250. };
  20251. var elements = Firebug.Selector(selector, doc);
  20252. for (var j=0, elementsLength=elements.length; j<elementsLength; j++)
  20253. {
  20254. var element = elements[j];
  20255. var eid = ElementCache(element);
  20256. if (!ElementCSSRulesMap[eid])
  20257. ElementCSSRulesMap[eid] = [];
  20258. ElementCSSRulesMap[eid].push(rid);
  20259. }
  20260. //console.log(selector, elements);
  20261. }
  20262. // TODO: xxxpedro. remove this, we don't need this anymore with the new getElementCSSRules
  20263. /*
  20264. for (var name in ElementCSSRulesMap)
  20265. {
  20266. if (ElementCSSRulesMap.hasOwnProperty(name))
  20267. {
  20268. var rules = ElementCSSRulesMap[name];
  20269. rules.sort(sortElementRules);
  20270. //rules.sort(solveRulesTied);
  20271. }
  20272. }
  20273. /**/
  20274. };
  20275. FBL.getElementCSSRules = function(element)
  20276. {
  20277. var eid = ElementCache(element);
  20278. var rules = ElementCSSRulesMap[eid];
  20279. if (!rules) return;
  20280. var arr = [element];
  20281. var Selector = Firebug.Selector;
  20282. var ruleId, rule;
  20283. // for the case of grouped selectors, we need to calculate the highest
  20284. // specificity within the selectors of the group that matches the element,
  20285. // so we can sort the rules properly without over estimating the specificity
  20286. // of grouped selectors
  20287. for (var i = 0, length = rules.length; i < length; i++)
  20288. {
  20289. ruleId = rules[i];
  20290. rule = CSSRuleMap[ruleId];
  20291. // check if it is a grouped selector
  20292. if (rule.selector.indexOf(",") != -1)
  20293. {
  20294. var selectors = rule.selector.split(",");
  20295. var maxSpecificity = -1;
  20296. var sel, spec, mostSpecificSelector;
  20297. // loop over all selectors in the group
  20298. for (var j, len = selectors.length; j < len; j++)
  20299. {
  20300. sel = selectors[j];
  20301. // find if the selector matches the element
  20302. if (Selector.matches(sel, arr).length == 1)
  20303. {
  20304. spec = getCSSRuleSpecificity(sel);
  20305. // find the most specific selector that macthes the element
  20306. if (spec > maxSpecificity)
  20307. {
  20308. maxSpecificity = spec;
  20309. mostSpecificSelector = sel;
  20310. }
  20311. }
  20312. }
  20313. rule.specificity = maxSpecificity;
  20314. }
  20315. }
  20316. rules.sort(sortElementRules);
  20317. //rules.sort(solveRulesTied);
  20318. return rules;
  20319. };
  20320. var sortElementRules = function(a, b)
  20321. {
  20322. var ruleA = CSSRuleMap[a];
  20323. var ruleB = CSSRuleMap[b];
  20324. var specificityA = ruleA.specificity;
  20325. var specificityB = ruleB.specificity;
  20326. if (specificityA > specificityB)
  20327. return 1;
  20328. else if (specificityA < specificityB)
  20329. return -1;
  20330. else
  20331. return ruleA.order > ruleB.order ? 1 : -1;
  20332. };
  20333. var solveRulesTied = function(a, b)
  20334. {
  20335. var ruleA = CSSRuleMap[a];
  20336. var ruleB = CSSRuleMap[b];
  20337. if (ruleA.specificity == ruleB.specificity)
  20338. return ruleA.order > ruleB.order ? 1 : -1;
  20339. return null;
  20340. };
  20341. var reSelectorTag = /(^|\s)(?:\w+)/g;
  20342. var reSelectorClass = /\.[\w\d_-]+/g;
  20343. var reSelectorId = /#[\w\d_-]+/g;
  20344. var getCSSRuleSpecificity = function(selector)
  20345. {
  20346. var match = selector.match(reSelectorTag);
  20347. var tagCount = match ? match.length : 0;
  20348. match = selector.match(reSelectorClass);
  20349. var classCount = match ? match.length : 0;
  20350. match = selector.match(reSelectorId);
  20351. var idCount = match ? match.length : 0;
  20352. return tagCount + 10*classCount + 100*idCount;
  20353. };
  20354. // ************************************************************************************************
  20355. // ************************************************************************************************
  20356. // ************************************************************************************************
  20357. // ************************************************************************************************
  20358. // ************************************************************************************************
  20359. // ************************************************************************************************
  20360. // ************************************************************************************************
  20361. // Constants
  20362. //const Cc = Components.classes;
  20363. //const Ci = Components.interfaces;
  20364. //const nsIDOMCSSStyleRule = Ci.nsIDOMCSSStyleRule;
  20365. //const nsIInterfaceRequestor = Ci.nsIInterfaceRequestor;
  20366. //const nsISelectionDisplay = Ci.nsISelectionDisplay;
  20367. //const nsISelectionController = Ci.nsISelectionController;
  20368. // See: http://mxr.mozilla.org/mozilla1.9.2/source/content/events/public/nsIEventStateManager.h#153
  20369. //const STATE_ACTIVE = 0x01;
  20370. //const STATE_FOCUS = 0x02;
  20371. //const STATE_HOVER = 0x04;
  20372. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20373. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20374. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20375. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20376. Firebug.SourceBoxPanel = Firebug.Panel;
  20377. var domUtils = null;
  20378. var textContent = isIE ? "innerText" : "textContent";
  20379. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20380. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20381. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20382. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20383. var CSSDomplateBase = {
  20384. isEditable: function(rule)
  20385. {
  20386. return !rule.isSystemSheet;
  20387. },
  20388. isSelectorEditable: function(rule)
  20389. {
  20390. return rule.isSelectorEditable && this.isEditable(rule);
  20391. }
  20392. };
  20393. var CSSPropTag = domplate(CSSDomplateBase, {
  20394. tag: DIV({"class": "cssProp focusRow", $disabledStyle: "$prop.disabled",
  20395. $editGroup: "$rule|isEditable",
  20396. $cssOverridden: "$prop.overridden", role : "option"},
  20397. A({"class": "cssPropDisable"}, "&nbsp;&nbsp;"),
  20398. SPAN({"class": "cssPropName", $editable: "$rule|isEditable"}, "$prop.name"),
  20399. SPAN({"class": "cssColon"}, ":"),
  20400. SPAN({"class": "cssPropValue", $editable: "$rule|isEditable"}, "$prop.value$prop.important"),
  20401. SPAN({"class": "cssSemi"}, ";")
  20402. )
  20403. });
  20404. var CSSRuleTag =
  20405. TAG("$rule.tag", {rule: "$rule"});
  20406. var CSSImportRuleTag = domplate({
  20407. tag: DIV({"class": "cssRule insertInto focusRow importRule", _repObject: "$rule.rule"},
  20408. "@import &quot;",
  20409. A({"class": "objectLink", _repObject: "$rule.rule.styleSheet"}, "$rule.rule.href"),
  20410. "&quot;;"
  20411. )
  20412. });
  20413. var CSSStyleRuleTag = domplate(CSSDomplateBase, {
  20414. tag: DIV({"class": "cssRule insertInto",
  20415. $cssEditableRule: "$rule|isEditable",
  20416. $editGroup: "$rule|isSelectorEditable",
  20417. _repObject: "$rule.rule",
  20418. "ruleId": "$rule.id", role : 'presentation'},
  20419. DIV({"class": "cssHead focusRow", role : 'listitem'},
  20420. SPAN({"class": "cssSelector", $editable: "$rule|isSelectorEditable"}, "$rule.selector"), " {"
  20421. ),
  20422. DIV({role : 'group'},
  20423. DIV({"class": "cssPropertyListBox", role : 'listbox'},
  20424. FOR("prop", "$rule.props",
  20425. TAG(CSSPropTag.tag, {rule: "$rule", prop: "$prop"})
  20426. )
  20427. )
  20428. ),
  20429. DIV({"class": "editable insertBefore", role:"presentation"}, "}")
  20430. )
  20431. });
  20432. var reSplitCSS = /(url\("?[^"\)]+?"?\))|(rgb\(.*?\))|(#[\dA-Fa-f]+)|(-?\d+(\.\d+)?(%|[a-z]{1,2})?)|([^,\s]+)|"(.*?)"/;
  20433. var reURL = /url\("?([^"\)]+)?"?\)/;
  20434. var reRepeat = /no-repeat|repeat-x|repeat-y|repeat/;
  20435. //const sothinkInstalled = !!$("swfcatcherKey_sidebar");
  20436. var sothinkInstalled = false;
  20437. var styleGroups =
  20438. {
  20439. text: [
  20440. "font-family",
  20441. "font-size",
  20442. "font-weight",
  20443. "font-style",
  20444. "color",
  20445. "text-transform",
  20446. "text-decoration",
  20447. "letter-spacing",
  20448. "word-spacing",
  20449. "line-height",
  20450. "text-align",
  20451. "vertical-align",
  20452. "direction",
  20453. "column-count",
  20454. "column-gap",
  20455. "column-width"
  20456. ],
  20457. background: [
  20458. "background-color",
  20459. "background-image",
  20460. "background-repeat",
  20461. "background-position",
  20462. "background-attachment",
  20463. "opacity"
  20464. ],
  20465. box: [
  20466. "width",
  20467. "height",
  20468. "top",
  20469. "right",
  20470. "bottom",
  20471. "left",
  20472. "margin-top",
  20473. "margin-right",
  20474. "margin-bottom",
  20475. "margin-left",
  20476. "padding-top",
  20477. "padding-right",
  20478. "padding-bottom",
  20479. "padding-left",
  20480. "border-top-width",
  20481. "border-right-width",
  20482. "border-bottom-width",
  20483. "border-left-width",
  20484. "border-top-color",
  20485. "border-right-color",
  20486. "border-bottom-color",
  20487. "border-left-color",
  20488. "border-top-style",
  20489. "border-right-style",
  20490. "border-bottom-style",
  20491. "border-left-style",
  20492. "-moz-border-top-radius",
  20493. "-moz-border-right-radius",
  20494. "-moz-border-bottom-radius",
  20495. "-moz-border-left-radius",
  20496. "outline-top-width",
  20497. "outline-right-width",
  20498. "outline-bottom-width",
  20499. "outline-left-width",
  20500. "outline-top-color",
  20501. "outline-right-color",
  20502. "outline-bottom-color",
  20503. "outline-left-color",
  20504. "outline-top-style",
  20505. "outline-right-style",
  20506. "outline-bottom-style",
  20507. "outline-left-style"
  20508. ],
  20509. layout: [
  20510. "position",
  20511. "display",
  20512. "visibility",
  20513. "z-index",
  20514. "overflow-x", // http://www.w3.org/TR/2002/WD-css3-box-20021024/#overflow
  20515. "overflow-y",
  20516. "overflow-clip",
  20517. "white-space",
  20518. "clip",
  20519. "float",
  20520. "clear",
  20521. "-moz-box-sizing"
  20522. ],
  20523. other: [
  20524. "cursor",
  20525. "list-style-image",
  20526. "list-style-position",
  20527. "list-style-type",
  20528. "marker-offset",
  20529. "user-focus",
  20530. "user-select",
  20531. "user-modify",
  20532. "user-input"
  20533. ]
  20534. };
  20535. var styleGroupTitles =
  20536. {
  20537. text: "Text",
  20538. background: "Background",
  20539. box: "Box Model",
  20540. layout: "Layout",
  20541. other: "Other"
  20542. };
  20543. Firebug.CSSModule = extend(Firebug.Module,
  20544. {
  20545. freeEdit: function(styleSheet, value)
  20546. {
  20547. if (!styleSheet.editStyleSheet)
  20548. {
  20549. var ownerNode = getStyleSheetOwnerNode(styleSheet);
  20550. styleSheet.disabled = true;
  20551. var url = CCSV("@mozilla.org/network/standard-url;1", Components.interfaces.nsIURL);
  20552. url.spec = styleSheet.href;
  20553. var editStyleSheet = ownerNode.ownerDocument.createElementNS(
  20554. "http://www.w3.org/1999/xhtml",
  20555. "style");
  20556. unwrapObject(editStyleSheet).firebugIgnore = true;
  20557. editStyleSheet.setAttribute("type", "text/css");
  20558. editStyleSheet.setAttributeNS(
  20559. "http://www.w3.org/XML/1998/namespace",
  20560. "base",
  20561. url.directory);
  20562. if (ownerNode.hasAttribute("media"))
  20563. {
  20564. editStyleSheet.setAttribute("media", ownerNode.getAttribute("media"));
  20565. }
  20566. // Insert the edited stylesheet directly after the old one to ensure the styles
  20567. // cascade properly.
  20568. ownerNode.parentNode.insertBefore(editStyleSheet, ownerNode.nextSibling);
  20569. styleSheet.editStyleSheet = editStyleSheet;
  20570. }
  20571. styleSheet.editStyleSheet.innerHTML = value;
  20572. if (FBTrace.DBG_CSS)
  20573. FBTrace.sysout("css.saveEdit styleSheet.href:"+styleSheet.href+" got innerHTML:"+value+"\n");
  20574. dispatch(this.fbListeners, "onCSSFreeEdit", [styleSheet, value]);
  20575. },
  20576. insertRule: function(styleSheet, cssText, ruleIndex)
  20577. {
  20578. if (FBTrace.DBG_CSS) FBTrace.sysout("Insert: " + ruleIndex + " " + cssText);
  20579. var insertIndex = styleSheet.insertRule(cssText, ruleIndex);
  20580. dispatch(this.fbListeners, "onCSSInsertRule", [styleSheet, cssText, ruleIndex]);
  20581. return insertIndex;
  20582. },
  20583. deleteRule: function(styleSheet, ruleIndex)
  20584. {
  20585. if (FBTrace.DBG_CSS) FBTrace.sysout("deleteRule: " + ruleIndex + " " + styleSheet.cssRules.length, styleSheet.cssRules);
  20586. dispatch(this.fbListeners, "onCSSDeleteRule", [styleSheet, ruleIndex]);
  20587. styleSheet.deleteRule(ruleIndex);
  20588. },
  20589. setProperty: function(rule, propName, propValue, propPriority)
  20590. {
  20591. var style = rule.style || rule;
  20592. // Record the original CSS text for the inline case so we can reconstruct at a later
  20593. // point for diffing purposes
  20594. var baseText = style.cssText;
  20595. // good browsers
  20596. if (style.getPropertyValue)
  20597. {
  20598. var prevValue = style.getPropertyValue(propName);
  20599. var prevPriority = style.getPropertyPriority(propName);
  20600. // XXXjoe Gecko bug workaround: Just changing priority doesn't have any effect
  20601. // unless we remove the property first
  20602. style.removeProperty(propName);
  20603. style.setProperty(propName, propValue, propPriority);
  20604. }
  20605. // sad browsers
  20606. else
  20607. {
  20608. // TODO: xxxpedro parse CSS rule to find property priority in IE?
  20609. //console.log(propName, propValue);
  20610. style[toCamelCase(propName)] = propValue;
  20611. }
  20612. if (propName) {
  20613. dispatch(this.fbListeners, "onCSSSetProperty", [style, propName, propValue, propPriority, prevValue, prevPriority, rule, baseText]);
  20614. }
  20615. },
  20616. removeProperty: function(rule, propName, parent)
  20617. {
  20618. var style = rule.style || rule;
  20619. // Record the original CSS text for the inline case so we can reconstruct at a later
  20620. // point for diffing purposes
  20621. var baseText = style.cssText;
  20622. if (style.getPropertyValue)
  20623. {
  20624. var prevValue = style.getPropertyValue(propName);
  20625. var prevPriority = style.getPropertyPriority(propName);
  20626. style.removeProperty(propName);
  20627. }
  20628. else
  20629. {
  20630. style[toCamelCase(propName)] = "";
  20631. }
  20632. if (propName) {
  20633. dispatch(this.fbListeners, "onCSSRemoveProperty", [style, propName, prevValue, prevPriority, rule, baseText]);
  20634. }
  20635. }/*,
  20636. cleanupSheets: function(doc, context)
  20637. {
  20638. // Due to the manner in which the layout engine handles multiple
  20639. // references to the same sheet we need to kick it a little bit.
  20640. // The injecting a simple stylesheet then removing it will force
  20641. // Firefox to regenerate it's CSS hierarchy.
  20642. //
  20643. // WARN: This behavior was determined anecdotally.
  20644. // See http://code.google.com/p/fbug/issues/detail?id=2440
  20645. var style = doc.createElementNS("http://www.w3.org/1999/xhtml", "style");
  20646. style.setAttribute("charset","utf-8");
  20647. unwrapObject(style).firebugIgnore = true;
  20648. style.setAttribute("type", "text/css");
  20649. style.innerHTML = "#fbIgnoreStyleDO_NOT_USE {}";
  20650. addStyleSheet(doc, style);
  20651. style.parentNode.removeChild(style);
  20652. // https://bugzilla.mozilla.org/show_bug.cgi?id=500365
  20653. // This voodoo touches each style sheet to force some Firefox internal change to allow edits.
  20654. var styleSheets = getAllStyleSheets(context);
  20655. for(var i = 0; i < styleSheets.length; i++)
  20656. {
  20657. try
  20658. {
  20659. var rules = styleSheets[i].cssRules;
  20660. if (rules.length > 0)
  20661. var touch = rules[0];
  20662. if (FBTrace.DBG_CSS && touch)
  20663. FBTrace.sysout("css.show() touch "+typeof(touch)+" in "+(styleSheets[i].href?styleSheets[i].href:context.getName()));
  20664. }
  20665. catch(e)
  20666. {
  20667. if (FBTrace.DBG_ERRORS)
  20668. FBTrace.sysout("css.show: sheet.cssRules FAILS for "+(styleSheets[i]?styleSheets[i].href:"null sheet")+e, e);
  20669. }
  20670. }
  20671. },
  20672. cleanupSheetHandler: function(event, context)
  20673. {
  20674. var target = event.target || event.srcElement,
  20675. tagName = (target.tagName || "").toLowerCase();
  20676. if (tagName == "link")
  20677. {
  20678. this.cleanupSheets(target.ownerDocument, context);
  20679. }
  20680. },
  20681. watchWindow: function(context, win)
  20682. {
  20683. var cleanupSheets = bind(this.cleanupSheets, this),
  20684. cleanupSheetHandler = bind(this.cleanupSheetHandler, this, context),
  20685. doc = win.document;
  20686. //doc.addEventListener("DOMAttrModified", cleanupSheetHandler, false);
  20687. //doc.addEventListener("DOMNodeInserted", cleanupSheetHandler, false);
  20688. },
  20689. loadedContext: function(context)
  20690. {
  20691. var self = this;
  20692. iterateWindows(context.browser.contentWindow, function(subwin)
  20693. {
  20694. self.cleanupSheets(subwin.document, context);
  20695. });
  20696. }
  20697. /**/
  20698. });
  20699. // ************************************************************************************************
  20700. Firebug.CSSStyleSheetPanel = function() {};
  20701. Firebug.CSSStyleSheetPanel.prototype = extend(Firebug.SourceBoxPanel,
  20702. {
  20703. template: domplate(
  20704. {
  20705. tag:
  20706. DIV({"class": "cssSheet insertInto a11yCSSView"},
  20707. FOR("rule", "$rules",
  20708. CSSRuleTag
  20709. ),
  20710. DIV({"class": "cssSheet editable insertBefore"}, "")
  20711. )
  20712. }),
  20713. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20714. refresh: function()
  20715. {
  20716. if (this.location)
  20717. this.updateLocation(this.location);
  20718. else if (this.selection)
  20719. this.updateSelection(this.selection);
  20720. },
  20721. toggleEditing: function()
  20722. {
  20723. if (!this.stylesheetEditor)
  20724. this.stylesheetEditor = new StyleSheetEditor(this.document);
  20725. if (this.editing)
  20726. Firebug.Editor.stopEditing();
  20727. else
  20728. {
  20729. if (!this.location)
  20730. return;
  20731. var styleSheet = this.location.editStyleSheet
  20732. ? this.location.editStyleSheet.sheet
  20733. : this.location;
  20734. var css = getStyleSheetCSS(styleSheet, this.context);
  20735. //var topmost = getTopmostRuleLine(this.panelNode);
  20736. this.stylesheetEditor.styleSheet = this.location;
  20737. Firebug.Editor.startEditing(this.panelNode, css, this.stylesheetEditor);
  20738. //this.stylesheetEditor.scrollToLine(topmost.line, topmost.offset);
  20739. }
  20740. },
  20741. getStylesheetURL: function(rule)
  20742. {
  20743. if (this.location.href)
  20744. return this.location.href;
  20745. else
  20746. return this.context.window.location.href;
  20747. },
  20748. getRuleByLine: function(styleSheet, line)
  20749. {
  20750. if (!domUtils)
  20751. return null;
  20752. var cssRules = styleSheet.cssRules;
  20753. for (var i = 0; i < cssRules.length; ++i)
  20754. {
  20755. var rule = cssRules[i];
  20756. if (rule instanceof CSSStyleRule)
  20757. {
  20758. var ruleLine = domUtils.getRuleLine(rule);
  20759. if (ruleLine >= line)
  20760. return rule;
  20761. }
  20762. }
  20763. },
  20764. highlightRule: function(rule)
  20765. {
  20766. var ruleElement = Firebug.getElementByRepObject(this.panelNode.firstChild, rule);
  20767. if (ruleElement)
  20768. {
  20769. scrollIntoCenterView(ruleElement, this.panelNode);
  20770. setClassTimed(ruleElement, "jumpHighlight", this.context);
  20771. }
  20772. },
  20773. getStyleSheetRules: function(context, styleSheet)
  20774. {
  20775. var isSystemSheet = isSystemStyleSheet(styleSheet);
  20776. function appendRules(cssRules)
  20777. {
  20778. for (var i = 0; i < cssRules.length; ++i)
  20779. {
  20780. var rule = cssRules[i];
  20781. // TODO: xxxpedro opera instanceof stylesheet remove the following comments when
  20782. // the issue with opera and style sheet Classes has been solved.
  20783. //if (rule instanceof CSSStyleRule)
  20784. if (instanceOf(rule, "CSSStyleRule"))
  20785. {
  20786. var props = this.getRuleProperties(context, rule);
  20787. //var line = domUtils.getRuleLine(rule);
  20788. var line = null;
  20789. var selector = rule.selectorText;
  20790. if (isIE)
  20791. {
  20792. selector = selector.replace(reSelectorTag,
  20793. function(s){return s.toLowerCase();});
  20794. }
  20795. var ruleId = rule.selectorText+"/"+line;
  20796. rules.push({tag: CSSStyleRuleTag.tag, rule: rule, id: ruleId,
  20797. selector: selector, props: props,
  20798. isSystemSheet: isSystemSheet,
  20799. isSelectorEditable: true});
  20800. }
  20801. //else if (rule instanceof CSSImportRule)
  20802. else if (instanceOf(rule, "CSSImportRule"))
  20803. rules.push({tag: CSSImportRuleTag.tag, rule: rule});
  20804. //else if (rule instanceof CSSMediaRule)
  20805. else if (instanceOf(rule, "CSSMediaRule"))
  20806. appendRules.apply(this, [rule.cssRules]);
  20807. else
  20808. {
  20809. if (FBTrace.DBG_ERRORS || FBTrace.DBG_CSS)
  20810. FBTrace.sysout("css getStyleSheetRules failed to classify a rule ", rule);
  20811. }
  20812. }
  20813. }
  20814. var rules = [];
  20815. appendRules.apply(this, [styleSheet.cssRules || styleSheet.rules]);
  20816. return rules;
  20817. },
  20818. parseCSSProps: function(style, inheritMode)
  20819. {
  20820. var props = [];
  20821. if (Firebug.expandShorthandProps)
  20822. {
  20823. var count = style.length-1,
  20824. index = style.length;
  20825. while (index--)
  20826. {
  20827. var propName = style.item(count - index);
  20828. this.addProperty(propName, style.getPropertyValue(propName), !!style.getPropertyPriority(propName), false, inheritMode, props);
  20829. }
  20830. }
  20831. else
  20832. {
  20833. var lines = style.cssText.match(/(?:[^;\(]*(?:\([^\)]*?\))?[^;\(]*)*;?/g);
  20834. var propRE = /\s*([^:\s]*)\s*:\s*(.*?)\s*(! important)?;?$/;
  20835. var line,i=0;
  20836. // TODO: xxxpedro port to firebug: variable leaked into global namespace
  20837. var m;
  20838. while(line=lines[i++]){
  20839. m = propRE.exec(line);
  20840. if(!m)
  20841. continue;
  20842. //var name = m[1], value = m[2], important = !!m[3];
  20843. if (m[2])
  20844. this.addProperty(m[1], m[2], !!m[3], false, inheritMode, props);
  20845. };
  20846. }
  20847. return props;
  20848. },
  20849. getRuleProperties: function(context, rule, inheritMode)
  20850. {
  20851. var props = this.parseCSSProps(rule.style, inheritMode);
  20852. // TODO: xxxpedro port to firebug: variable leaked into global namespace
  20853. //var line = domUtils.getRuleLine(rule);
  20854. var line;
  20855. var ruleId = rule.selectorText+"/"+line;
  20856. this.addOldProperties(context, ruleId, inheritMode, props);
  20857. sortProperties(props);
  20858. return props;
  20859. },
  20860. addOldProperties: function(context, ruleId, inheritMode, props)
  20861. {
  20862. if (context.selectorMap && context.selectorMap.hasOwnProperty(ruleId) )
  20863. {
  20864. var moreProps = context.selectorMap[ruleId];
  20865. for (var i = 0; i < moreProps.length; ++i)
  20866. {
  20867. var prop = moreProps[i];
  20868. this.addProperty(prop.name, prop.value, prop.important, true, inheritMode, props);
  20869. }
  20870. }
  20871. },
  20872. addProperty: function(name, value, important, disabled, inheritMode, props)
  20873. {
  20874. name = name.toLowerCase();
  20875. if (inheritMode && !inheritedStyleNames[name])
  20876. return;
  20877. name = this.translateName(name, value);
  20878. if (name)
  20879. {
  20880. value = stripUnits(rgbToHex(value));
  20881. important = important ? " !important" : "";
  20882. var prop = {name: name, value: value, important: important, disabled: disabled};
  20883. props.push(prop);
  20884. }
  20885. },
  20886. translateName: function(name, value)
  20887. {
  20888. // Don't show these proprietary Mozilla properties
  20889. if ((value == "-moz-initial"
  20890. && (name == "-moz-background-clip" || name == "-moz-background-origin"
  20891. || name == "-moz-background-inline-policy"))
  20892. || (value == "physical"
  20893. && (name == "margin-left-ltr-source" || name == "margin-left-rtl-source"
  20894. || name == "margin-right-ltr-source" || name == "margin-right-rtl-source"))
  20895. || (value == "physical"
  20896. && (name == "padding-left-ltr-source" || name == "padding-left-rtl-source"
  20897. || name == "padding-right-ltr-source" || name == "padding-right-rtl-source")))
  20898. return null;
  20899. // Translate these back to the form the user probably expects
  20900. if (name == "margin-left-value")
  20901. return "margin-left";
  20902. else if (name == "margin-right-value")
  20903. return "margin-right";
  20904. else if (name == "margin-top-value")
  20905. return "margin-top";
  20906. else if (name == "margin-bottom-value")
  20907. return "margin-bottom";
  20908. else if (name == "padding-left-value")
  20909. return "padding-left";
  20910. else if (name == "padding-right-value")
  20911. return "padding-right";
  20912. else if (name == "padding-top-value")
  20913. return "padding-top";
  20914. else if (name == "padding-bottom-value")
  20915. return "padding-bottom";
  20916. // XXXjoe What about border!
  20917. else
  20918. return name;
  20919. },
  20920. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  20921. editElementStyle: function()
  20922. {
  20923. ///var rulesBox = this.panelNode.getElementsByClassName("cssElementRuleContainer")[0];
  20924. var rulesBox = $$(".cssElementRuleContainer", this.panelNode)[0];
  20925. var styleRuleBox = rulesBox && Firebug.getElementByRepObject(rulesBox, this.selection);
  20926. if (!styleRuleBox)
  20927. {
  20928. var rule = {rule: this.selection, inherited: false, selector: "element.style", props: []};
  20929. if (!rulesBox)
  20930. {
  20931. // The element did not have any displayed styles. We need to create the whole tree and remove
  20932. // the no styles message
  20933. styleRuleBox = this.template.cascadedTag.replace({
  20934. rules: [rule], inherited: [], inheritLabel: "Inherited from" // $STR("InheritedFrom")
  20935. }, this.panelNode);
  20936. ///styleRuleBox = styleRuleBox.getElementsByClassName("cssElementRuleContainer")[0];
  20937. styleRuleBox = $$(".cssElementRuleContainer", styleRuleBox)[0];
  20938. }
  20939. else
  20940. styleRuleBox = this.template.ruleTag.insertBefore({rule: rule}, rulesBox);
  20941. ///styleRuleBox = styleRuleBox.getElementsByClassName("insertInto")[0];
  20942. styleRuleBox = $$(".insertInto", styleRuleBox)[0];
  20943. }
  20944. Firebug.Editor.insertRowForObject(styleRuleBox);
  20945. },
  20946. insertPropertyRow: function(row)
  20947. {
  20948. Firebug.Editor.insertRowForObject(row);
  20949. },
  20950. insertRule: function(row)
  20951. {
  20952. var location = getAncestorByClass(row, "cssRule");
  20953. if (!location)
  20954. {
  20955. location = getChildByClass(this.panelNode, "cssSheet");
  20956. Firebug.Editor.insertRowForObject(location);
  20957. }
  20958. else
  20959. {
  20960. Firebug.Editor.insertRow(location, "before");
  20961. }
  20962. },
  20963. editPropertyRow: function(row)
  20964. {
  20965. var propValueBox = getChildByClass(row, "cssPropValue");
  20966. Firebug.Editor.startEditing(propValueBox);
  20967. },
  20968. deletePropertyRow: function(row)
  20969. {
  20970. var rule = Firebug.getRepObject(row);
  20971. var propName = getChildByClass(row, "cssPropName")[textContent];
  20972. Firebug.CSSModule.removeProperty(rule, propName);
  20973. // Remove the property from the selector map, if it was disabled
  20974. var ruleId = Firebug.getRepNode(row).getAttribute("ruleId");
  20975. if ( this.context.selectorMap && this.context.selectorMap.hasOwnProperty(ruleId) )
  20976. {
  20977. var map = this.context.selectorMap[ruleId];
  20978. for (var i = 0; i < map.length; ++i)
  20979. {
  20980. if (map[i].name == propName)
  20981. {
  20982. map.splice(i, 1);
  20983. break;
  20984. }
  20985. }
  20986. }
  20987. if (this.name == "stylesheet")
  20988. dispatch([Firebug.A11yModel], 'onInlineEditorClose', [this, row.firstChild, true]);
  20989. row.parentNode.removeChild(row);
  20990. this.markChange(this.name == "stylesheet");
  20991. },
  20992. disablePropertyRow: function(row)
  20993. {
  20994. toggleClass(row, "disabledStyle");
  20995. var rule = Firebug.getRepObject(row);
  20996. var propName = getChildByClass(row, "cssPropName")[textContent];
  20997. if (!this.context.selectorMap)
  20998. this.context.selectorMap = {};
  20999. // XXXjoe Generate unique key for elements too
  21000. var ruleId = Firebug.getRepNode(row).getAttribute("ruleId");
  21001. if (!(this.context.selectorMap.hasOwnProperty(ruleId)))
  21002. this.context.selectorMap[ruleId] = [];
  21003. var map = this.context.selectorMap[ruleId];
  21004. var propValue = getChildByClass(row, "cssPropValue")[textContent];
  21005. var parsedValue = parsePriority(propValue);
  21006. if (hasClass(row, "disabledStyle"))
  21007. {
  21008. Firebug.CSSModule.removeProperty(rule, propName);
  21009. map.push({"name": propName, "value": parsedValue.value,
  21010. "important": parsedValue.priority});
  21011. }
  21012. else
  21013. {
  21014. Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);
  21015. var index = findPropByName(map, propName);
  21016. map.splice(index, 1);
  21017. }
  21018. this.markChange(this.name == "stylesheet");
  21019. },
  21020. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21021. onMouseDown: function(event)
  21022. {
  21023. //console.log("onMouseDown", event.target || event.srcElement, event);
  21024. // xxxpedro adjusting coordinates because the panel isn't a window yet
  21025. var offset = event.clientX - this.panelNode.parentNode.offsetLeft;
  21026. // XXjoe Hack to only allow clicking on the checkbox
  21027. if (!isLeftClick(event) || offset > 20)
  21028. return;
  21029. var target = event.target || event.srcElement;
  21030. if (hasClass(target, "textEditor"))
  21031. return;
  21032. var row = getAncestorByClass(target, "cssProp");
  21033. if (row && hasClass(row, "editGroup"))
  21034. {
  21035. this.disablePropertyRow(row);
  21036. cancelEvent(event);
  21037. }
  21038. },
  21039. onDoubleClick: function(event)
  21040. {
  21041. //console.log("onDoubleClick", event.target || event.srcElement, event);
  21042. // xxxpedro adjusting coordinates because the panel isn't a window yet
  21043. var offset = event.clientX - this.panelNode.parentNode.offsetLeft;
  21044. if (!isLeftClick(event) || offset <= 20)
  21045. return;
  21046. var target = event.target || event.srcElement;
  21047. //console.log("ok", target, hasClass(target, "textEditorInner"), !isLeftClick(event), offset <= 20);
  21048. // if the inline editor was clicked, don't insert a new rule
  21049. if (hasClass(target, "textEditorInner"))
  21050. return;
  21051. var row = getAncestorByClass(target, "cssRule");
  21052. if (row && !getAncestorByClass(target, "cssPropName")
  21053. && !getAncestorByClass(target, "cssPropValue"))
  21054. {
  21055. this.insertPropertyRow(row);
  21056. cancelEvent(event);
  21057. }
  21058. },
  21059. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21060. // extends Panel
  21061. name: "stylesheet",
  21062. title: "CSS",
  21063. parentPanel: null,
  21064. searchable: true,
  21065. dependents: ["css", "stylesheet", "dom", "domSide", "layout"],
  21066. options:
  21067. {
  21068. hasToolButtons: true
  21069. },
  21070. create: function()
  21071. {
  21072. Firebug.Panel.create.apply(this, arguments);
  21073. this.onMouseDown = bind(this.onMouseDown, this);
  21074. this.onDoubleClick = bind(this.onDoubleClick, this);
  21075. if (this.name == "stylesheet")
  21076. {
  21077. this.onChangeSelect = bind(this.onChangeSelect, this);
  21078. var doc = Firebug.browser.document;
  21079. var selectNode = this.selectNode = createElement("select");
  21080. processAllStyleSheets(doc, function(doc, styleSheet)
  21081. {
  21082. var key = StyleSheetCache.key(styleSheet);
  21083. var fileName = getFileName(styleSheet.href) || getFileName(doc.location.href);
  21084. var option = createElement("option", {value: key});
  21085. option.appendChild(Firebug.chrome.document.createTextNode(fileName));
  21086. selectNode.appendChild(option);
  21087. });
  21088. this.toolButtonsNode.appendChild(selectNode);
  21089. }
  21090. /**/
  21091. },
  21092. onChangeSelect: function(event)
  21093. {
  21094. event = event || window.event;
  21095. var target = event.srcElement || event.currentTarget;
  21096. var key = target.value;
  21097. var styleSheet = StyleSheetCache.get(key);
  21098. this.updateLocation(styleSheet);
  21099. },
  21100. initialize: function()
  21101. {
  21102. Firebug.Panel.initialize.apply(this, arguments);
  21103. //if (!domUtils)
  21104. //{
  21105. // try {
  21106. // domUtils = CCSV("@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
  21107. // } catch (exc) {
  21108. // if (FBTrace.DBG_ERRORS)
  21109. // FBTrace.sysout("@mozilla.org/inspector/dom-utils;1 FAILED to load: "+exc, exc);
  21110. // }
  21111. //}
  21112. //TODO: xxxpedro
  21113. this.context = Firebug.chrome; // TODO: xxxpedro css2
  21114. this.document = Firebug.chrome.document; // TODO: xxxpedro css2
  21115. this.initializeNode();
  21116. if (this.name == "stylesheet")
  21117. {
  21118. var styleSheets = Firebug.browser.document.styleSheets;
  21119. if (styleSheets.length > 0)
  21120. {
  21121. addEvent(this.selectNode, "change", this.onChangeSelect);
  21122. this.updateLocation(styleSheets[0]);
  21123. }
  21124. }
  21125. //Firebug.SourceBoxPanel.initialize.apply(this, arguments);
  21126. },
  21127. shutdown: function()
  21128. {
  21129. // must destroy the editor when we leave the panel to avoid problems (Issue 2981)
  21130. Firebug.Editor.stopEditing();
  21131. if (this.name == "stylesheet")
  21132. {
  21133. removeEvent(this.selectNode, "change", this.onChangeSelect);
  21134. }
  21135. this.destroyNode();
  21136. Firebug.Panel.shutdown.apply(this, arguments);
  21137. },
  21138. destroy: function(state)
  21139. {
  21140. //state.scrollTop = this.panelNode.scrollTop ? this.panelNode.scrollTop : this.lastScrollTop;
  21141. //persistObjects(this, state);
  21142. // xxxpedro we are stopping the editor in the shutdown method already
  21143. //Firebug.Editor.stopEditing();
  21144. Firebug.Panel.destroy.apply(this, arguments);
  21145. },
  21146. initializeNode: function(oldPanelNode)
  21147. {
  21148. addEvent(this.panelNode, "mousedown", this.onMouseDown);
  21149. addEvent(this.panelNode, "dblclick", this.onDoubleClick);
  21150. //Firebug.SourceBoxPanel.initializeNode.apply(this, arguments);
  21151. //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'css']);
  21152. },
  21153. destroyNode: function()
  21154. {
  21155. removeEvent(this.panelNode, "mousedown", this.onMouseDown);
  21156. removeEvent(this.panelNode, "dblclick", this.onDoubleClick);
  21157. //Firebug.SourceBoxPanel.destroyNode.apply(this, arguments);
  21158. //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'css']);
  21159. },
  21160. ishow: function(state)
  21161. {
  21162. Firebug.Inspector.stopInspecting(true);
  21163. this.showToolbarButtons("fbCSSButtons", true);
  21164. if (this.context.loaded && !this.location) // wait for loadedContext to restore the panel
  21165. {
  21166. restoreObjects(this, state);
  21167. if (!this.location)
  21168. this.location = this.getDefaultLocation();
  21169. if (state && state.scrollTop)
  21170. this.panelNode.scrollTop = state.scrollTop;
  21171. }
  21172. },
  21173. ihide: function()
  21174. {
  21175. this.showToolbarButtons("fbCSSButtons", false);
  21176. this.lastScrollTop = this.panelNode.scrollTop;
  21177. },
  21178. supportsObject: function(object)
  21179. {
  21180. if (object instanceof CSSStyleSheet)
  21181. return 1;
  21182. else if (object instanceof CSSStyleRule)
  21183. return 2;
  21184. else if (object instanceof CSSStyleDeclaration)
  21185. return 2;
  21186. else if (object instanceof SourceLink && object.type == "css" && reCSS.test(object.href))
  21187. return 2;
  21188. else
  21189. return 0;
  21190. },
  21191. updateLocation: function(styleSheet)
  21192. {
  21193. if (!styleSheet)
  21194. return;
  21195. if (styleSheet.editStyleSheet)
  21196. styleSheet = styleSheet.editStyleSheet.sheet;
  21197. // if it is a restricted stylesheet, show the warning message and abort the update process
  21198. if (styleSheet.restricted)
  21199. {
  21200. FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, this.panelNode);
  21201. // TODO: xxxpedro remove when there the external resource problem is fixed
  21202. externalStyleSheetWarning.tag.append({
  21203. object: "The stylesheet could not be loaded due to access restrictions. ",
  21204. link: "more...",
  21205. href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22Access_to_restricted_URI_denied.22"
  21206. }, this.panelNode);
  21207. return;
  21208. }
  21209. var rules = this.getStyleSheetRules(this.context, styleSheet);
  21210. var result;
  21211. if (rules.length)
  21212. result = this.template.tag.replace({rules: rules}, this.panelNode);
  21213. else
  21214. result = FirebugReps.Warning.tag.replace({object: "EmptyStyleSheet"}, this.panelNode);
  21215. // TODO: xxxpedro need to fix showToolbarButtons function
  21216. //this.showToolbarButtons("fbCSSButtons", !isSystemStyleSheet(this.location));
  21217. //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, this.panelNode]);
  21218. },
  21219. updateSelection: function(object)
  21220. {
  21221. this.selection = null;
  21222. if (object instanceof CSSStyleDeclaration) {
  21223. object = object.parentRule;
  21224. }
  21225. if (object instanceof CSSStyleRule)
  21226. {
  21227. this.navigate(object.parentStyleSheet);
  21228. this.highlightRule(object);
  21229. }
  21230. else if (object instanceof CSSStyleSheet)
  21231. {
  21232. this.navigate(object);
  21233. }
  21234. else if (object instanceof SourceLink)
  21235. {
  21236. try
  21237. {
  21238. var sourceLink = object;
  21239. var sourceFile = getSourceFileByHref(sourceLink.href, this.context);
  21240. if (sourceFile)
  21241. {
  21242. clearNode(this.panelNode); // replace rendered stylesheets
  21243. this.showSourceFile(sourceFile);
  21244. var lineNo = object.line;
  21245. if (lineNo)
  21246. this.scrollToLine(lineNo, this.jumpHighlightFactory(lineNo, this.context));
  21247. }
  21248. else // XXXjjb we should not be taking this path
  21249. {
  21250. var stylesheet = getStyleSheetByHref(sourceLink.href, this.context);
  21251. if (stylesheet)
  21252. this.navigate(stylesheet);
  21253. else
  21254. {
  21255. if (FBTrace.DBG_CSS)
  21256. FBTrace.sysout("css.updateSelection no sourceFile for "+sourceLink.href, sourceLink);
  21257. }
  21258. }
  21259. }
  21260. catch(exc) {
  21261. if (FBTrace.DBG_CSS)
  21262. FBTrace.sysout("css.upDateSelection FAILS "+exc, exc);
  21263. }
  21264. }
  21265. },
  21266. updateOption: function(name, value)
  21267. {
  21268. if (name == "expandShorthandProps")
  21269. this.refresh();
  21270. },
  21271. getLocationList: function()
  21272. {
  21273. var styleSheets = getAllStyleSheets(this.context);
  21274. return styleSheets;
  21275. },
  21276. getOptionsMenuItems: function()
  21277. {
  21278. return [
  21279. {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps,
  21280. command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") },
  21281. "-",
  21282. {label: "Refresh", command: bind(this.refresh, this) }
  21283. ];
  21284. },
  21285. getContextMenuItems: function(style, target)
  21286. {
  21287. var items = [];
  21288. if (this.infoTipType == "color")
  21289. {
  21290. items.push(
  21291. {label: "CopyColor",
  21292. command: bindFixed(copyToClipboard, FBL, this.infoTipObject) }
  21293. );
  21294. }
  21295. else if (this.infoTipType == "image")
  21296. {
  21297. items.push(
  21298. {label: "CopyImageLocation",
  21299. command: bindFixed(copyToClipboard, FBL, this.infoTipObject) },
  21300. {label: "OpenImageInNewTab",
  21301. command: bindFixed(openNewTab, FBL, this.infoTipObject) }
  21302. );
  21303. }
  21304. ///if (this.selection instanceof Element)
  21305. if (isElement(this.selection))
  21306. {
  21307. items.push(
  21308. //"-",
  21309. {label: "EditStyle",
  21310. command: bindFixed(this.editElementStyle, this) }
  21311. );
  21312. }
  21313. else if (!isSystemStyleSheet(this.selection))
  21314. {
  21315. items.push(
  21316. //"-",
  21317. {label: "NewRule",
  21318. command: bindFixed(this.insertRule, this, target) }
  21319. );
  21320. }
  21321. var cssRule = getAncestorByClass(target, "cssRule");
  21322. if (cssRule && hasClass(cssRule, "cssEditableRule"))
  21323. {
  21324. items.push(
  21325. "-",
  21326. {label: "NewProp",
  21327. command: bindFixed(this.insertPropertyRow, this, target) }
  21328. );
  21329. var propRow = getAncestorByClass(target, "cssProp");
  21330. if (propRow)
  21331. {
  21332. var propName = getChildByClass(propRow, "cssPropName")[textContent];
  21333. var isDisabled = hasClass(propRow, "disabledStyle");
  21334. items.push(
  21335. {label: $STRF("EditProp", [propName]), nol10n: true,
  21336. command: bindFixed(this.editPropertyRow, this, propRow) },
  21337. {label: $STRF("DeleteProp", [propName]), nol10n: true,
  21338. command: bindFixed(this.deletePropertyRow, this, propRow) },
  21339. {label: $STRF("DisableProp", [propName]), nol10n: true,
  21340. type: "checkbox", checked: isDisabled,
  21341. command: bindFixed(this.disablePropertyRow, this, propRow) }
  21342. );
  21343. }
  21344. }
  21345. items.push(
  21346. "-",
  21347. {label: "Refresh", command: bind(this.refresh, this) }
  21348. );
  21349. return items;
  21350. },
  21351. browseObject: function(object)
  21352. {
  21353. if (this.infoTipType == "image")
  21354. {
  21355. openNewTab(this.infoTipObject);
  21356. return true;
  21357. }
  21358. },
  21359. showInfoTip: function(infoTip, target, x, y)
  21360. {
  21361. var propValue = getAncestorByClass(target, "cssPropValue");
  21362. if (propValue)
  21363. {
  21364. var offset = getClientOffset(propValue);
  21365. var offsetX = x-offset.x;
  21366. var text = propValue[textContent];
  21367. var charWidth = propValue.offsetWidth/text.length;
  21368. var charOffset = Math.floor(offsetX/charWidth);
  21369. var cssValue = parseCSSValue(text, charOffset);
  21370. if (cssValue)
  21371. {
  21372. if (cssValue.value == this.infoTipValue)
  21373. return true;
  21374. this.infoTipValue = cssValue.value;
  21375. if (cssValue.type == "rgb" || (!cssValue.type && isColorKeyword(cssValue.value)))
  21376. {
  21377. this.infoTipType = "color";
  21378. this.infoTipObject = cssValue.value;
  21379. return Firebug.InfoTip.populateColorInfoTip(infoTip, cssValue.value);
  21380. }
  21381. else if (cssValue.type == "url")
  21382. {
  21383. ///var propNameNode = target.parentNode.getElementsByClassName("cssPropName").item(0);
  21384. var propNameNode = getElementByClass(target.parentNode, "cssPropName");
  21385. if (propNameNode && isImageRule(propNameNode[textContent]))
  21386. {
  21387. var rule = Firebug.getRepObject(target);
  21388. var baseURL = this.getStylesheetURL(rule);
  21389. var relURL = parseURLValue(cssValue.value);
  21390. var absURL = isDataURL(relURL) ? relURL:absoluteURL(relURL, baseURL);
  21391. var repeat = parseRepeatValue(text);
  21392. this.infoTipType = "image";
  21393. this.infoTipObject = absURL;
  21394. return Firebug.InfoTip.populateImageInfoTip(infoTip, absURL, repeat);
  21395. }
  21396. }
  21397. }
  21398. }
  21399. delete this.infoTipType;
  21400. delete this.infoTipValue;
  21401. delete this.infoTipObject;
  21402. },
  21403. getEditor: function(target, value)
  21404. {
  21405. if (target == this.panelNode
  21406. || hasClass(target, "cssSelector") || hasClass(target, "cssRule")
  21407. || hasClass(target, "cssSheet"))
  21408. {
  21409. if (!this.ruleEditor)
  21410. this.ruleEditor = new CSSRuleEditor(this.document);
  21411. return this.ruleEditor;
  21412. }
  21413. else
  21414. {
  21415. if (!this.editor)
  21416. this.editor = new CSSEditor(this.document);
  21417. return this.editor;
  21418. }
  21419. },
  21420. getDefaultLocation: function()
  21421. {
  21422. try
  21423. {
  21424. var styleSheets = this.context.window.document.styleSheets;
  21425. if (styleSheets.length)
  21426. {
  21427. var sheet = styleSheets[0];
  21428. return (Firebug.filterSystemURLs && isSystemURL(getURLForStyleSheet(sheet))) ? null : sheet;
  21429. }
  21430. }
  21431. catch (exc)
  21432. {
  21433. if (FBTrace.DBG_LOCATIONS)
  21434. FBTrace.sysout("css.getDefaultLocation FAILS "+exc, exc);
  21435. }
  21436. },
  21437. getObjectDescription: function(styleSheet)
  21438. {
  21439. var url = getURLForStyleSheet(styleSheet);
  21440. var instance = getInstanceForStyleSheet(styleSheet);
  21441. var baseDescription = splitURLBase(url);
  21442. if (instance) {
  21443. baseDescription.name = baseDescription.name + " #" + (instance + 1);
  21444. }
  21445. return baseDescription;
  21446. },
  21447. search: function(text, reverse)
  21448. {
  21449. var curDoc = this.searchCurrentDoc(!Firebug.searchGlobal, text, reverse);
  21450. if (!curDoc && Firebug.searchGlobal)
  21451. {
  21452. return this.searchOtherDocs(text, reverse);
  21453. }
  21454. return curDoc;
  21455. },
  21456. searchOtherDocs: function(text, reverse)
  21457. {
  21458. var scanRE = Firebug.Search.getTestingRegex(text);
  21459. function scanDoc(styleSheet) {
  21460. // we don't care about reverse here as we are just looking for existence,
  21461. // if we do have a result we will handle the reverse logic on display
  21462. for (var i = 0; i < styleSheet.cssRules.length; i++)
  21463. {
  21464. if (scanRE.test(styleSheet.cssRules[i].cssText))
  21465. {
  21466. return true;
  21467. }
  21468. }
  21469. }
  21470. if (this.navigateToNextDocument(scanDoc, reverse))
  21471. {
  21472. return this.searchCurrentDoc(true, text, reverse);
  21473. }
  21474. },
  21475. searchCurrentDoc: function(wrapSearch, text, reverse)
  21476. {
  21477. if (!text)
  21478. {
  21479. delete this.currentSearch;
  21480. return false;
  21481. }
  21482. var row;
  21483. if (this.currentSearch && text == this.currentSearch.text)
  21484. {
  21485. row = this.currentSearch.findNext(wrapSearch, false, reverse, Firebug.Search.isCaseSensitive(text));
  21486. }
  21487. else
  21488. {
  21489. if (this.editing)
  21490. {
  21491. this.currentSearch = new TextSearch(this.stylesheetEditor.box);
  21492. row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text));
  21493. if (row)
  21494. {
  21495. var sel = this.document.defaultView.getSelection();
  21496. sel.removeAllRanges();
  21497. sel.addRange(this.currentSearch.range);
  21498. scrollSelectionIntoView(this);
  21499. return true;
  21500. }
  21501. else
  21502. return false;
  21503. }
  21504. else
  21505. {
  21506. function findRow(node) { return node.nodeType == 1 ? node : node.parentNode; }
  21507. this.currentSearch = new TextSearch(this.panelNode, findRow);
  21508. row = this.currentSearch.find(text, reverse, Firebug.Search.isCaseSensitive(text));
  21509. }
  21510. }
  21511. if (row)
  21512. {
  21513. this.document.defaultView.getSelection().selectAllChildren(row);
  21514. scrollIntoCenterView(row, this.panelNode);
  21515. dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, row]);
  21516. return true;
  21517. }
  21518. else
  21519. {
  21520. dispatch([Firebug.A11yModel], 'onCSSSearchMatchFound', [this, text, null]);
  21521. return false;
  21522. }
  21523. },
  21524. getSearchOptionsMenuItems: function()
  21525. {
  21526. return [
  21527. Firebug.Search.searchOptionMenu("search.Case_Sensitive", "searchCaseSensitive"),
  21528. Firebug.Search.searchOptionMenu("search.Multiple_Files", "searchGlobal")
  21529. ];
  21530. }
  21531. });
  21532. /**/
  21533. // ************************************************************************************************
  21534. function CSSElementPanel() {}
  21535. CSSElementPanel.prototype = extend(Firebug.CSSStyleSheetPanel.prototype,
  21536. {
  21537. template: domplate(
  21538. {
  21539. cascadedTag:
  21540. DIV({"class": "a11yCSSView", role : 'presentation'},
  21541. DIV({role : 'list', 'aria-label' : $STR('aria.labels.style rules') },
  21542. FOR("rule", "$rules",
  21543. TAG("$ruleTag", {rule: "$rule"})
  21544. )
  21545. ),
  21546. DIV({role : "list", 'aria-label' :$STR('aria.labels.inherited style rules')},
  21547. FOR("section", "$inherited",
  21548. H1({"class": "cssInheritHeader groupHeader focusRow", role : 'listitem' },
  21549. SPAN({"class": "cssInheritLabel"}, "$inheritLabel"),
  21550. TAG(FirebugReps.Element.shortTag, {object: "$section.element"})
  21551. ),
  21552. DIV({role : 'group'},
  21553. FOR("rule", "$section.rules",
  21554. TAG("$ruleTag", {rule: "$rule"})
  21555. )
  21556. )
  21557. )
  21558. )
  21559. ),
  21560. ruleTag:
  21561. isIE ?
  21562. // IE needs the sourceLink first, otherwise it will be rendered outside the panel
  21563. DIV({"class": "cssElementRuleContainer"},
  21564. TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"}),
  21565. TAG(CSSStyleRuleTag.tag, {rule: "$rule"})
  21566. )
  21567. :
  21568. // other browsers need the sourceLink last, otherwise it will cause an extra space
  21569. // before the rule representation
  21570. DIV({"class": "cssElementRuleContainer"},
  21571. TAG(CSSStyleRuleTag.tag, {rule: "$rule"}),
  21572. TAG(FirebugReps.SourceLink.tag, {object: "$rule.sourceLink"})
  21573. )
  21574. }),
  21575. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21576. updateCascadeView: function(element)
  21577. {
  21578. //dispatch([Firebug.A11yModel], 'onBeforeCSSRulesAdded', [this]);
  21579. var rules = [], sections = [], usedProps = {};
  21580. this.getInheritedRules(element, sections, usedProps);
  21581. this.getElementRules(element, rules, usedProps);
  21582. if (rules.length || sections.length)
  21583. {
  21584. var inheritLabel = "Inherited from"; // $STR("InheritedFrom");
  21585. var result = this.template.cascadedTag.replace({rules: rules, inherited: sections,
  21586. inheritLabel: inheritLabel}, this.panelNode);
  21587. //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
  21588. }
  21589. else
  21590. {
  21591. var result = FirebugReps.Warning.tag.replace({object: "EmptyElementCSS"}, this.panelNode);
  21592. //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
  21593. }
  21594. // TODO: xxxpedro remove when there the external resource problem is fixed
  21595. if (externalStyleSheetURLs.length > 0)
  21596. externalStyleSheetWarning.tag.append({
  21597. object: "The results here may be inaccurate because some " +
  21598. "stylesheets could not be loaded due to access restrictions. ",
  21599. link: "more...",
  21600. href: "http://getfirebug.com/wiki/index.php/Firebug_Lite_FAQ#I_keep_seeing_.22This_element_has_no_style_rules.22"
  21601. }, this.panelNode);
  21602. },
  21603. getStylesheetURL: function(rule)
  21604. {
  21605. // if the parentStyleSheet.href is null, CSS std says its inline style.
  21606. // TODO: xxxpedro IE doesn't have rule.parentStyleSheet so we must fall back to the doc.location
  21607. if (rule && rule.parentStyleSheet && rule.parentStyleSheet.href)
  21608. return rule.parentStyleSheet.href;
  21609. else
  21610. return this.selection.ownerDocument.location.href;
  21611. },
  21612. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21613. getInheritedRules: function(element, sections, usedProps)
  21614. {
  21615. var parent = element.parentNode;
  21616. if (parent && parent.nodeType == 1)
  21617. {
  21618. this.getInheritedRules(parent, sections, usedProps);
  21619. var rules = [];
  21620. this.getElementRules(parent, rules, usedProps, true);
  21621. if (rules.length)
  21622. sections.splice(0, 0, {element: parent, rules: rules});
  21623. }
  21624. },
  21625. getElementRules: function(element, rules, usedProps, inheritMode)
  21626. {
  21627. var inspectedRules, displayedRules = {};
  21628. // TODO: xxxpedro remove document specificity issue
  21629. //var eid = ElementCache(element);
  21630. //inspectedRules = ElementCSSRulesMap[eid];
  21631. inspectedRules = getElementCSSRules(element);
  21632. if (inspectedRules)
  21633. {
  21634. for (var i = 0, length=inspectedRules.length; i < length; ++i)
  21635. {
  21636. var ruleId = inspectedRules[i];
  21637. var ruleData = CSSRuleMap[ruleId];
  21638. var rule = ruleData.rule;
  21639. var ssid = ruleData.styleSheetId;
  21640. var parentStyleSheet = StyleSheetCache.get(ssid);
  21641. var href = parentStyleSheet.externalURL ? parentStyleSheet.externalURL : parentStyleSheet.href; // Null means inline
  21642. var instance = null;
  21643. //var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument);
  21644. var isSystemSheet = false;
  21645. //var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet);
  21646. if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules
  21647. continue;
  21648. if (!href)
  21649. href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452
  21650. var props = this.getRuleProperties(this.context, rule, inheritMode);
  21651. if (inheritMode && !props.length)
  21652. continue;
  21653. //
  21654. //var line = domUtils.getRuleLine(rule);
  21655. var line;
  21656. var ruleId = rule.selectorText+"/"+line;
  21657. var sourceLink = new SourceLink(href, line, "css", rule, instance);
  21658. this.markOverridenProps(props, usedProps, inheritMode);
  21659. rules.splice(0, 0, {rule: rule, id: ruleId,
  21660. selector: ruleData.selector, sourceLink: sourceLink,
  21661. props: props, inherited: inheritMode,
  21662. isSystemSheet: isSystemSheet});
  21663. }
  21664. }
  21665. if (element.style)
  21666. this.getStyleProperties(element, rules, usedProps, inheritMode);
  21667. if (FBTrace.DBG_CSS)
  21668. FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules);
  21669. },
  21670. /*
  21671. getElementRules: function(element, rules, usedProps, inheritMode)
  21672. {
  21673. var inspectedRules, displayedRules = {};
  21674. try
  21675. {
  21676. inspectedRules = domUtils ? domUtils.getCSSStyleRules(element) : null;
  21677. } catch (exc) {}
  21678. if (inspectedRules)
  21679. {
  21680. for (var i = 0; i < inspectedRules.Count(); ++i)
  21681. {
  21682. var rule = QI(inspectedRules.GetElementAt(i), nsIDOMCSSStyleRule);
  21683. var href = rule.parentStyleSheet.href; // Null means inline
  21684. var instance = getInstanceForStyleSheet(rule.parentStyleSheet, element.ownerDocument);
  21685. var isSystemSheet = isSystemStyleSheet(rule.parentStyleSheet);
  21686. if (!Firebug.showUserAgentCSS && isSystemSheet) // This removes user agent rules
  21687. continue;
  21688. if (!href)
  21689. href = element.ownerDocument.location.href; // http://code.google.com/p/fbug/issues/detail?id=452
  21690. var props = this.getRuleProperties(this.context, rule, inheritMode);
  21691. if (inheritMode && !props.length)
  21692. continue;
  21693. var line = domUtils.getRuleLine(rule);
  21694. var ruleId = rule.selectorText+"/"+line;
  21695. var sourceLink = new SourceLink(href, line, "css", rule, instance);
  21696. this.markOverridenProps(props, usedProps, inheritMode);
  21697. rules.splice(0, 0, {rule: rule, id: ruleId,
  21698. selector: rule.selectorText, sourceLink: sourceLink,
  21699. props: props, inherited: inheritMode,
  21700. isSystemSheet: isSystemSheet});
  21701. }
  21702. }
  21703. if (element.style)
  21704. this.getStyleProperties(element, rules, usedProps, inheritMode);
  21705. if (FBTrace.DBG_CSS)
  21706. FBTrace.sysout("getElementRules "+rules.length+" rules for "+getElementXPath(element), rules);
  21707. },
  21708. /**/
  21709. markOverridenProps: function(props, usedProps, inheritMode)
  21710. {
  21711. for (var i = 0; i < props.length; ++i)
  21712. {
  21713. var prop = props[i];
  21714. if ( usedProps.hasOwnProperty(prop.name) )
  21715. {
  21716. var deadProps = usedProps[prop.name]; // all previous occurrences of this property
  21717. for (var j = 0; j < deadProps.length; ++j)
  21718. {
  21719. var deadProp = deadProps[j];
  21720. if (!deadProp.disabled && !deadProp.wasInherited && deadProp.important && !prop.important)
  21721. prop.overridden = true; // new occurrence overridden
  21722. else if (!prop.disabled)
  21723. deadProp.overridden = true; // previous occurrences overridden
  21724. }
  21725. }
  21726. else
  21727. usedProps[prop.name] = [];
  21728. prop.wasInherited = inheritMode ? true : false;
  21729. usedProps[prop.name].push(prop); // all occurrences of a property seen so far, by name
  21730. }
  21731. },
  21732. getStyleProperties: function(element, rules, usedProps, inheritMode)
  21733. {
  21734. var props = this.parseCSSProps(element.style, inheritMode);
  21735. this.addOldProperties(this.context, getElementXPath(element), inheritMode, props);
  21736. sortProperties(props);
  21737. this.markOverridenProps(props, usedProps, inheritMode);
  21738. if (props.length)
  21739. rules.splice(0, 0,
  21740. {rule: element, id: getElementXPath(element),
  21741. selector: "element.style", props: props, inherited: inheritMode});
  21742. },
  21743. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21744. // extends Panel
  21745. name: "css",
  21746. title: "Style",
  21747. parentPanel: "HTML",
  21748. order: 0,
  21749. initialize: function()
  21750. {
  21751. this.context = Firebug.chrome; // TODO: xxxpedro css2
  21752. this.document = Firebug.chrome.document; // TODO: xxxpedro css2
  21753. Firebug.CSSStyleSheetPanel.prototype.initialize.apply(this, arguments);
  21754. // TODO: xxxpedro css2
  21755. var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId);
  21756. if (selection)
  21757. this.select(selection, true);
  21758. //this.updateCascadeView(document.getElementsByTagName("h1")[0]);
  21759. //this.updateCascadeView(document.getElementById("build"));
  21760. /*
  21761. this.onStateChange = bindFixed(this.contentStateCheck, this);
  21762. this.onHoverChange = bindFixed(this.contentStateCheck, this, STATE_HOVER);
  21763. this.onActiveChange = bindFixed(this.contentStateCheck, this, STATE_ACTIVE);
  21764. /**/
  21765. },
  21766. ishow: function(state)
  21767. {
  21768. },
  21769. watchWindow: function(win)
  21770. {
  21771. if (domUtils)
  21772. {
  21773. // Normally these would not be required, but in order to update after the state is set
  21774. // using the options menu we need to monitor these global events as well
  21775. var doc = win.document;
  21776. ///addEvent(doc, "mouseover", this.onHoverChange);
  21777. ///addEvent(doc, "mousedown", this.onActiveChange);
  21778. }
  21779. },
  21780. unwatchWindow: function(win)
  21781. {
  21782. var doc = win.document;
  21783. ///removeEvent(doc, "mouseover", this.onHoverChange);
  21784. ///removeEvent(doc, "mousedown", this.onActiveChange);
  21785. if (isAncestor(this.stateChangeEl, doc))
  21786. {
  21787. this.removeStateChangeHandlers();
  21788. }
  21789. },
  21790. supportsObject: function(object)
  21791. {
  21792. return object instanceof Element ? 1 : 0;
  21793. },
  21794. updateView: function(element)
  21795. {
  21796. this.updateCascadeView(element);
  21797. if (domUtils)
  21798. {
  21799. this.contentState = safeGetContentState(element);
  21800. this.addStateChangeHandlers(element);
  21801. }
  21802. },
  21803. updateSelection: function(element)
  21804. {
  21805. if ( !instanceOf(element , "Element") ) // html supports SourceLink
  21806. return;
  21807. if (sothinkInstalled)
  21808. {
  21809. FirebugReps.Warning.tag.replace({object: "SothinkWarning"}, this.panelNode);
  21810. return;
  21811. }
  21812. /*
  21813. if (!domUtils)
  21814. {
  21815. FirebugReps.Warning.tag.replace({object: "DOMInspectorWarning"}, this.panelNode);
  21816. return;
  21817. }
  21818. /**/
  21819. if (!element)
  21820. return;
  21821. this.updateView(element);
  21822. },
  21823. updateOption: function(name, value)
  21824. {
  21825. if (name == "showUserAgentCSS" || name == "expandShorthandProps")
  21826. this.refresh();
  21827. },
  21828. getOptionsMenuItems: function()
  21829. {
  21830. var ret = [
  21831. {label: "Show User Agent CSS", type: "checkbox", checked: Firebug.showUserAgentCSS,
  21832. command: bindFixed(Firebug.togglePref, Firebug, "showUserAgentCSS") },
  21833. {label: "Expand Shorthand Properties", type: "checkbox", checked: Firebug.expandShorthandProps,
  21834. command: bindFixed(Firebug.togglePref, Firebug, "expandShorthandProps") }
  21835. ];
  21836. if (domUtils && this.selection)
  21837. {
  21838. var state = safeGetContentState(this.selection);
  21839. ret.push("-");
  21840. ret.push({label: ":active", type: "checkbox", checked: state & STATE_ACTIVE,
  21841. command: bindFixed(this.updateContentState, this, STATE_ACTIVE, state & STATE_ACTIVE)});
  21842. ret.push({label: ":hover", type: "checkbox", checked: state & STATE_HOVER,
  21843. command: bindFixed(this.updateContentState, this, STATE_HOVER, state & STATE_HOVER)});
  21844. }
  21845. return ret;
  21846. },
  21847. updateContentState: function(state, remove)
  21848. {
  21849. domUtils.setContentState(remove ? this.selection.ownerDocument.documentElement : this.selection, state);
  21850. this.refresh();
  21851. },
  21852. addStateChangeHandlers: function(el)
  21853. {
  21854. this.removeStateChangeHandlers();
  21855. /*
  21856. addEvent(el, "focus", this.onStateChange);
  21857. addEvent(el, "blur", this.onStateChange);
  21858. addEvent(el, "mouseup", this.onStateChange);
  21859. addEvent(el, "mousedown", this.onStateChange);
  21860. addEvent(el, "mouseover", this.onStateChange);
  21861. addEvent(el, "mouseout", this.onStateChange);
  21862. /**/
  21863. this.stateChangeEl = el;
  21864. },
  21865. removeStateChangeHandlers: function()
  21866. {
  21867. var sel = this.stateChangeEl;
  21868. if (sel)
  21869. {
  21870. /*
  21871. removeEvent(sel, "focus", this.onStateChange);
  21872. removeEvent(sel, "blur", this.onStateChange);
  21873. removeEvent(sel, "mouseup", this.onStateChange);
  21874. removeEvent(sel, "mousedown", this.onStateChange);
  21875. removeEvent(sel, "mouseover", this.onStateChange);
  21876. removeEvent(sel, "mouseout", this.onStateChange);
  21877. /**/
  21878. }
  21879. },
  21880. contentStateCheck: function(state)
  21881. {
  21882. if (!state || this.contentState & state)
  21883. {
  21884. var timeoutRunner = bindFixed(function()
  21885. {
  21886. var newState = safeGetContentState(this.selection);
  21887. if (newState != this.contentState)
  21888. {
  21889. this.context.invalidatePanels(this.name);
  21890. }
  21891. }, this);
  21892. // Delay exec until after the event has processed and the state has been updated
  21893. setTimeout(timeoutRunner, 0);
  21894. }
  21895. }
  21896. });
  21897. function safeGetContentState(selection)
  21898. {
  21899. try
  21900. {
  21901. return domUtils.getContentState(selection);
  21902. }
  21903. catch (e)
  21904. {
  21905. if (FBTrace.DBG_ERRORS)
  21906. FBTrace.sysout("css.safeGetContentState; EXCEPTION", e);
  21907. }
  21908. }
  21909. // ************************************************************************************************
  21910. function CSSComputedElementPanel() {}
  21911. CSSComputedElementPanel.prototype = extend(CSSElementPanel.prototype,
  21912. {
  21913. template: domplate(
  21914. {
  21915. computedTag:
  21916. DIV({"class": "a11yCSSView", role : "list", "aria-label" : $STR('aria.labels.computed styles')},
  21917. FOR("group", "$groups",
  21918. H1({"class": "cssInheritHeader groupHeader focusRow", role : "listitem"},
  21919. SPAN({"class": "cssInheritLabel"}, "$group.title")
  21920. ),
  21921. TABLE({width: "100%", role : 'group'},
  21922. TBODY({role : 'presentation'},
  21923. FOR("prop", "$group.props",
  21924. TR({"class": 'focusRow computedStyleRow', role : 'listitem'},
  21925. TD({"class": "stylePropName", role : 'presentation'}, "$prop.name"),
  21926. TD({"class": "stylePropValue", role : 'presentation'}, "$prop.value")
  21927. )
  21928. )
  21929. )
  21930. )
  21931. )
  21932. )
  21933. }),
  21934. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21935. updateComputedView: function(element)
  21936. {
  21937. var win = isIE ?
  21938. element.ownerDocument.parentWindow :
  21939. element.ownerDocument.defaultView;
  21940. var style = isIE ?
  21941. element.currentStyle :
  21942. win.getComputedStyle(element, "");
  21943. var groups = [];
  21944. for (var groupName in styleGroups)
  21945. {
  21946. // TODO: xxxpedro i18n $STR
  21947. //var title = $STR("StyleGroup-" + groupName);
  21948. var title = styleGroupTitles[groupName];
  21949. var group = {title: title, props: []};
  21950. groups.push(group);
  21951. var props = styleGroups[groupName];
  21952. for (var i = 0; i < props.length; ++i)
  21953. {
  21954. var propName = props[i];
  21955. var propValue = style.getPropertyValue ?
  21956. style.getPropertyValue(propName) :
  21957. ""+style[toCamelCase(propName)];
  21958. if (propValue === undefined || propValue === null)
  21959. continue;
  21960. propValue = stripUnits(rgbToHex(propValue));
  21961. if (propValue)
  21962. group.props.push({name: propName, value: propValue});
  21963. }
  21964. }
  21965. var result = this.template.computedTag.replace({groups: groups}, this.panelNode);
  21966. //dispatch([Firebug.A11yModel], 'onCSSRulesAdded', [this, result]);
  21967. },
  21968. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  21969. // extends Panel
  21970. name: "computed",
  21971. title: "Computed",
  21972. parentPanel: "HTML",
  21973. order: 1,
  21974. updateView: function(element)
  21975. {
  21976. this.updateComputedView(element);
  21977. },
  21978. getOptionsMenuItems: function()
  21979. {
  21980. return [
  21981. {label: "Refresh", command: bind(this.refresh, this) }
  21982. ];
  21983. }
  21984. });
  21985. // ************************************************************************************************
  21986. // CSSEditor
  21987. function CSSEditor(doc)
  21988. {
  21989. this.initializeInline(doc);
  21990. }
  21991. CSSEditor.prototype = domplate(Firebug.InlineEditor.prototype,
  21992. {
  21993. insertNewRow: function(target, insertWhere)
  21994. {
  21995. var rule = Firebug.getRepObject(target);
  21996. var emptyProp =
  21997. {
  21998. // TODO: xxxpedro - uses charCode(255) to force the element being rendered,
  21999. // allowing webkit to get the correct position of the property name "span",
  22000. // when inserting a new CSS rule?
  22001. name: "",
  22002. value: "",
  22003. important: ""
  22004. };
  22005. if (insertWhere == "before")
  22006. return CSSPropTag.tag.insertBefore({prop: emptyProp, rule: rule}, target);
  22007. else
  22008. return CSSPropTag.tag.insertAfter({prop: emptyProp, rule: rule}, target);
  22009. },
  22010. saveEdit: function(target, value, previousValue)
  22011. {
  22012. // We need to check the value first in order to avoid a problem in IE8
  22013. // See Issue 3038: Empty (null) styles when adding CSS styles in Firebug Lite
  22014. if (!value) return;
  22015. target.innerHTML = escapeForCss(value);
  22016. var row = getAncestorByClass(target, "cssProp");
  22017. if (hasClass(row, "disabledStyle"))
  22018. toggleClass(row, "disabledStyle");
  22019. var rule = Firebug.getRepObject(target);
  22020. if (hasClass(target, "cssPropName"))
  22021. {
  22022. if (value && previousValue != value) // name of property has changed.
  22023. {
  22024. var propValue = getChildByClass(row, "cssPropValue")[textContent];
  22025. var parsedValue = parsePriority(propValue);
  22026. if (propValue && propValue != "undefined") {
  22027. if (FBTrace.DBG_CSS)
  22028. FBTrace.sysout("CSSEditor.saveEdit : "+previousValue+"->"+value+" = "+propValue+"\n");
  22029. if (previousValue)
  22030. Firebug.CSSModule.removeProperty(rule, previousValue);
  22031. Firebug.CSSModule.setProperty(rule, value, parsedValue.value, parsedValue.priority);
  22032. }
  22033. }
  22034. else if (!value) // name of the property has been deleted, so remove the property.
  22035. Firebug.CSSModule.removeProperty(rule, previousValue);
  22036. }
  22037. else if (getAncestorByClass(target, "cssPropValue"))
  22038. {
  22039. var propName = getChildByClass(row, "cssPropName")[textContent];
  22040. var propValue = getChildByClass(row, "cssPropValue")[textContent];
  22041. if (FBTrace.DBG_CSS)
  22042. {
  22043. FBTrace.sysout("CSSEditor.saveEdit propName=propValue: "+propName +" = "+propValue+"\n");
  22044. // FBTrace.sysout("CSSEditor.saveEdit BEFORE style:",style);
  22045. }
  22046. if (value && value != "null")
  22047. {
  22048. var parsedValue = parsePriority(value);
  22049. Firebug.CSSModule.setProperty(rule, propName, parsedValue.value, parsedValue.priority);
  22050. }
  22051. else if (previousValue && previousValue != "null")
  22052. Firebug.CSSModule.removeProperty(rule, propName);
  22053. }
  22054. this.panel.markChange(this.panel.name == "stylesheet");
  22055. },
  22056. advanceToNext: function(target, charCode)
  22057. {
  22058. if (charCode == 58 /*":"*/ && hasClass(target, "cssPropName"))
  22059. return true;
  22060. },
  22061. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22062. getAutoCompleteRange: function(value, offset)
  22063. {
  22064. if (hasClass(this.target, "cssPropName"))
  22065. return {start: 0, end: value.length-1};
  22066. else
  22067. return parseCSSValue(value, offset);
  22068. },
  22069. getAutoCompleteList: function(preExpr, expr, postExpr)
  22070. {
  22071. if (hasClass(this.target, "cssPropName"))
  22072. {
  22073. return getCSSPropertyNames();
  22074. }
  22075. else
  22076. {
  22077. var row = getAncestorByClass(this.target, "cssProp");
  22078. var propName = getChildByClass(row, "cssPropName")[textContent];
  22079. return getCSSKeywordsByProperty(propName);
  22080. }
  22081. }
  22082. });
  22083. //************************************************************************************************
  22084. //CSSRuleEditor
  22085. function CSSRuleEditor(doc)
  22086. {
  22087. this.initializeInline(doc);
  22088. this.completeAsYouType = false;
  22089. }
  22090. CSSRuleEditor.uniquifier = 0;
  22091. CSSRuleEditor.prototype = domplate(Firebug.InlineEditor.prototype,
  22092. {
  22093. insertNewRow: function(target, insertWhere)
  22094. {
  22095. var emptyRule = {
  22096. selector: "",
  22097. id: "",
  22098. props: [],
  22099. isSelectorEditable: true
  22100. };
  22101. if (insertWhere == "before")
  22102. return CSSStyleRuleTag.tag.insertBefore({rule: emptyRule}, target);
  22103. else
  22104. return CSSStyleRuleTag.tag.insertAfter({rule: emptyRule}, target);
  22105. },
  22106. saveEdit: function(target, value, previousValue)
  22107. {
  22108. if (FBTrace.DBG_CSS)
  22109. FBTrace.sysout("CSSRuleEditor.saveEdit: '" + value + "' '" + previousValue + "'", target);
  22110. target.innerHTML = escapeForCss(value);
  22111. if (value === previousValue) return;
  22112. var row = getAncestorByClass(target, "cssRule");
  22113. var styleSheet = this.panel.location;
  22114. styleSheet = styleSheet.editStyleSheet ? styleSheet.editStyleSheet.sheet : styleSheet;
  22115. var cssRules = styleSheet.cssRules;
  22116. var rule = Firebug.getRepObject(target), oldRule = rule;
  22117. var ruleIndex = cssRules.length;
  22118. if (rule || Firebug.getRepObject(row.nextSibling))
  22119. {
  22120. var searchRule = rule || Firebug.getRepObject(row.nextSibling);
  22121. for (ruleIndex=0; ruleIndex<cssRules.length && searchRule!=cssRules[ruleIndex]; ruleIndex++) {}
  22122. }
  22123. // Delete in all cases except for new add
  22124. // We want to do this before the insert to ease change tracking
  22125. if (oldRule)
  22126. {
  22127. Firebug.CSSModule.deleteRule(styleSheet, ruleIndex);
  22128. }
  22129. // Firefox does not follow the spec for the update selector text case.
  22130. // When attempting to update the value, firefox will silently fail.
  22131. // See https://bugzilla.mozilla.org/show_bug.cgi?id=37468 for the quite
  22132. // old discussion of this bug.
  22133. // As a result we need to recreate the style every time the selector
  22134. // changes.
  22135. if (value)
  22136. {
  22137. var cssText = [ value, "{" ];
  22138. var props = row.getElementsByClassName("cssProp");
  22139. for (var i = 0; i < props.length; i++) {
  22140. var propEl = props[i];
  22141. if (!hasClass(propEl, "disabledStyle")) {
  22142. cssText.push(getChildByClass(propEl, "cssPropName")[textContent]);
  22143. cssText.push(":");
  22144. cssText.push(getChildByClass(propEl, "cssPropValue")[textContent]);
  22145. cssText.push(";");
  22146. }
  22147. }
  22148. cssText.push("}");
  22149. cssText = cssText.join("");
  22150. try
  22151. {
  22152. var insertLoc = Firebug.CSSModule.insertRule(styleSheet, cssText, ruleIndex);
  22153. rule = cssRules[insertLoc];
  22154. ruleIndex++;
  22155. }
  22156. catch (err)
  22157. {
  22158. if (FBTrace.DBG_CSS || FBTrace.DBG_ERRORS)
  22159. FBTrace.sysout("CSS Insert Error: "+err, err);
  22160. target.innerHTML = escapeForCss(previousValue);
  22161. row.repObject = undefined;
  22162. return;
  22163. }
  22164. } else {
  22165. rule = undefined;
  22166. }
  22167. // Update the rep object
  22168. row.repObject = rule;
  22169. if (!oldRule)
  22170. {
  22171. // Who knows what the domutils will return for rule line
  22172. // for a recently created rule. To be safe we just generate
  22173. // a unique value as this is only used as an internal key.
  22174. var ruleId = "new/"+value+"/"+(++CSSRuleEditor.uniquifier);
  22175. row.setAttribute("ruleId", ruleId);
  22176. }
  22177. this.panel.markChange(this.panel.name == "stylesheet");
  22178. }
  22179. });
  22180. // ************************************************************************************************
  22181. // StyleSheetEditor
  22182. function StyleSheetEditor(doc)
  22183. {
  22184. this.box = this.tag.replace({}, doc, this);
  22185. this.input = this.box.firstChild;
  22186. }
  22187. StyleSheetEditor.prototype = domplate(Firebug.BaseEditor,
  22188. {
  22189. multiLine: true,
  22190. tag: DIV(
  22191. TEXTAREA({"class": "styleSheetEditor fullPanelEditor", oninput: "$onInput"})
  22192. ),
  22193. getValue: function()
  22194. {
  22195. return this.input.value;
  22196. },
  22197. setValue: function(value)
  22198. {
  22199. return this.input.value = value;
  22200. },
  22201. show: function(target, panel, value, textSize, targetSize)
  22202. {
  22203. this.target = target;
  22204. this.panel = panel;
  22205. this.panel.panelNode.appendChild(this.box);
  22206. this.input.value = value;
  22207. this.input.focus();
  22208. var command = Firebug.chrome.$("cmd_toggleCSSEditing");
  22209. command.setAttribute("checked", true);
  22210. },
  22211. hide: function()
  22212. {
  22213. var command = Firebug.chrome.$("cmd_toggleCSSEditing");
  22214. command.setAttribute("checked", false);
  22215. if (this.box.parentNode == this.panel.panelNode)
  22216. this.panel.panelNode.removeChild(this.box);
  22217. delete this.target;
  22218. delete this.panel;
  22219. delete this.styleSheet;
  22220. },
  22221. saveEdit: function(target, value, previousValue)
  22222. {
  22223. Firebug.CSSModule.freeEdit(this.styleSheet, value);
  22224. },
  22225. endEditing: function()
  22226. {
  22227. this.panel.refresh();
  22228. return true;
  22229. },
  22230. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22231. onInput: function()
  22232. {
  22233. Firebug.Editor.update();
  22234. },
  22235. scrollToLine: function(line, offset)
  22236. {
  22237. this.startMeasuring(this.input);
  22238. var lineHeight = this.measureText().height;
  22239. this.stopMeasuring();
  22240. this.input.scrollTop = (line * lineHeight) + offset;
  22241. }
  22242. });
  22243. // ************************************************************************************************
  22244. // Local Helpers
  22245. var rgbToHex = function rgbToHex(value)
  22246. {
  22247. return value.replace(/\brgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)/gi, rgbToHexReplacer);
  22248. };
  22249. var rgbToHexReplacer = function(_, r, g, b) {
  22250. return '#' + ((1 << 24) + (r << 16) + (g << 8) + (b << 0)).toString(16).substr(-6).toUpperCase();
  22251. };
  22252. var stripUnits = function stripUnits(value)
  22253. {
  22254. // remove units from '0px', '0em' etc. leave non-zero units in-tact.
  22255. return value.replace(/(url\(.*?\)|[^0]\S*\s*)|0(%|em|ex|px|in|cm|mm|pt|pc)(\s|$)/gi, stripUnitsReplacer);
  22256. };
  22257. var stripUnitsReplacer = function(_, skip, remove, whitespace) {
  22258. return skip || ('0' + whitespace);
  22259. };
  22260. function parsePriority(value)
  22261. {
  22262. var rePriority = /(.*?)\s*(!important)?$/;
  22263. var m = rePriority.exec(value);
  22264. var propValue = m ? m[1] : "";
  22265. var priority = m && m[2] ? "important" : "";
  22266. return {value: propValue, priority: priority};
  22267. }
  22268. function parseURLValue(value)
  22269. {
  22270. var m = reURL.exec(value);
  22271. return m ? m[1] : "";
  22272. }
  22273. function parseRepeatValue(value)
  22274. {
  22275. var m = reRepeat.exec(value);
  22276. return m ? m[0] : "";
  22277. }
  22278. function parseCSSValue(value, offset)
  22279. {
  22280. var start = 0;
  22281. var m;
  22282. while (1)
  22283. {
  22284. m = reSplitCSS.exec(value);
  22285. if (m && m.index+m[0].length < offset)
  22286. {
  22287. value = value.substr(m.index+m[0].length);
  22288. start += m.index+m[0].length;
  22289. offset -= m.index+m[0].length;
  22290. }
  22291. else
  22292. break;
  22293. }
  22294. if (m)
  22295. {
  22296. var type;
  22297. if (m[1])
  22298. type = "url";
  22299. else if (m[2] || m[3])
  22300. type = "rgb";
  22301. else if (m[4])
  22302. type = "int";
  22303. return {value: m[0], start: start+m.index, end: start+m.index+(m[0].length-1), type: type};
  22304. }
  22305. }
  22306. function findPropByName(props, name)
  22307. {
  22308. for (var i = 0; i < props.length; ++i)
  22309. {
  22310. if (props[i].name == name)
  22311. return i;
  22312. }
  22313. }
  22314. function sortProperties(props)
  22315. {
  22316. props.sort(function(a, b)
  22317. {
  22318. return a.name > b.name ? 1 : -1;
  22319. });
  22320. }
  22321. function getTopmostRuleLine(panelNode)
  22322. {
  22323. for (var child = panelNode.firstChild; child; child = child.nextSibling)
  22324. {
  22325. if (child.offsetTop+child.offsetHeight > panelNode.scrollTop)
  22326. {
  22327. var rule = child.repObject;
  22328. if (rule)
  22329. return {
  22330. line: domUtils.getRuleLine(rule),
  22331. offset: panelNode.scrollTop-child.offsetTop
  22332. };
  22333. }
  22334. }
  22335. return 0;
  22336. }
  22337. function getStyleSheetCSS(sheet, context)
  22338. {
  22339. if (sheet.ownerNode instanceof HTMLStyleElement)
  22340. return sheet.ownerNode.innerHTML;
  22341. else
  22342. return context.sourceCache.load(sheet.href).join("");
  22343. }
  22344. function getStyleSheetOwnerNode(sheet) {
  22345. for (; sheet && !sheet.ownerNode; sheet = sheet.parentStyleSheet);
  22346. return sheet.ownerNode;
  22347. }
  22348. function scrollSelectionIntoView(panel)
  22349. {
  22350. var selCon = getSelectionController(panel);
  22351. selCon.scrollSelectionIntoView(
  22352. nsISelectionController.SELECTION_NORMAL,
  22353. nsISelectionController.SELECTION_FOCUS_REGION, true);
  22354. }
  22355. function getSelectionController(panel)
  22356. {
  22357. var browser = Firebug.chrome.getPanelBrowser(panel);
  22358. return browser.docShell.QueryInterface(nsIInterfaceRequestor)
  22359. .getInterface(nsISelectionDisplay)
  22360. .QueryInterface(nsISelectionController);
  22361. }
  22362. // ************************************************************************************************
  22363. Firebug.registerModule(Firebug.CSSModule);
  22364. Firebug.registerPanel(Firebug.CSSStyleSheetPanel);
  22365. Firebug.registerPanel(CSSElementPanel);
  22366. Firebug.registerPanel(CSSComputedElementPanel);
  22367. // ************************************************************************************************
  22368. }});
  22369. /* See license.txt for terms of usage */
  22370. FBL.ns(function() { with (FBL) {
  22371. // ************************************************************************************************
  22372. // ************************************************************************************************
  22373. // Script Module
  22374. Firebug.Script = extend(Firebug.Module,
  22375. {
  22376. getPanel: function()
  22377. {
  22378. return Firebug.chrome ? Firebug.chrome.getPanel("Script") : null;
  22379. },
  22380. selectSourceCode: function(index)
  22381. {
  22382. this.getPanel().selectSourceCode(index);
  22383. }
  22384. });
  22385. Firebug.registerModule(Firebug.Script);
  22386. // ************************************************************************************************
  22387. // Script Panel
  22388. function ScriptPanel(){};
  22389. ScriptPanel.prototype = extend(Firebug.Panel,
  22390. {
  22391. name: "Script",
  22392. title: "Script",
  22393. selectIndex: 0, // index of the current selectNode's option
  22394. sourceIndex: -1, // index of the script node, based in doc.getElementsByTagName("script")
  22395. options: {
  22396. hasToolButtons: true
  22397. },
  22398. create: function()
  22399. {
  22400. Firebug.Panel.create.apply(this, arguments);
  22401. this.onChangeSelect = bind(this.onChangeSelect, this);
  22402. var doc = Firebug.browser.document;
  22403. var scripts = doc.getElementsByTagName("script");
  22404. var selectNode = this.selectNode = createElement("select");
  22405. for(var i=0, script; script=scripts[i]; i++)
  22406. {
  22407. // Don't show Firebug Lite source code in the list of options
  22408. if (Firebug.ignoreFirebugElements && script.getAttribute("firebugIgnore"))
  22409. continue;
  22410. var fileName = getFileName(script.src) || getFileName(doc.location.href);
  22411. var option = createElement("option", {value:i});
  22412. option.appendChild(Firebug.chrome.document.createTextNode(fileName));
  22413. selectNode.appendChild(option);
  22414. };
  22415. this.toolButtonsNode.appendChild(selectNode);
  22416. },
  22417. initialize: function()
  22418. {
  22419. // we must render the code first, so the persistent state can be restore
  22420. this.selectSourceCode(this.selectIndex);
  22421. Firebug.Panel.initialize.apply(this, arguments);
  22422. addEvent(this.selectNode, "change", this.onChangeSelect);
  22423. },
  22424. shutdown: function()
  22425. {
  22426. removeEvent(this.selectNode, "change", this.onChangeSelect);
  22427. Firebug.Panel.shutdown.apply(this, arguments);
  22428. },
  22429. detach: function(oldChrome, newChrome)
  22430. {
  22431. Firebug.Panel.detach.apply(this, arguments);
  22432. var oldPanel = oldChrome.getPanel("Script");
  22433. var index = oldPanel.selectIndex;
  22434. this.selectNode.selectedIndex = index;
  22435. this.selectIndex = index;
  22436. this.sourceIndex = -1;
  22437. },
  22438. onChangeSelect: function(event)
  22439. {
  22440. var select = this.selectNode;
  22441. this.selectIndex = select.selectedIndex;
  22442. var option = select.options[select.selectedIndex];
  22443. if (!option)
  22444. return;
  22445. var selectedSourceIndex = parseInt(option.value);
  22446. this.renderSourceCode(selectedSourceIndex);
  22447. },
  22448. selectSourceCode: function(index)
  22449. {
  22450. var select = this.selectNode;
  22451. select.selectedIndex = index;
  22452. var option = select.options[index];
  22453. if (!option)
  22454. return;
  22455. var selectedSourceIndex = parseInt(option.value);
  22456. this.renderSourceCode(selectedSourceIndex);
  22457. },
  22458. renderSourceCode: function(index)
  22459. {
  22460. if (this.sourceIndex != index)
  22461. {
  22462. var renderProcess = function renderProcess(src)
  22463. {
  22464. var html = [],
  22465. hl = 0;
  22466. src = isIE && !isExternal ?
  22467. src+'\n' : // IE put an extra line when reading source of local resources
  22468. '\n'+src;
  22469. // find the number of lines of code
  22470. src = src.replace(/\n\r|\r\n/g, "\n");
  22471. var match = src.match(/[\n]/g);
  22472. var lines=match ? match.length : 0;
  22473. // render the full source code + line numbers html
  22474. html[hl++] = '<div><div class="sourceBox" style="left:';
  22475. html[hl++] = 35 + 7*(lines+'').length;
  22476. html[hl++] = 'px;"><pre class="sourceCode">';
  22477. html[hl++] = escapeHTML(src);
  22478. html[hl++] = '</pre></div><div class="lineNo">';
  22479. // render the line number divs
  22480. for(var l=1, lines; l<=lines; l++)
  22481. {
  22482. html[hl++] = '<div line="';
  22483. html[hl++] = l;
  22484. html[hl++] = '">';
  22485. html[hl++] = l;
  22486. html[hl++] = '</div>';
  22487. }
  22488. html[hl++] = '</div></div>';
  22489. updatePanel(html);
  22490. };
  22491. var updatePanel = function(html)
  22492. {
  22493. self.panelNode.innerHTML = html.join("");
  22494. // IE needs this timeout, otherwise the panel won't scroll
  22495. setTimeout(function(){
  22496. self.synchronizeUI();
  22497. },0);
  22498. };
  22499. var onFailure = function()
  22500. {
  22501. FirebugReps.Warning.tag.replace({object: "AccessRestricted"}, self.panelNode);
  22502. };
  22503. var self = this;
  22504. var doc = Firebug.browser.document;
  22505. var script = doc.getElementsByTagName("script")[index];
  22506. var url = getScriptURL(script);
  22507. var isExternal = url && url != doc.location.href;
  22508. try
  22509. {
  22510. if (isExternal)
  22511. {
  22512. Ajax.request({url: url, onSuccess: renderProcess, onFailure: onFailure});
  22513. }
  22514. else
  22515. {
  22516. var src = script.innerHTML;
  22517. renderProcess(src);
  22518. }
  22519. }
  22520. catch(e)
  22521. {
  22522. onFailure();
  22523. }
  22524. this.sourceIndex = index;
  22525. }
  22526. }
  22527. });
  22528. Firebug.registerPanel(ScriptPanel);
  22529. // ************************************************************************************************
  22530. var getScriptURL = function getScriptURL(script)
  22531. {
  22532. var reFile = /([^\/\?#]+)(#.+)?$/;
  22533. var rePath = /^(.*\/)/;
  22534. var reProtocol = /^\w+:\/\//;
  22535. var path = null;
  22536. var doc = Firebug.browser.document;
  22537. var file = reFile.exec(script.src);
  22538. if (file)
  22539. {
  22540. var fileName = file[1];
  22541. var fileOptions = file[2];
  22542. // absolute path
  22543. if (reProtocol.test(script.src)) {
  22544. path = rePath.exec(script.src)[1];
  22545. }
  22546. // relative path
  22547. else
  22548. {
  22549. var r = rePath.exec(script.src);
  22550. var src = r ? r[1] : script.src;
  22551. var backDir = /^((?:\.\.\/)+)(.*)/.exec(src);
  22552. var reLastDir = /^(.*\/)[^\/]+\/$/;
  22553. path = rePath.exec(doc.location.href)[1];
  22554. // "../some/path"
  22555. if (backDir)
  22556. {
  22557. var j = backDir[1].length/3;
  22558. var p;
  22559. while (j-- > 0)
  22560. path = reLastDir.exec(path)[1];
  22561. path += backDir[2];
  22562. }
  22563. else if(src.indexOf("/") != -1)
  22564. {
  22565. // "./some/path"
  22566. if(/^\.\/./.test(src))
  22567. {
  22568. path += src.substring(2);
  22569. }
  22570. // "/some/path"
  22571. else if(/^\/./.test(src))
  22572. {
  22573. var domain = /^(\w+:\/\/[^\/]+)/.exec(path);
  22574. path = domain[1] + src;
  22575. }
  22576. // "some/path"
  22577. else
  22578. {
  22579. path += src;
  22580. }
  22581. }
  22582. }
  22583. }
  22584. var m = path && path.match(/([^\/]+)\/$/) || null;
  22585. if (path && m)
  22586. {
  22587. return path + fileName;
  22588. }
  22589. };
  22590. var getFileName = function getFileName(path)
  22591. {
  22592. if (!path) return "";
  22593. var match = path && path.match(/[^\/]+(\?.*)?(#.*)?$/);
  22594. return match && match[0] || path;
  22595. };
  22596. // ************************************************************************************************
  22597. }});
  22598. /* See license.txt for terms of usage */
  22599. FBL.ns(function() { with (FBL) {
  22600. // ************************************************************************************************
  22601. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22602. var ElementCache = Firebug.Lite.Cache.Element;
  22603. var insertSliceSize = 18;
  22604. var insertInterval = 40;
  22605. var ignoreVars =
  22606. {
  22607. "__firebug__": 1,
  22608. "eval": 1,
  22609. // We are forced to ignore Java-related variables, because
  22610. // trying to access them causes browser freeze
  22611. "java": 1,
  22612. "sun": 1,
  22613. "Packages": 1,
  22614. "JavaArray": 1,
  22615. "JavaMember": 1,
  22616. "JavaObject": 1,
  22617. "JavaClass": 1,
  22618. "JavaPackage": 1,
  22619. "_firebug": 1,
  22620. "_FirebugConsole": 1,
  22621. "_FirebugCommandLine": 1
  22622. };
  22623. if (Firebug.ignoreFirebugElements)
  22624. ignoreVars[Firebug.Lite.Cache.ID] = 1;
  22625. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22626. var memberPanelRep =
  22627. isIE6 ?
  22628. {"class": "memberLabel $member.type\\Label", href: "javacript:void(0)"}
  22629. :
  22630. {"class": "memberLabel $member.type\\Label"};
  22631. var RowTag =
  22632. TR({"class": "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren", role : 'presentation',
  22633. level: "$member.level"},
  22634. TD({"class": "memberLabelCell", style: "padding-left: $member.indent\\px", role : 'presentation'},
  22635. A(memberPanelRep,
  22636. SPAN({}, "$member.name")
  22637. )
  22638. ),
  22639. TD({"class": "memberValueCell", role : 'presentation'},
  22640. TAG("$member.tag", {object: "$member.value"})
  22641. )
  22642. );
  22643. var WatchRowTag =
  22644. TR({"class": "watchNewRow", level: 0},
  22645. TD({"class": "watchEditCell", colspan: 2},
  22646. DIV({"class": "watchEditBox a11yFocusNoTab", role: "button", 'tabindex' : '0',
  22647. 'aria-label' : $STR('press enter to add new watch expression')},
  22648. $STR("NewWatch")
  22649. )
  22650. )
  22651. );
  22652. var SizerRow =
  22653. TR({role : 'presentation'},
  22654. TD({width: "30%"}),
  22655. TD({width: "70%"})
  22656. );
  22657. var domTableClass = isIElt8 ? "domTable domTableIE" : "domTable";
  22658. var DirTablePlate = domplate(Firebug.Rep,
  22659. {
  22660. tag:
  22661. TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0, onclick: "$onClick", role :"tree"},
  22662. TBODY({role: 'presentation'},
  22663. SizerRow,
  22664. FOR("member", "$object|memberIterator", RowTag)
  22665. )
  22666. ),
  22667. watchTag:
  22668. TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0,
  22669. _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'},
  22670. TBODY({role : 'presentation'},
  22671. SizerRow,
  22672. WatchRowTag
  22673. )
  22674. ),
  22675. tableTag:
  22676. TABLE({"class": domTableClass, cellpadding: 0, cellspacing: 0,
  22677. _toggles: "$toggles", _domPanel: "$domPanel", onclick: "$onClick", role : 'tree'},
  22678. TBODY({role : 'presentation'},
  22679. SizerRow
  22680. )
  22681. ),
  22682. rowTag:
  22683. FOR("member", "$members", RowTag),
  22684. memberIterator: function(object, level)
  22685. {
  22686. return getMembers(object, level);
  22687. },
  22688. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  22689. onClick: function(event)
  22690. {
  22691. if (!isLeftClick(event))
  22692. return;
  22693. var target = event.target || event.srcElement;
  22694. var row = getAncestorByClass(target, "memberRow");
  22695. var label = getAncestorByClass(target, "memberLabel");
  22696. if (label && hasClass(row, "hasChildren"))
  22697. {
  22698. var row = label.parentNode.parentNode;
  22699. this.toggleRow(row);
  22700. }
  22701. else
  22702. {
  22703. var object = Firebug.getRepObject(target);
  22704. if (typeof(object) == "function")
  22705. {
  22706. Firebug.chrome.select(object, "script");
  22707. cancelEvent(event);
  22708. }
  22709. else if (event.detail == 2 && !object)
  22710. {
  22711. var panel = row.parentNode.parentNode.domPanel;
  22712. if (panel)
  22713. {
  22714. var rowValue = panel.getRowPropertyValue(row);
  22715. if (typeof(rowValue) == "boolean")
  22716. panel.setPropertyValue(row, !rowValue);
  22717. else
  22718. panel.editProperty(row);
  22719. cancelEvent(event);
  22720. }
  22721. }
  22722. }
  22723. return false;
  22724. },
  22725. toggleRow: function(row)
  22726. {
  22727. var level = parseInt(row.getAttribute("level"));
  22728. var toggles = row.parentNode.parentNode.toggles;
  22729. if (hasClass(row, "opened"))
  22730. {
  22731. removeClass(row, "opened");
  22732. if (toggles)
  22733. {
  22734. var path = getPath(row);
  22735. // Remove the path from the toggle tree
  22736. for (var i = 0; i < path.length; ++i)
  22737. {
  22738. if (i == path.length-1)
  22739. delete toggles[path[i]];
  22740. else
  22741. toggles = toggles[path[i]];
  22742. }
  22743. }
  22744. var rowTag = this.rowTag;
  22745. var tbody = row.parentNode;
  22746. setTimeout(function()
  22747. {
  22748. for (var firstRow = row.nextSibling; firstRow; firstRow = row.nextSibling)
  22749. {
  22750. if (parseInt(firstRow.getAttribute("level")) <= level)
  22751. break;
  22752. tbody.removeChild(firstRow);
  22753. }
  22754. }, row.insertTimeout ? row.insertTimeout : 0);
  22755. }
  22756. else
  22757. {
  22758. setClass(row, "opened");
  22759. if (toggles)
  22760. {
  22761. var path = getPath(row);
  22762. // Mark the path in the toggle tree
  22763. for (var i = 0; i < path.length; ++i)
  22764. {
  22765. var name = path[i];
  22766. if (toggles.hasOwnProperty(name))
  22767. toggles = toggles[name];
  22768. else
  22769. toggles = toggles[name] = {};
  22770. }
  22771. }
  22772. var value = row.lastChild.firstChild.repObject;
  22773. var members = getMembers(value, level+1);
  22774. var rowTag = this.rowTag;
  22775. var lastRow = row;
  22776. var delay = 0;
  22777. //var setSize = members.length;
  22778. //var rowCount = 1;
  22779. while (members.length)
  22780. {
  22781. with({slice: members.splice(0, insertSliceSize), isLast: !members.length})
  22782. {
  22783. setTimeout(function()
  22784. {
  22785. if (lastRow.parentNode)
  22786. {
  22787. var result = rowTag.insertRows({members: slice}, lastRow);
  22788. lastRow = result[1];
  22789. //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [null, result, rowCount, setSize]);
  22790. //rowCount += insertSliceSize;
  22791. }
  22792. if (isLast)
  22793. row.removeAttribute("insertTimeout");
  22794. }, delay);
  22795. }
  22796. delay += insertInterval;
  22797. }
  22798. row.insertTimeout = delay;
  22799. }
  22800. }
  22801. });
  22802. // ************************************************************************************************
  22803. Firebug.DOMBasePanel = function() {}
  22804. Firebug.DOMBasePanel.prototype = extend(Firebug.Panel,
  22805. {
  22806. tag: DirTablePlate.tableTag,
  22807. getRealObject: function(object)
  22808. {
  22809. // TODO: Move this to some global location
  22810. // TODO: Unwrapping should be centralized rather than sprinkling it around ad hoc.
  22811. // TODO: We might be able to make this check more authoritative with QueryInterface.
  22812. if (!object) return object;
  22813. if (object.wrappedJSObject) return object.wrappedJSObject;
  22814. return object;
  22815. },
  22816. rebuild: function(update, scrollTop)
  22817. {
  22818. //dispatch([Firebug.A11yModel], 'onBeforeDomUpdateSelection', [this]);
  22819. var members = getMembers(this.selection);
  22820. expandMembers(members, this.toggles, 0, 0);
  22821. this.showMembers(members, update, scrollTop);
  22822. //TODO: xxxpedro statusbar
  22823. if (!this.parentPanel)
  22824. updateStatusBar(this);
  22825. },
  22826. showMembers: function(members, update, scrollTop)
  22827. {
  22828. // If we are still in the midst of inserting rows, cancel all pending
  22829. // insertions here - this is a big speedup when stepping in the debugger
  22830. if (this.timeouts)
  22831. {
  22832. for (var i = 0; i < this.timeouts.length; ++i)
  22833. this.context.clearTimeout(this.timeouts[i]);
  22834. delete this.timeouts;
  22835. }
  22836. if (!members.length)
  22837. return this.showEmptyMembers();
  22838. var panelNode = this.panelNode;
  22839. var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop;
  22840. // If we are asked to "update" the current view, then build the new table
  22841. // offscreen and swap it in when it's done
  22842. var offscreen = update && panelNode.firstChild;
  22843. var dest = offscreen ? panelNode.ownerDocument : panelNode;
  22844. var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest);
  22845. var tbody = table.lastChild;
  22846. var rowTag = DirTablePlate.rowTag;
  22847. // Insert the first slice immediately
  22848. //var slice = members.splice(0, insertSliceSize);
  22849. //var result = rowTag.insertRows({members: slice}, tbody.lastChild);
  22850. //var setSize = members.length;
  22851. //var rowCount = 1;
  22852. var panel = this;
  22853. var result;
  22854. //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
  22855. var timeouts = [];
  22856. var delay = 0;
  22857. // enable to measure rendering performance
  22858. var renderStart = new Date().getTime();
  22859. while (members.length)
  22860. {
  22861. with({slice: members.splice(0, insertSliceSize), isLast: !members.length})
  22862. {
  22863. timeouts.push(this.context.setTimeout(function()
  22864. {
  22865. // TODO: xxxpedro can this be a timing error related to the
  22866. // "iteration number" approach insted of "duration time"?
  22867. // avoid error in IE8
  22868. if (!tbody.lastChild) return;
  22869. result = rowTag.insertRows({members: slice}, tbody.lastChild);
  22870. //rowCount += insertSliceSize;
  22871. //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
  22872. if ((panelNode.scrollHeight+panelNode.offsetHeight) >= priorScrollTop)
  22873. panelNode.scrollTop = priorScrollTop;
  22874. // enable to measure rendering performance
  22875. //if (isLast) alert(new Date().getTime() - renderStart + "ms");
  22876. }, delay));
  22877. delay += insertInterval;
  22878. }
  22879. }
  22880. if (offscreen)
  22881. {
  22882. timeouts.push(this.context.setTimeout(function()
  22883. {
  22884. if (panelNode.firstChild)
  22885. panelNode.replaceChild(table, panelNode.firstChild);
  22886. else
  22887. panelNode.appendChild(table);
  22888. // Scroll back to where we were before
  22889. panelNode.scrollTop = priorScrollTop;
  22890. }, delay));
  22891. }
  22892. else
  22893. {
  22894. timeouts.push(this.context.setTimeout(function()
  22895. {
  22896. panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop;
  22897. }, delay));
  22898. }
  22899. this.timeouts = timeouts;
  22900. },
  22901. /*
  22902. // new
  22903. showMembers: function(members, update, scrollTop)
  22904. {
  22905. // If we are still in the midst of inserting rows, cancel all pending
  22906. // insertions here - this is a big speedup when stepping in the debugger
  22907. if (this.timeouts)
  22908. {
  22909. for (var i = 0; i < this.timeouts.length; ++i)
  22910. this.context.clearTimeout(this.timeouts[i]);
  22911. delete this.timeouts;
  22912. }
  22913. if (!members.length)
  22914. return this.showEmptyMembers();
  22915. var panelNode = this.panelNode;
  22916. var priorScrollTop = scrollTop == undefined ? panelNode.scrollTop : scrollTop;
  22917. // If we are asked to "update" the current view, then build the new table
  22918. // offscreen and swap it in when it's done
  22919. var offscreen = update && panelNode.firstChild;
  22920. var dest = offscreen ? panelNode.ownerDocument : panelNode;
  22921. var table = this.tag.replace({domPanel: this, toggles: this.toggles}, dest);
  22922. var tbody = table.lastChild;
  22923. var rowTag = DirTablePlate.rowTag;
  22924. // Insert the first slice immediately
  22925. //var slice = members.splice(0, insertSliceSize);
  22926. //var result = rowTag.insertRows({members: slice}, tbody.lastChild);
  22927. //var setSize = members.length;
  22928. //var rowCount = 1;
  22929. var panel = this;
  22930. var result;
  22931. //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
  22932. var timeouts = [];
  22933. var delay = 0;
  22934. var _insertSliceSize = insertSliceSize;
  22935. var _insertInterval = insertInterval;
  22936. // enable to measure rendering performance
  22937. var renderStart = new Date().getTime();
  22938. var lastSkip = renderStart, now;
  22939. while (members.length)
  22940. {
  22941. with({slice: members.splice(0, _insertSliceSize), isLast: !members.length})
  22942. {
  22943. var _tbody = tbody;
  22944. var _rowTag = rowTag;
  22945. var _panelNode = panelNode;
  22946. var _priorScrollTop = priorScrollTop;
  22947. timeouts.push(this.context.setTimeout(function()
  22948. {
  22949. // TODO: xxxpedro can this be a timing error related to the
  22950. // "iteration number" approach insted of "duration time"?
  22951. // avoid error in IE8
  22952. if (!_tbody.lastChild) return;
  22953. result = _rowTag.insertRows({members: slice}, _tbody.lastChild);
  22954. //rowCount += _insertSliceSize;
  22955. //dispatch([Firebug.A11yModel], 'onMemberRowSliceAdded', [panel, result, rowCount, setSize]);
  22956. if ((_panelNode.scrollHeight + _panelNode.offsetHeight) >= _priorScrollTop)
  22957. _panelNode.scrollTop = _priorScrollTop;
  22958. // enable to measure rendering performance
  22959. //alert("gap: " + (new Date().getTime() - lastSkip));
  22960. //lastSkip = new Date().getTime();
  22961. //if (isLast) alert("new: " + (new Date().getTime() - renderStart) + "ms");
  22962. }, delay));
  22963. delay += _insertInterval;
  22964. }
  22965. }
  22966. if (offscreen)
  22967. {
  22968. timeouts.push(this.context.setTimeout(function()
  22969. {
  22970. if (panelNode.firstChild)
  22971. panelNode.replaceChild(table, panelNode.firstChild);
  22972. else
  22973. panelNode.appendChild(table);
  22974. // Scroll back to where we were before
  22975. panelNode.scrollTop = priorScrollTop;
  22976. }, delay));
  22977. }
  22978. else
  22979. {
  22980. timeouts.push(this.context.setTimeout(function()
  22981. {
  22982. panelNode.scrollTop = scrollTop == undefined ? 0 : scrollTop;
  22983. }, delay));
  22984. }
  22985. this.timeouts = timeouts;
  22986. },
  22987. /**/
  22988. showEmptyMembers: function()
  22989. {
  22990. FirebugReps.Warning.tag.replace({object: "NoMembersWarning"}, this.panelNode);
  22991. },
  22992. findPathObject: function(object)
  22993. {
  22994. var pathIndex = -1;
  22995. for (var i = 0; i < this.objectPath.length; ++i)
  22996. {
  22997. // IE needs === instead of == or otherwise some objects will
  22998. // be considered equal to different objects, returning the
  22999. // wrong index of the objectPath array
  23000. if (this.getPathObject(i) === object)
  23001. return i;
  23002. }
  23003. return -1;
  23004. },
  23005. getPathObject: function(index)
  23006. {
  23007. var object = this.objectPath[index];
  23008. if (object instanceof Property)
  23009. return object.getObject();
  23010. else
  23011. return object;
  23012. },
  23013. getRowObject: function(row)
  23014. {
  23015. var object = getRowOwnerObject(row);
  23016. return object ? object : this.selection;
  23017. },
  23018. getRowPropertyValue: function(row)
  23019. {
  23020. var object = this.getRowObject(row);
  23021. object = this.getRealObject(object);
  23022. if (object)
  23023. {
  23024. var propName = getRowName(row);
  23025. if (object instanceof jsdIStackFrame)
  23026. return Firebug.Debugger.evaluate(propName, this.context);
  23027. else
  23028. return object[propName];
  23029. }
  23030. },
  23031. /*
  23032. copyProperty: function(row)
  23033. {
  23034. var value = this.getRowPropertyValue(row);
  23035. copyToClipboard(value);
  23036. },
  23037. editProperty: function(row, editValue)
  23038. {
  23039. if (hasClass(row, "watchNewRow"))
  23040. {
  23041. if (this.context.stopped)
  23042. Firebug.Editor.startEditing(row, "");
  23043. else if (Firebug.Console.isAlwaysEnabled()) // not stopped in debugger, need command line
  23044. {
  23045. if (Firebug.CommandLine.onCommandLineFocus())
  23046. Firebug.Editor.startEditing(row, "");
  23047. else
  23048. row.innerHTML = $STR("warning.Command line blocked?");
  23049. }
  23050. else
  23051. row.innerHTML = $STR("warning.Console must be enabled");
  23052. }
  23053. else if (hasClass(row, "watchRow"))
  23054. Firebug.Editor.startEditing(row, getRowName(row));
  23055. else
  23056. {
  23057. var object = this.getRowObject(row);
  23058. this.context.thisValue = object;
  23059. if (!editValue)
  23060. {
  23061. var propValue = this.getRowPropertyValue(row);
  23062. var type = typeof(propValue);
  23063. if (type == "undefined" || type == "number" || type == "boolean")
  23064. editValue = propValue;
  23065. else if (type == "string")
  23066. editValue = "\"" + escapeJS(propValue) + "\"";
  23067. else if (propValue == null)
  23068. editValue = "null";
  23069. else if (object instanceof Window || object instanceof jsdIStackFrame)
  23070. editValue = getRowName(row);
  23071. else
  23072. editValue = "this." + getRowName(row);
  23073. }
  23074. Firebug.Editor.startEditing(row, editValue);
  23075. }
  23076. },
  23077. deleteProperty: function(row)
  23078. {
  23079. if (hasClass(row, "watchRow"))
  23080. this.deleteWatch(row);
  23081. else
  23082. {
  23083. var object = getRowOwnerObject(row);
  23084. if (!object)
  23085. object = this.selection;
  23086. object = this.getRealObject(object);
  23087. if (object)
  23088. {
  23089. var name = getRowName(row);
  23090. try
  23091. {
  23092. delete object[name];
  23093. }
  23094. catch (exc)
  23095. {
  23096. return;
  23097. }
  23098. this.rebuild(true);
  23099. this.markChange();
  23100. }
  23101. }
  23102. },
  23103. setPropertyValue: function(row, value) // value must be string
  23104. {
  23105. if(FBTrace.DBG_DOM)
  23106. {
  23107. FBTrace.sysout("row: "+row);
  23108. FBTrace.sysout("value: "+value+" type "+typeof(value), value);
  23109. }
  23110. var name = getRowName(row);
  23111. if (name == "this")
  23112. return;
  23113. var object = this.getRowObject(row);
  23114. object = this.getRealObject(object);
  23115. if (object && !(object instanceof jsdIStackFrame))
  23116. {
  23117. // unwrappedJSObject.property = unwrappedJSObject
  23118. Firebug.CommandLine.evaluate(value, this.context, object, this.context.getGlobalScope(),
  23119. function success(result, context)
  23120. {
  23121. if (FBTrace.DBG_DOM)
  23122. FBTrace.sysout("setPropertyValue evaluate success object["+name+"]="+result+" type "+typeof(result), result);
  23123. object[name] = result;
  23124. },
  23125. function failed(exc, context)
  23126. {
  23127. try
  23128. {
  23129. if (FBTrace.DBG_DOM)
  23130. FBTrace.sysout("setPropertyValue evaluate failed with exc:"+exc+" object["+name+"]="+value+" type "+typeof(value), exc);
  23131. // If the value doesn't parse, then just store it as a string. Some users will
  23132. // not realize they're supposed to enter a JavaScript expression and just type
  23133. // literal text
  23134. object[name] = String(value); // unwrappedJSobject.property = string
  23135. }
  23136. catch (exc)
  23137. {
  23138. return;
  23139. }
  23140. }
  23141. );
  23142. }
  23143. else if (this.context.stopped)
  23144. {
  23145. try
  23146. {
  23147. Firebug.CommandLine.evaluate(name+"="+value, this.context);
  23148. }
  23149. catch (exc)
  23150. {
  23151. try
  23152. {
  23153. // See catch block above...
  23154. object[name] = String(value); // unwrappedJSobject.property = string
  23155. }
  23156. catch (exc)
  23157. {
  23158. return;
  23159. }
  23160. }
  23161. }
  23162. this.rebuild(true);
  23163. this.markChange();
  23164. },
  23165. highlightRow: function(row)
  23166. {
  23167. if (this.highlightedRow)
  23168. cancelClassTimed(this.highlightedRow, "jumpHighlight", this.context);
  23169. this.highlightedRow = row;
  23170. if (row)
  23171. setClassTimed(row, "jumpHighlight", this.context);
  23172. },/**/
  23173. onMouseMove: function(event)
  23174. {
  23175. var target = event.srcElement || event.target;
  23176. var object = getAncestorByClass(target, "objectLink-element");
  23177. object = object ? object.repObject : null;
  23178. if(object && instanceOf(object, "Element") && object.nodeType == 1)
  23179. {
  23180. if(object != lastHighlightedObject)
  23181. {
  23182. Firebug.Inspector.drawBoxModel(object);
  23183. object = lastHighlightedObject;
  23184. }
  23185. }
  23186. else
  23187. Firebug.Inspector.hideBoxModel();
  23188. },
  23189. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23190. // extends Panel
  23191. create: function()
  23192. {
  23193. // TODO: xxxpedro
  23194. this.context = Firebug.browser;
  23195. this.objectPath = [];
  23196. this.propertyPath = [];
  23197. this.viewPath = [];
  23198. this.pathIndex = -1;
  23199. this.toggles = {};
  23200. Firebug.Panel.create.apply(this, arguments);
  23201. this.panelNode.style.padding = "0 1px";
  23202. },
  23203. initialize: function(){
  23204. Firebug.Panel.initialize.apply(this, arguments);
  23205. addEvent(this.panelNode, "mousemove", this.onMouseMove);
  23206. },
  23207. shutdown: function()
  23208. {
  23209. removeEvent(this.panelNode, "mousemove", this.onMouseMove);
  23210. Firebug.Panel.shutdown.apply(this, arguments);
  23211. },
  23212. /*
  23213. destroy: function(state)
  23214. {
  23215. var view = this.viewPath[this.pathIndex];
  23216. if (view && this.panelNode.scrollTop)
  23217. view.scrollTop = this.panelNode.scrollTop;
  23218. if (this.pathIndex)
  23219. state.pathIndex = this.pathIndex;
  23220. if (this.viewPath)
  23221. state.viewPath = this.viewPath;
  23222. if (this.propertyPath)
  23223. state.propertyPath = this.propertyPath;
  23224. if (this.propertyPath.length > 0 && !this.propertyPath[1])
  23225. state.firstSelection = persistObject(this.getPathObject(1), this.context);
  23226. Firebug.Panel.destroy.apply(this, arguments);
  23227. },
  23228. /**/
  23229. ishow: function(state)
  23230. {
  23231. if (this.context.loaded && !this.selection)
  23232. {
  23233. if (!state)
  23234. {
  23235. this.select(null);
  23236. return;
  23237. }
  23238. if (state.viewPath)
  23239. this.viewPath = state.viewPath;
  23240. if (state.propertyPath)
  23241. this.propertyPath = state.propertyPath;
  23242. var defaultObject = this.getDefaultSelection(this.context);
  23243. var selectObject = defaultObject;
  23244. if (state.firstSelection)
  23245. {
  23246. var restored = state.firstSelection(this.context);
  23247. if (restored)
  23248. {
  23249. selectObject = restored;
  23250. this.objectPath = [defaultObject, restored];
  23251. }
  23252. else
  23253. this.objectPath = [defaultObject];
  23254. }
  23255. else
  23256. this.objectPath = [defaultObject];
  23257. if (this.propertyPath.length > 1)
  23258. {
  23259. for (var i = 1; i < this.propertyPath.length; ++i)
  23260. {
  23261. var name = this.propertyPath[i];
  23262. if (!name)
  23263. continue;
  23264. var object = selectObject;
  23265. try
  23266. {
  23267. selectObject = object[name];
  23268. }
  23269. catch (exc)
  23270. {
  23271. selectObject = null;
  23272. }
  23273. if (selectObject)
  23274. {
  23275. this.objectPath.push(new Property(object, name));
  23276. }
  23277. else
  23278. {
  23279. // If we can't access a property, just stop
  23280. this.viewPath.splice(i);
  23281. this.propertyPath.splice(i);
  23282. this.objectPath.splice(i);
  23283. selectObject = this.getPathObject(this.objectPath.length-1);
  23284. break;
  23285. }
  23286. }
  23287. }
  23288. var selection = state.pathIndex <= this.objectPath.length-1
  23289. ? this.getPathObject(state.pathIndex)
  23290. : this.getPathObject(this.objectPath.length-1);
  23291. this.select(selection);
  23292. }
  23293. },
  23294. /*
  23295. hide: function()
  23296. {
  23297. var view = this.viewPath[this.pathIndex];
  23298. if (view && this.panelNode.scrollTop)
  23299. view.scrollTop = this.panelNode.scrollTop;
  23300. },
  23301. /**/
  23302. supportsObject: function(object)
  23303. {
  23304. if (object == null)
  23305. return 1000;
  23306. if (typeof(object) == "undefined")
  23307. return 1000;
  23308. else if (object instanceof SourceLink)
  23309. return 0;
  23310. else
  23311. return 1; // just agree to support everything but not agressively.
  23312. },
  23313. refresh: function()
  23314. {
  23315. this.rebuild(true);
  23316. },
  23317. updateSelection: function(object)
  23318. {
  23319. var previousIndex = this.pathIndex;
  23320. var previousView = previousIndex == -1 ? null : this.viewPath[previousIndex];
  23321. var newPath = this.pathToAppend;
  23322. delete this.pathToAppend;
  23323. var pathIndex = this.findPathObject(object);
  23324. if (newPath || pathIndex == -1)
  23325. {
  23326. this.toggles = {};
  23327. if (newPath)
  23328. {
  23329. // Remove everything after the point where we are inserting, so we
  23330. // essentially replace it with the new path
  23331. if (previousView)
  23332. {
  23333. if (this.panelNode.scrollTop)
  23334. previousView.scrollTop = this.panelNode.scrollTop;
  23335. var start = previousIndex + 1,
  23336. // Opera needs the length argument in splice(), otherwise
  23337. // it will consider that only one element should be removed
  23338. length = this.objectPath.length - start;
  23339. this.objectPath.splice(start, length);
  23340. this.propertyPath.splice(start, length);
  23341. this.viewPath.splice(start, length);
  23342. }
  23343. var value = this.getPathObject(previousIndex);
  23344. if (!value)
  23345. {
  23346. if (FBTrace.DBG_ERRORS)
  23347. FBTrace.sysout("dom.updateSelection no pathObject for "+previousIndex+"\n");
  23348. return;
  23349. }
  23350. for (var i = 0, length = newPath.length; i < length; ++i)
  23351. {
  23352. var name = newPath[i];
  23353. var object = value;
  23354. try
  23355. {
  23356. value = value[name];
  23357. }
  23358. catch(exc)
  23359. {
  23360. if (FBTrace.DBG_ERRORS)
  23361. FBTrace.sysout("dom.updateSelection FAILS at path_i="+i+" for name:"+name+"\n");
  23362. return;
  23363. }
  23364. ++this.pathIndex;
  23365. this.objectPath.push(new Property(object, name));
  23366. this.propertyPath.push(name);
  23367. this.viewPath.push({toggles: this.toggles, scrollTop: 0});
  23368. }
  23369. }
  23370. else
  23371. {
  23372. this.toggles = {};
  23373. var win = Firebug.browser.window;
  23374. //var win = this.context.getGlobalScope();
  23375. if (object === win)
  23376. {
  23377. this.pathIndex = 0;
  23378. this.objectPath = [win];
  23379. this.propertyPath = [null];
  23380. this.viewPath = [{toggles: this.toggles, scrollTop: 0}];
  23381. }
  23382. else
  23383. {
  23384. this.pathIndex = 1;
  23385. this.objectPath = [win, object];
  23386. this.propertyPath = [null, null];
  23387. this.viewPath = [
  23388. {toggles: {}, scrollTop: 0},
  23389. {toggles: this.toggles, scrollTop: 0}
  23390. ];
  23391. }
  23392. }
  23393. this.panelNode.scrollTop = 0;
  23394. this.rebuild();
  23395. }
  23396. else
  23397. {
  23398. this.pathIndex = pathIndex;
  23399. var view = this.viewPath[pathIndex];
  23400. this.toggles = view.toggles;
  23401. // Persist the current scroll location
  23402. if (previousView && this.panelNode.scrollTop)
  23403. previousView.scrollTop = this.panelNode.scrollTop;
  23404. this.rebuild(false, view.scrollTop);
  23405. }
  23406. },
  23407. getObjectPath: function(object)
  23408. {
  23409. return this.objectPath;
  23410. },
  23411. getDefaultSelection: function()
  23412. {
  23413. return Firebug.browser.window;
  23414. //return this.context.getGlobalScope();
  23415. }/*,
  23416. updateOption: function(name, value)
  23417. {
  23418. const optionMap = {showUserProps: 1, showUserFuncs: 1, showDOMProps: 1,
  23419. showDOMFuncs: 1, showDOMConstants: 1};
  23420. if ( optionMap.hasOwnProperty(name) )
  23421. this.rebuild(true);
  23422. },
  23423. getOptionsMenuItems: function()
  23424. {
  23425. return [
  23426. optionMenu("ShowUserProps", "showUserProps"),
  23427. optionMenu("ShowUserFuncs", "showUserFuncs"),
  23428. optionMenu("ShowDOMProps", "showDOMProps"),
  23429. optionMenu("ShowDOMFuncs", "showDOMFuncs"),
  23430. optionMenu("ShowDOMConstants", "showDOMConstants"),
  23431. "-",
  23432. {label: "Refresh", command: bindFixed(this.rebuild, this, true) }
  23433. ];
  23434. },
  23435. getContextMenuItems: function(object, target)
  23436. {
  23437. var row = getAncestorByClass(target, "memberRow");
  23438. var items = [];
  23439. if (row)
  23440. {
  23441. var rowName = getRowName(row);
  23442. var rowObject = this.getRowObject(row);
  23443. var rowValue = this.getRowPropertyValue(row);
  23444. var isWatch = hasClass(row, "watchRow");
  23445. var isStackFrame = rowObject instanceof jsdIStackFrame;
  23446. if (typeof(rowValue) == "string" || typeof(rowValue) == "number")
  23447. {
  23448. // Functions already have a copy item in their context menu
  23449. items.push(
  23450. "-",
  23451. {label: "CopyValue",
  23452. command: bindFixed(this.copyProperty, this, row) }
  23453. );
  23454. }
  23455. items.push(
  23456. "-",
  23457. {label: isWatch ? "EditWatch" : (isStackFrame ? "EditVariable" : "EditProperty"),
  23458. command: bindFixed(this.editProperty, this, row) }
  23459. );
  23460. if (isWatch || (!isStackFrame && !isDOMMember(rowObject, rowName)))
  23461. {
  23462. items.push(
  23463. {label: isWatch ? "DeleteWatch" : "DeleteProperty",
  23464. command: bindFixed(this.deleteProperty, this, row) }
  23465. );
  23466. }
  23467. }
  23468. items.push(
  23469. "-",
  23470. {label: "Refresh", command: bindFixed(this.rebuild, this, true) }
  23471. );
  23472. return items;
  23473. },
  23474. getEditor: function(target, value)
  23475. {
  23476. if (!this.editor)
  23477. this.editor = new DOMEditor(this.document);
  23478. return this.editor;
  23479. }/**/
  23480. });
  23481. // ************************************************************************************************
  23482. // TODO: xxxpedro statusbar
  23483. var updateStatusBar = function(panel)
  23484. {
  23485. var path = panel.propertyPath;
  23486. var index = panel.pathIndex;
  23487. var r = [];
  23488. for (var i=0, l=path.length; i<l; i++)
  23489. {
  23490. r.push(i==index ? '<a class="fbHover fbButton fbBtnSelected" ' : '<a class="fbHover fbButton" ');
  23491. r.push('pathIndex=');
  23492. r.push(i);
  23493. if(isIE6)
  23494. r.push(' href="javascript:void(0)"');
  23495. r.push('>');
  23496. r.push(i==0 ? "window" : path[i] || "Object");
  23497. r.push('</a>');
  23498. if(i < l-1)
  23499. r.push('<span class="fbStatusSeparator">&gt;</span>');
  23500. }
  23501. panel.statusBarNode.innerHTML = r.join("");
  23502. };
  23503. var DOMMainPanel = Firebug.DOMPanel = function () {};
  23504. Firebug.DOMPanel.DirTable = DirTablePlate;
  23505. DOMMainPanel.prototype = extend(Firebug.DOMBasePanel.prototype,
  23506. {
  23507. onClickStatusBar: function(event)
  23508. {
  23509. var target = event.srcElement || event.target;
  23510. var element = getAncestorByClass(target, "fbHover");
  23511. if(element)
  23512. {
  23513. var pathIndex = element.getAttribute("pathIndex");
  23514. if(pathIndex)
  23515. {
  23516. this.select(this.getPathObject(pathIndex));
  23517. }
  23518. }
  23519. },
  23520. selectRow: function(row, target)
  23521. {
  23522. if (!target)
  23523. target = row.lastChild.firstChild;
  23524. if (!target || !target.repObject)
  23525. return;
  23526. this.pathToAppend = getPath(row);
  23527. // If the object is inside an array, look up its index
  23528. var valueBox = row.lastChild.firstChild;
  23529. if (hasClass(valueBox, "objectBox-array"))
  23530. {
  23531. var arrayIndex = FirebugReps.Arr.getItemIndex(target);
  23532. this.pathToAppend.push(arrayIndex);
  23533. }
  23534. // Make sure we get a fresh status path for the object, since otherwise
  23535. // it might find the object in the existing path and not refresh it
  23536. //Firebug.chrome.clearStatusPath();
  23537. this.select(target.repObject, true);
  23538. },
  23539. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23540. onClick: function(event)
  23541. {
  23542. var target = event.srcElement || event.target;
  23543. var repNode = Firebug.getRepNode(target);
  23544. if (repNode)
  23545. {
  23546. var row = getAncestorByClass(target, "memberRow");
  23547. if (row)
  23548. {
  23549. this.selectRow(row, repNode);
  23550. cancelEvent(event);
  23551. }
  23552. }
  23553. },
  23554. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23555. // extends Panel
  23556. name: "DOM",
  23557. title: "DOM",
  23558. searchable: true,
  23559. statusSeparator: ">",
  23560. options: {
  23561. hasToolButtons: true,
  23562. hasStatusBar: true
  23563. },
  23564. create: function()
  23565. {
  23566. Firebug.DOMBasePanel.prototype.create.apply(this, arguments);
  23567. this.onClick = bind(this.onClick, this);
  23568. //TODO: xxxpedro
  23569. this.onClickStatusBar = bind(this.onClickStatusBar, this);
  23570. this.panelNode.style.padding = "0 1px";
  23571. },
  23572. initialize: function(oldPanelNode)
  23573. {
  23574. //this.panelNode.addEventListener("click", this.onClick, false);
  23575. //dispatch([Firebug.A11yModel], 'onInitializeNode', [this, 'console']);
  23576. Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
  23577. addEvent(this.panelNode, "click", this.onClick);
  23578. // TODO: xxxpedro dom
  23579. this.ishow();
  23580. //TODO: xxxpedro
  23581. addEvent(this.statusBarNode, "click", this.onClickStatusBar);
  23582. },
  23583. shutdown: function()
  23584. {
  23585. //this.panelNode.removeEventListener("click", this.onClick, false);
  23586. //dispatch([Firebug.A11yModel], 'onDestroyNode', [this, 'console']);
  23587. removeEvent(this.panelNode, "click", this.onClick);
  23588. Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments);
  23589. }/*,
  23590. search: function(text, reverse)
  23591. {
  23592. if (!text)
  23593. {
  23594. delete this.currentSearch;
  23595. this.highlightRow(null);
  23596. return false;
  23597. }
  23598. var row;
  23599. if (this.currentSearch && text == this.currentSearch.text)
  23600. row = this.currentSearch.findNext(true, undefined, reverse, Firebug.searchCaseSensitive);
  23601. else
  23602. {
  23603. function findRow(node) { return getAncestorByClass(node, "memberRow"); }
  23604. this.currentSearch = new TextSearch(this.panelNode, findRow);
  23605. row = this.currentSearch.find(text, reverse, Firebug.searchCaseSensitive);
  23606. }
  23607. if (row)
  23608. {
  23609. var sel = this.document.defaultView.getSelection();
  23610. sel.removeAllRanges();
  23611. sel.addRange(this.currentSearch.range);
  23612. scrollIntoCenterView(row, this.panelNode);
  23613. this.highlightRow(row);
  23614. dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, row]);
  23615. return true;
  23616. }
  23617. else
  23618. {
  23619. dispatch([Firebug.A11yModel], 'onDomSearchMatchFound', [this, text, null]);
  23620. return false;
  23621. }
  23622. }/**/
  23623. });
  23624. Firebug.registerPanel(DOMMainPanel);
  23625. // ************************************************************************************************
  23626. // ************************************************************************************************
  23627. // Local Helpers
  23628. var getMembers = function getMembers(object, level) // we expect object to be user-level object wrapped in security blanket
  23629. {
  23630. if (!level)
  23631. level = 0;
  23632. var ordinals = [], userProps = [], userClasses = [], userFuncs = [],
  23633. domProps = [], domFuncs = [], domConstants = [];
  23634. try
  23635. {
  23636. var domMembers = getDOMMembers(object);
  23637. //var domMembers = {}; // TODO: xxxpedro
  23638. //var domConstantMap = {}; // TODO: xxxpedro
  23639. if (object.wrappedJSObject)
  23640. var insecureObject = object.wrappedJSObject;
  23641. else
  23642. var insecureObject = object;
  23643. // IE function prototype is not listed in (for..in)
  23644. if (isIE && isFunction(object))
  23645. addMember("user", userProps, "prototype", object.prototype, level);
  23646. for (var name in insecureObject) // enumeration is safe
  23647. {
  23648. if (ignoreVars[name] == 1) // javascript.options.strict says ignoreVars is undefined.
  23649. continue;
  23650. var val;
  23651. try
  23652. {
  23653. val = insecureObject[name]; // getter is safe
  23654. }
  23655. catch (exc)
  23656. {
  23657. // Sometimes we get exceptions trying to access certain members
  23658. if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM)
  23659. FBTrace.sysout("dom.getMembers cannot access "+name, exc);
  23660. }
  23661. var ordinal = parseInt(name);
  23662. if (ordinal || ordinal == 0)
  23663. {
  23664. addMember("ordinal", ordinals, name, val, level);
  23665. }
  23666. else if (isFunction(val))
  23667. {
  23668. if (isClassFunction(val) && !(name in domMembers))
  23669. addMember("userClass", userClasses, name, val, level);
  23670. else if (name in domMembers)
  23671. addMember("domFunction", domFuncs, name, val, level, domMembers[name]);
  23672. else
  23673. addMember("userFunction", userFuncs, name, val, level);
  23674. }
  23675. else
  23676. {
  23677. //TODO: xxxpedro
  23678. /*
  23679. var getterFunction = insecureObject.__lookupGetter__(name),
  23680. setterFunction = insecureObject.__lookupSetter__(name),
  23681. prefix = "";
  23682. if(getterFunction && !setterFunction)
  23683. prefix = "get ";
  23684. /**/
  23685. var prefix = "";
  23686. if (name in domMembers && !(name in domConstantMap))
  23687. addMember("dom", domProps, (prefix+name), val, level, domMembers[name]);
  23688. else if (name in domConstantMap)
  23689. addMember("dom", domConstants, (prefix+name), val, level);
  23690. else
  23691. addMember("user", userProps, (prefix+name), val, level);
  23692. }
  23693. }
  23694. }
  23695. catch (exc)
  23696. {
  23697. // Sometimes we get exceptions just from trying to iterate the members
  23698. // of certain objects, like StorageList, but don't let that gum up the works
  23699. throw exc;
  23700. if (FBTrace.DBG_ERRORS && FBTrace.DBG_DOM)
  23701. FBTrace.sysout("dom.getMembers FAILS: ", exc);
  23702. //throw exc;
  23703. }
  23704. function sortName(a, b) { return a.name > b.name ? 1 : -1; }
  23705. function sortOrder(a, b) { return a.order > b.order ? 1 : -1; }
  23706. var members = [];
  23707. members.push.apply(members, ordinals);
  23708. Firebug.showUserProps = true; // TODO: xxxpedro
  23709. Firebug.showUserFuncs = true; // TODO: xxxpedro
  23710. Firebug.showDOMProps = true;
  23711. Firebug.showDOMFuncs = true;
  23712. Firebug.showDOMConstants = true;
  23713. if (Firebug.showUserProps)
  23714. {
  23715. userProps.sort(sortName);
  23716. members.push.apply(members, userProps);
  23717. }
  23718. if (Firebug.showUserFuncs)
  23719. {
  23720. userClasses.sort(sortName);
  23721. members.push.apply(members, userClasses);
  23722. userFuncs.sort(sortName);
  23723. members.push.apply(members, userFuncs);
  23724. }
  23725. if (Firebug.showDOMProps)
  23726. {
  23727. domProps.sort(sortName);
  23728. members.push.apply(members, domProps);
  23729. }
  23730. if (Firebug.showDOMFuncs)
  23731. {
  23732. domFuncs.sort(sortName);
  23733. members.push.apply(members, domFuncs);
  23734. }
  23735. if (Firebug.showDOMConstants)
  23736. members.push.apply(members, domConstants);
  23737. return members;
  23738. }
  23739. function expandMembers(members, toggles, offset, level) // recursion starts with offset=0, level=0
  23740. {
  23741. var expanded = 0;
  23742. for (var i = offset; i < members.length; ++i)
  23743. {
  23744. var member = members[i];
  23745. if (member.level > level)
  23746. break;
  23747. if ( toggles.hasOwnProperty(member.name) )
  23748. {
  23749. member.open = "opened"; // member.level <= level && member.name in toggles.
  23750. var newMembers = getMembers(member.value, level+1); // sets newMembers.level to level+1
  23751. var args = [i+1, 0];
  23752. args.push.apply(args, newMembers);
  23753. members.splice.apply(members, args);
  23754. /*
  23755. if (FBTrace.DBG_DOM)
  23756. {
  23757. FBTrace.sysout("expandMembers member.name", member.name);
  23758. FBTrace.sysout("expandMembers toggles", toggles);
  23759. FBTrace.sysout("expandMembers toggles[member.name]", toggles[member.name]);
  23760. FBTrace.sysout("dom.expandedMembers level: "+level+" member", member);
  23761. }
  23762. /**/
  23763. expanded += newMembers.length;
  23764. i += newMembers.length + expandMembers(members, toggles[member.name], i+1, level+1);
  23765. }
  23766. }
  23767. return expanded;
  23768. }
  23769. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23770. function isClassFunction(fn)
  23771. {
  23772. try
  23773. {
  23774. for (var name in fn.prototype)
  23775. return true;
  23776. } catch (exc) {}
  23777. return false;
  23778. }
  23779. var hasProperties = function hasProperties(ob)
  23780. {
  23781. try
  23782. {
  23783. for (var name in ob)
  23784. return true;
  23785. } catch (exc) {}
  23786. // IE function prototype is not listed in (for..in)
  23787. if (isFunction(ob)) return true;
  23788. return false;
  23789. }
  23790. FBL.ErrorCopy = function(message)
  23791. {
  23792. this.message = message;
  23793. };
  23794. var addMember = function addMember(type, props, name, value, level, order)
  23795. {
  23796. var rep = Firebug.getRep(value); // do this first in case a call to instanceof reveals contents
  23797. var tag = rep.shortTag ? rep.shortTag : rep.tag;
  23798. var ErrorCopy = function(){}; //TODO: xxxpedro
  23799. var valueType = typeof(value);
  23800. var hasChildren = hasProperties(value) && !(value instanceof ErrorCopy) &&
  23801. (isFunction(value) || (valueType == "object" && value != null)
  23802. || (valueType == "string" && value.length > Firebug.stringCropLength));
  23803. props.push({
  23804. name: name,
  23805. value: value,
  23806. type: type,
  23807. rowClass: "memberRow-"+type,
  23808. open: "",
  23809. order: order,
  23810. level: level,
  23811. indent: level*16,
  23812. hasChildren: hasChildren,
  23813. tag: tag
  23814. });
  23815. }
  23816. var getWatchRowIndex = function getWatchRowIndex(row)
  23817. {
  23818. var index = -1;
  23819. for (; row && hasClass(row, "watchRow"); row = row.previousSibling)
  23820. ++index;
  23821. return index;
  23822. }
  23823. var getRowName = function getRowName(row)
  23824. {
  23825. var node = row.firstChild;
  23826. return node.textContent ? node.textContent : node.innerText;
  23827. }
  23828. var getRowValue = function getRowValue(row)
  23829. {
  23830. return row.lastChild.firstChild.repObject;
  23831. }
  23832. var getRowOwnerObject = function getRowOwnerObject(row)
  23833. {
  23834. var parentRow = getParentRow(row);
  23835. if (parentRow)
  23836. return getRowValue(parentRow);
  23837. }
  23838. var getParentRow = function getParentRow(row)
  23839. {
  23840. var level = parseInt(row.getAttribute("level"))-1;
  23841. for (row = row.previousSibling; row; row = row.previousSibling)
  23842. {
  23843. if (parseInt(row.getAttribute("level")) == level)
  23844. return row;
  23845. }
  23846. }
  23847. var getPath = function getPath(row)
  23848. {
  23849. var name = getRowName(row);
  23850. var path = [name];
  23851. var level = parseInt(row.getAttribute("level"))-1;
  23852. for (row = row.previousSibling; row; row = row.previousSibling)
  23853. {
  23854. if (parseInt(row.getAttribute("level")) == level)
  23855. {
  23856. var name = getRowName(row);
  23857. path.splice(0, 0, name);
  23858. --level;
  23859. }
  23860. }
  23861. return path;
  23862. }
  23863. // ************************************************************************************************
  23864. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23865. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23866. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23867. // ************************************************************************************************
  23868. // DOM Module
  23869. Firebug.DOM = extend(Firebug.Module,
  23870. {
  23871. getPanel: function()
  23872. {
  23873. return Firebug.chrome ? Firebug.chrome.getPanel("DOM") : null;
  23874. }
  23875. });
  23876. Firebug.registerModule(Firebug.DOM);
  23877. // ************************************************************************************************
  23878. // DOM Panel
  23879. var lastHighlightedObject;
  23880. function DOMSidePanel(){};
  23881. DOMSidePanel.prototype = extend(Firebug.DOMBasePanel.prototype,
  23882. {
  23883. selectRow: function(row, target)
  23884. {
  23885. if (!target)
  23886. target = row.lastChild.firstChild;
  23887. if (!target || !target.repObject)
  23888. return;
  23889. this.pathToAppend = getPath(row);
  23890. // If the object is inside an array, look up its index
  23891. var valueBox = row.lastChild.firstChild;
  23892. if (hasClass(valueBox, "objectBox-array"))
  23893. {
  23894. var arrayIndex = FirebugReps.Arr.getItemIndex(target);
  23895. this.pathToAppend.push(arrayIndex);
  23896. }
  23897. // Make sure we get a fresh status path for the object, since otherwise
  23898. // it might find the object in the existing path and not refresh it
  23899. //Firebug.chrome.clearStatusPath();
  23900. var object = target.repObject;
  23901. if (instanceOf(object, "Element"))
  23902. {
  23903. Firebug.HTML.selectTreeNode(ElementCache(object));
  23904. }
  23905. else
  23906. {
  23907. Firebug.chrome.selectPanel("DOM");
  23908. Firebug.chrome.getPanel("DOM").select(object, true);
  23909. }
  23910. },
  23911. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23912. onClick: function(event)
  23913. {
  23914. /*
  23915. var target = event.srcElement || event.target;
  23916. var object = getAncestorByClass(target, "objectLink");
  23917. object = object ? object.repObject : null;
  23918. if(!object) return;
  23919. if (instanceOf(object, "Element"))
  23920. {
  23921. Firebug.HTML.selectTreeNode(ElementCache(object));
  23922. }
  23923. else
  23924. {
  23925. Firebug.chrome.selectPanel("DOM");
  23926. Firebug.chrome.getPanel("DOM").select(object, true);
  23927. }
  23928. /**/
  23929. var target = event.srcElement || event.target;
  23930. var repNode = Firebug.getRepNode(target);
  23931. if (repNode)
  23932. {
  23933. var row = getAncestorByClass(target, "memberRow");
  23934. if (row)
  23935. {
  23936. this.selectRow(row, repNode);
  23937. cancelEvent(event);
  23938. }
  23939. }
  23940. /**/
  23941. },
  23942. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23943. // extends Panel
  23944. name: "DOMSidePanel",
  23945. parentPanel: "HTML",
  23946. title: "DOM",
  23947. options: {
  23948. hasToolButtons: true
  23949. },
  23950. isInitialized: false,
  23951. create: function()
  23952. {
  23953. Firebug.DOMBasePanel.prototype.create.apply(this, arguments);
  23954. this.onClick = bind(this.onClick, this);
  23955. },
  23956. initialize: function(){
  23957. Firebug.DOMBasePanel.prototype.initialize.apply(this, arguments);
  23958. addEvent(this.panelNode, "click", this.onClick);
  23959. // TODO: xxxpedro css2
  23960. var selection = ElementCache.get(FirebugChrome.selectedHTMLElementId);
  23961. if (selection)
  23962. this.select(selection, true);
  23963. },
  23964. shutdown: function()
  23965. {
  23966. removeEvent(this.panelNode, "click", this.onClick);
  23967. Firebug.DOMBasePanel.prototype.shutdown.apply(this, arguments);
  23968. },
  23969. reattach: function(oldChrome)
  23970. {
  23971. //this.isInitialized = oldChrome.getPanel("DOM").isInitialized;
  23972. this.toggles = oldChrome.getPanel("DOMSidePanel").toggles;
  23973. }
  23974. });
  23975. Firebug.registerPanel(DOMSidePanel);
  23976. // ************************************************************************************************
  23977. }});
  23978. /* See license.txt for terms of usage */
  23979. FBL.FBTrace = {};
  23980. (function() {
  23981. // ************************************************************************************************
  23982. var traceOptions = {
  23983. DBG_TIMESTAMP: 1,
  23984. DBG_INITIALIZE: 1,
  23985. DBG_CHROME: 1,
  23986. DBG_ERRORS: 1,
  23987. DBG_DISPATCH: 1,
  23988. DBG_CSS: 1
  23989. };
  23990. this.module = null;
  23991. this.initialize = function()
  23992. {
  23993. if (!this.messageQueue)
  23994. this.messageQueue = [];
  23995. for (var name in traceOptions)
  23996. this[name] = traceOptions[name];
  23997. };
  23998. // ************************************************************************************************
  23999. // FBTrace API
  24000. this.sysout = function()
  24001. {
  24002. return this.logFormatted(arguments, "");
  24003. };
  24004. this.dumpProperties = function(title, object)
  24005. {
  24006. return this.logFormatted("dumpProperties() not supported.", "warning");
  24007. };
  24008. this.dumpStack = function()
  24009. {
  24010. return this.logFormatted("dumpStack() not supported.", "warning");
  24011. };
  24012. this.flush = function(module)
  24013. {
  24014. this.module = module;
  24015. var queue = this.messageQueue;
  24016. this.messageQueue = [];
  24017. for (var i = 0; i < queue.length; ++i)
  24018. this.writeMessage(queue[i][0], queue[i][1], queue[i][2]);
  24019. };
  24020. this.getPanel = function()
  24021. {
  24022. return this.module ? this.module.getPanel() : null;
  24023. };
  24024. //*************************************************************************************************
  24025. this.logFormatted = function(objects, className)
  24026. {
  24027. var html = this.DBG_TIMESTAMP ? [getTimestamp(), " | "] : [];
  24028. var length = objects.length;
  24029. for (var i = 0; i < length; ++i)
  24030. {
  24031. appendText(" ", html);
  24032. var object = objects[i];
  24033. if (i == 0)
  24034. {
  24035. html.push("<b>");
  24036. appendText(object, html);
  24037. html.push("</b>");
  24038. }
  24039. else
  24040. appendText(object, html);
  24041. }
  24042. return this.logRow(html, className);
  24043. };
  24044. this.logRow = function(message, className)
  24045. {
  24046. var panel = this.getPanel();
  24047. if (panel && panel.panelNode)
  24048. this.writeMessage(message, className);
  24049. else
  24050. {
  24051. this.messageQueue.push([message, className]);
  24052. }
  24053. return this.LOG_COMMAND;
  24054. };
  24055. this.writeMessage = function(message, className)
  24056. {
  24057. var container = this.getPanel().containerNode;
  24058. var isScrolledToBottom =
  24059. container.scrollTop + container.offsetHeight >= container.scrollHeight;
  24060. this.writeRow.call(this, message, className);
  24061. if (isScrolledToBottom)
  24062. container.scrollTop = container.scrollHeight - container.offsetHeight;
  24063. };
  24064. this.appendRow = function(row)
  24065. {
  24066. var container = this.getPanel().panelNode;
  24067. container.appendChild(row);
  24068. };
  24069. this.writeRow = function(message, className)
  24070. {
  24071. var row = this.getPanel().panelNode.ownerDocument.createElement("div");
  24072. row.className = "logRow" + (className ? " logRow-"+className : "");
  24073. row.innerHTML = message.join("");
  24074. this.appendRow(row);
  24075. };
  24076. //*************************************************************************************************
  24077. function appendText(object, html)
  24078. {
  24079. html.push(escapeHTML(objectToString(object)));
  24080. };
  24081. function getTimestamp()
  24082. {
  24083. var now = new Date();
  24084. var ms = "" + (now.getMilliseconds() / 1000).toFixed(3);
  24085. ms = ms.substr(2);
  24086. return now.toLocaleTimeString() + "." + ms;
  24087. };
  24088. //*************************************************************************************************
  24089. var HTMLtoEntity =
  24090. {
  24091. "<": "&lt;",
  24092. ">": "&gt;",
  24093. "&": "&amp;",
  24094. "'": "&#39;",
  24095. '"': "&quot;"
  24096. };
  24097. function replaceChars(ch)
  24098. {
  24099. return HTMLtoEntity[ch];
  24100. };
  24101. function escapeHTML(value)
  24102. {
  24103. return (value+"").replace(/[<>&"']/g, replaceChars);
  24104. };
  24105. //*************************************************************************************************
  24106. function objectToString(object)
  24107. {
  24108. try
  24109. {
  24110. return object+"";
  24111. }
  24112. catch (exc)
  24113. {
  24114. return null;
  24115. }
  24116. };
  24117. // ************************************************************************************************
  24118. }).apply(FBL.FBTrace);
  24119. /* See license.txt for terms of usage */
  24120. FBL.ns(function() { with (FBL) {
  24121. // ************************************************************************************************
  24122. // If application isn't in trace mode, the FBTrace panel won't be loaded
  24123. if (!Env.Options.enableTrace) return;
  24124. // ************************************************************************************************
  24125. // FBTrace Module
  24126. Firebug.Trace = extend(Firebug.Module,
  24127. {
  24128. getPanel: function()
  24129. {
  24130. return Firebug.chrome ? Firebug.chrome.getPanel("Trace") : null;
  24131. },
  24132. clear: function()
  24133. {
  24134. this.getPanel().panelNode.innerHTML = "";
  24135. }
  24136. });
  24137. Firebug.registerModule(Firebug.Trace);
  24138. // ************************************************************************************************
  24139. // FBTrace Panel
  24140. function TracePanel(){};
  24141. TracePanel.prototype = extend(Firebug.Panel,
  24142. {
  24143. name: "Trace",
  24144. title: "Trace",
  24145. options: {
  24146. hasToolButtons: true,
  24147. innerHTMLSync: true
  24148. },
  24149. create: function(){
  24150. Firebug.Panel.create.apply(this, arguments);
  24151. this.clearButton = new Button({
  24152. caption: "Clear",
  24153. title: "Clear FBTrace logs",
  24154. owner: Firebug.Trace,
  24155. onClick: Firebug.Trace.clear
  24156. });
  24157. },
  24158. initialize: function(){
  24159. Firebug.Panel.initialize.apply(this, arguments);
  24160. this.clearButton.initialize();
  24161. }
  24162. });
  24163. Firebug.registerPanel(TracePanel);
  24164. // ************************************************************************************************
  24165. }});
  24166. /* See license.txt for terms of usage */
  24167. FBL.ns(function() { with (FBL) {
  24168. // ************************************************************************************************
  24169. // ************************************************************************************************
  24170. // Globals
  24171. var modules = [];
  24172. var panelTypes = [];
  24173. var panelTypeMap = {};
  24174. var parentPanelMap = {};
  24175. var registerModule = Firebug.registerModule;
  24176. var registerPanel = Firebug.registerPanel;
  24177. // ************************************************************************************************
  24178. append(Firebug,
  24179. {
  24180. extend: function(fn)
  24181. {
  24182. if (Firebug.chrome && Firebug.chrome.addPanel)
  24183. {
  24184. var namespace = ns(fn);
  24185. fn.call(namespace, FBL);
  24186. }
  24187. else
  24188. {
  24189. setTimeout(function(){Firebug.extend(fn);},100);
  24190. }
  24191. },
  24192. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  24193. // Registration
  24194. registerModule: function()
  24195. {
  24196. registerModule.apply(Firebug, arguments);
  24197. modules.push.apply(modules, arguments);
  24198. dispatch(modules, "initialize", []);
  24199. if (FBTrace.DBG_INITIALIZE) FBTrace.sysout("Firebug.registerModule");
  24200. },
  24201. registerPanel: function()
  24202. {
  24203. registerPanel.apply(Firebug, arguments);
  24204. panelTypes.push.apply(panelTypes, arguments);
  24205. for (var i = 0, panelType; panelType = arguments[i]; ++i)
  24206. {
  24207. // TODO: xxxpedro investigate why Dev Panel throws an error
  24208. if (panelType.prototype.name == "Dev") continue;
  24209. panelTypeMap[panelType.prototype.name] = arguments[i];
  24210. var parentPanelName = panelType.prototype.parentPanel;
  24211. if (parentPanelName)
  24212. {
  24213. parentPanelMap[parentPanelName] = 1;
  24214. }
  24215. else
  24216. {
  24217. var panelName = panelType.prototype.name;
  24218. var chrome = Firebug.chrome;
  24219. chrome.addPanel(panelName);
  24220. // tab click handler
  24221. var onTabClick = function onTabClick()
  24222. {
  24223. chrome.selectPanel(panelName);
  24224. return false;
  24225. };
  24226. chrome.addController([chrome.panelMap[panelName].tabNode, "mousedown", onTabClick]);
  24227. }
  24228. }
  24229. if (FBTrace.DBG_INITIALIZE)
  24230. for (var i = 0; i < arguments.length; ++i)
  24231. FBTrace.sysout("Firebug.registerPanel", arguments[i].prototype.name);
  24232. }
  24233. });
  24234. // ************************************************************************************************
  24235. }});
  24236. FBL.ns(function() { with (FBL) {
  24237. // ************************************************************************************************
  24238. FirebugChrome.Skin =
  24239. {
  24240. CSS: '.collapsed{display:none;}[collapsed="true"]{display:none;}#fbCSS{padding:0 !important;}.cssPropDisable{float:left;display:block;width:2em;cursor:default;}.infoTip{z-index:2147483647;position:fixed;padding:2px 3px;border:1px solid #CBE087;background:LightYellow;font-family:Monaco,monospace;color:#000000;display:none;white-space:nowrap;pointer-events:none;}.infoTip[active="true"]{display:block;}.infoTipLoading{width:16px;height:16px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif) no-repeat;}.infoTipImageBox{font-size:11px;min-width:100px;text-align:center;}.infoTipCaption{font-size:11px;font:Monaco,monospace;}.infoTipLoading > .infoTipImage,.infoTipLoading > .infoTipCaption{display:none;}h1.groupHeader{padding:2px 4px;margin:0 0 4px 0;border-top:1px solid #CCCCCC;border-bottom:1px solid #CCCCCC;background:#eee url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x;font-size:11px;font-weight:bold;_position:relative;}.inlineEditor,.fixedWidthEditor{z-index:2147483647;position:absolute;display:none;}.inlineEditor{margin-left:-6px;margin-top:-3px;}.textEditorInner,.fixedWidthEditor{margin:0 0 0 0 !important;padding:0;border:none !important;font:inherit;text-decoration:inherit;background-color:#FFFFFF;}.fixedWidthEditor{border-top:1px solid #888888 !important;border-bottom:1px solid #888888 !important;}.textEditorInner{position:relative;top:-7px;left:-5px;outline:none;resize:none;}.textEditorInner1{padding-left:11px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y;_overflow:hidden;}.textEditorInner2{position:relative;padding-right:2px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.png) repeat-y 100% 0;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorBorders.gif) repeat-y 100% 0;_position:fixed;}.textEditorTop1{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 0;margin-left:11px;height:10px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 0;_overflow:hidden;}.textEditorTop2{position:relative;left:-11px;width:11px;height:10px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat;}.textEditorBottom1{position:relative;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 100% 100%;margin-left:11px;height:12px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 100% 100%;}.textEditorBottom2{position:relative;left:-11px;width:11px;height:12px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.png) no-repeat 0 100%;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/textEditorCorners.gif) no-repeat 0 100%;}.panelNode-css{overflow-x:hidden;}.cssSheet > .insertBefore{height:1.5em;}.cssRule{position:relative;margin:0;padding:1em 0 0 6px;font-family:Monaco,monospace;color:#000000;}.cssRule:first-child{padding-top:6px;}.cssElementRuleContainer{position:relative;}.cssHead{padding-right:150px;}.cssProp{}.cssPropName{color:DarkGreen;}.cssPropValue{margin-left:8px;color:DarkBlue;}.cssOverridden span{text-decoration:line-through;}.cssInheritedRule{}.cssInheritLabel{margin-right:0.5em;font-weight:bold;}.cssRule .objectLink-sourceLink{top:0;}.cssProp.editGroup:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disable.gif) no-repeat 2px 1px;}.cssProp.editGroup.editing{background:none;}.cssProp.disabledStyle{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.png) no-repeat 2px 1px;_background:url(https://getfirebug.com/releases/lite/latest/skin/xp/disableHover.gif) no-repeat 2px 1px;opacity:1;color:#CCCCCC;}.disabledStyle .cssPropName,.disabledStyle .cssPropValue{color:#CCCCCC;}.cssPropValue.editing + .cssSemi,.inlineExpander + .cssSemi{display:none;}.cssPropValue.editing{white-space:nowrap;}.stylePropName{font-weight:bold;padding:0 4px 4px 4px;width:50%;}.stylePropValue{width:50%;}.panelNode-net{overflow-x:hidden;}.netTable{width:100%;}.hideCategory-undefined .category-undefined,.hideCategory-html .category-html,.hideCategory-css .category-css,.hideCategory-js .category-js,.hideCategory-image .category-image,.hideCategory-xhr .category-xhr,.hideCategory-flash .category-flash,.hideCategory-txt .category-txt,.hideCategory-bin .category-bin{display:none;}.netHeadRow{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netHeadCol{border-bottom:1px solid #CCCCCC;padding:2px 4px 2px 18px;font-weight:bold;}.netHeadLabel{white-space:nowrap;overflow:hidden;}.netHeaderRow{height:16px;}.netHeaderCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;background:#BBBBBB url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeader.gif) repeat-x;white-space:nowrap;}.netHeaderRow > .netHeaderCell:first-child > .netHeaderCellBox{padding:2px 14px 2px 18px;}.netHeaderCellBox{padding:2px 14px 2px 10px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.netHeaderCell:hover:active{background:#959595 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderActive.gif) repeat-x;}.netHeaderSorted{background:#7D93B2 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSorted.gif) repeat-x;}.netHeaderSorted > .netHeaderCellBox{border-right-color:#6B7C93;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowDown.png) no-repeat right;}.netHeaderSorted.sortedAscending > .netHeaderCellBox{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/arrowUp.png);}.netHeaderSorted:hover:active{background:#536B90 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/tableHeaderSortedActive.gif) repeat-x;}.panelNode-net .netRowHeader{display:block;}.netRowHeader{cursor:pointer;display:none;height:15px;margin-right:0 !important;}.netRow .netRowHeader{background-position:5px 1px;}.netRow[breakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpoint.png);}.netRow[breakpoint="true"][disabledBreakpoint="true"] .netRowHeader{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/breakpointDisabled.png);}.netRow.category-xhr:hover .netRowHeader{background-color:#F6F6F6;}#netBreakpointBar{max-width:38px;}#netHrefCol > .netHeaderCellBox{border-left:0px;}.netRow .netRowHeader{width:3px;}.netInfoRow .netRowHeader{display:table-cell;}.netTable[hiddenCols~=netHrefCol] TD[id="netHrefCol"],.netTable[hiddenCols~=netHrefCol] TD.netHrefCol,.netTable[hiddenCols~=netStatusCol] TD[id="netStatusCol"],.netTable[hiddenCols~=netStatusCol] TD.netStatusCol,.netTable[hiddenCols~=netDomainCol] TD[id="netDomainCol"],.netTable[hiddenCols~=netDomainCol] TD.netDomainCol,.netTable[hiddenCols~=netSizeCol] TD[id="netSizeCol"],.netTable[hiddenCols~=netSizeCol] TD.netSizeCol,.netTable[hiddenCols~=netTimeCol] TD[id="netTimeCol"],.netTable[hiddenCols~=netTimeCol] TD.netTimeCol{display:none;}.netRow{background:LightYellow;}.netRow.loaded{background:#FFFFFF;}.netRow.loaded:hover{background:#EFEFEF;}.netCol{padding:0;vertical-align:top;border-bottom:1px solid #EFEFEF;white-space:nowrap;height:17px;}.netLabel{width:100%;}.netStatusCol{padding-left:10px;color:rgb(128,128,128);}.responseError > .netStatusCol{color:red;}.netDomainCol{padding-left:5px;}.netSizeCol{text-align:right;padding-right:10px;}.netHrefLabel{-moz-box-sizing:padding-box;overflow:hidden;z-index:10;position:absolute;padding-left:18px;padding-top:1px;max-width:15%;font-weight:bold;}.netFullHrefLabel{display:none;-moz-user-select:none;padding-right:10px;padding-bottom:3px;max-width:100%;background:#FFFFFF;z-index:200;}.netHrefCol:hover > .netFullHrefLabel{display:block;}.netRow.loaded:hover .netCol > .netFullHrefLabel{background-color:#EFEFEF;}.useA11y .a11yShowFullLabel{display:block;background-image:none !important;border:1px solid #CBE087;background-color:LightYellow;font-family:Monaco,monospace;color:#000000;font-size:10px;z-index:2147483647;}.netSizeLabel{padding-left:6px;}.netStatusLabel,.netDomainLabel,.netSizeLabel,.netBar{padding:1px 0 2px 0 !important;}.responseError{color:red;}.hasHeaders .netHrefLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.netLoadingIcon{position:absolute;border:0;margin-left:14px;width:16px;height:16px;background:transparent no-repeat 0 0;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/loading_16.gif);display:inline-block;}.loaded .netLoadingIcon{display:none;}.netBar,.netSummaryBar{position:relative;border-right:50px solid transparent;}.netResolvingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResolving.gif) repeat-x;z-index:60;}.netConnectingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarConnecting.gif) repeat-x;z-index:50;}.netBlockingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarWaiting.gif) repeat-x;z-index:40;}.netSendingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarSending.gif) repeat-x;z-index:30;}.netWaitingBar{position:absolute;left:0;top:0;bottom:0;background:#FFFFFF url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarResponded.gif) repeat-x;z-index:20;min-width:1px;}.netReceivingBar{position:absolute;left:0;top:0;bottom:0;background:#38D63B url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoading.gif) repeat-x;z-index:10;}.netWindowLoadBar,.netContentLoadBar{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:red;z-index:70;opacity:0.5;display:none;margin-bottom:-1px;}.netContentLoadBar{background-color:Blue;}.netTimeLabel{-moz-box-sizing:padding-box;position:absolute;top:1px;left:100%;padding-left:6px;color:#444444;min-width:16px;}.loaded .netReceivingBar,.loaded.netReceivingBar{background:#B6B6B6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarLoaded.gif) repeat-x;border-color:#B6B6B6;}.fromCache .netReceivingBar,.fromCache.netReceivingBar{background:#D6D6D6 url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/netBarCached.gif) repeat-x;border-color:#D6D6D6;}.netSummaryRow .netTimeLabel,.loaded .netTimeLabel{background:transparent;}.timeInfoTip{width:150px; height:40px}.timeInfoTipBar,.timeInfoTipEventBar{position:relative;display:block;margin:0;opacity:1;height:15px;width:4px;}.timeInfoTipEventBar{width:1px !important;}.timeInfoTipCell.startTime{padding-right:8px;}.timeInfoTipCell.elapsedTime{text-align:right;padding-right:8px;}.sizeInfoLabelCol{font-weight:bold;padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;}.sizeInfoSizeCol{font-weight:bold;}.sizeInfoDetailCol{color:gray;text-align:right;}.sizeInfoDescCol{font-style:italic;}.netSummaryRow .netReceivingBar{background:#BBBBBB;border:none;}.netSummaryLabel{color:#222222;}.netSummaryRow{background:#BBBBBB !important;font-weight:bold;}.netSummaryRow .netBar{border-right-color:#BBBBBB;}.netSummaryRow > .netCol{border-top:1px solid #999999;border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:1px;padding-bottom:2px;}.netSummaryRow > .netHrefCol:hover{background:transparent !important;}.netCountLabel{padding-left:18px;}.netTotalSizeCol{text-align:right;padding-right:10px;}.netTotalTimeCol{text-align:right;}.netCacheSizeLabel{position:absolute;z-index:1000;left:0;top:0;}.netLimitRow{background:rgb(255,255,225) !important;font-weight:normal;color:black;font-weight:normal;}.netLimitLabel{padding-left:18px;}.netLimitRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;vertical-align:middle !important;padding-top:2px;padding-bottom:2px;}.netLimitButton{font-size:11px;padding-top:1px;padding-bottom:1px;}.netInfoCol{border-top:1px solid #EEEEEE;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/group.gif) repeat-x #FFFFFF;}.netInfoBody{margin:10px 0 4px 10px;}.netInfoTabs{position:relative;padding-left:17px;}.netInfoTab{position:relative;top:-3px;margin-top:10px;padding:4px 6px;border:1px solid transparent;border-bottom:none;_border:none;font-weight:bold;color:#565656;cursor:pointer;}.netInfoTabSelected{cursor:default !important;border:1px solid #D7D7D7 !important;border-bottom:none !important;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;background-color:#FFFFFF;}.logRow-netInfo.error .netInfoTitle{color:red;}.logRow-netInfo.loading .netInfoResponseText{font-style:italic;color:#888888;}.loading .netInfoResponseHeadersTitle{display:none;}.netInfoResponseSizeLimit{font-family:Lucida Grande,Tahoma,sans-serif;padding-top:10px;font-size:11px;}.netInfoText{display:none;margin:0;border:1px solid #D7D7D7;border-right:none;padding:8px;background-color:#FFFFFF;font-family:Monaco,monospace;white-space:pre-wrap;}.netInfoTextSelected{display:block;}.netInfoParamName{padding-right:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;vertical-align:top;text-align:right;white-space:nowrap;}.netInfoPostText .netInfoParamName{width:1px;}.netInfoParamValue{width:100%;}.netInfoHeadersText,.netInfoPostText,.netInfoPutText{padding-top:0;}.netInfoHeadersGroup,.netInfoPostParams,.netInfoPostSource{margin-bottom:4px;border-bottom:1px solid #D7D7D7;padding-top:8px;padding-bottom:2px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#565656;}.netInfoPostParamsTable,.netInfoPostPartsTable,.netInfoPostJSONTable,.netInfoPostXMLTable,.netInfoPostSourceTable{margin-bottom:10px;width:100%;}.netInfoPostContentType{color:#bdbdbd;padding-left:50px;font-weight:normal;}.netInfoHtmlPreview{border:0;width:100%;height:100%;}.netHeadersViewSource{color:#bdbdbd;margin-left:200px;font-weight:normal;}.netHeadersViewSource:hover{color:blue;cursor:pointer;}.netActivationRow,.netPageSeparatorRow{background:rgb(229,229,229) !important;font-weight:normal;color:black;}.netActivationLabel{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/chrome://firebug/skin/infoIcon.png) no-repeat 3px 2px;padding-left:22px;}.netPageSeparatorRow{height:5px !important;}.netPageSeparatorLabel{padding-left:22px;height:5px !important;}.netPageRow{background-color:rgb(255,255,255);}.netPageRow:hover{background:#EFEFEF;}.netPageLabel{padding:1px 0 2px 18px !important;font-weight:bold;}.netActivationRow > .netCol{border-bottom:2px solid;-moz-border-bottom-colors:#EFEFEF #999999;padding-top:2px;padding-bottom:3px;}.twisty,.logRow-errorMessage > .hasTwisty > .errorTitle,.logRow-log > .objectBox-array.hasTwisty,.logRow-spy .spyHead .spyTitle,.logGroup > .logRow,.memberRow.hasChildren > .memberLabelCell > .memberLabel,.hasHeaders .netHrefLabel,.netPageRow > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;min-height:12px;}.logRow-errorMessage > .hasTwisty.opened > .errorTitle,.logRow-log > .objectBox-array.hasTwisty.opened,.logRow-spy.opened .spyHead .spyTitle,.logGroup.opened > .logRow,.memberRow.hasChildren.opened > .memberLabelCell > .memberLabel,.nodeBox.highlightOpen > .nodeLabel > .twisty,.nodeBox.open > .nodeLabel > .twisty,.netRow.opened > .netCol > .netHrefLabel,.netPageRow.opened > .netCol > .netPageTitle{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}.twisty{background-position:4px 4px;}* html .logRow-spy .spyHead .spyTitle,* html .logGroup .logGroupLabel,* html .hasChildren .memberLabelCell .memberLabel,* html .hasHeaders .netHrefLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);background-repeat:no-repeat;background-position:2px 2px;}* html .opened .spyHead .spyTitle,* html .opened .logGroupLabel,* html .opened .memberLabelCell .memberLabel{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);background-repeat:no-repeat;background-position:2px 2px;}.panelNode-console{overflow-x:hidden;}.objectLink{text-decoration:none;}.objectLink:hover{cursor:pointer;text-decoration:underline;}.logRow{position:relative;margin:0;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;background-color:#FFFFFF;overflow:hidden !important;}.useA11y .logRow:focus{border-bottom:1px solid #000000 !important;outline:none !important;background-color:#FFFFAD !important;}.useA11y .logRow:focus a.objectLink-sourceLink{background-color:#FFFFAD;}.useA11y .a11yFocus:focus,.useA11y .objectBox:focus{outline:2px solid #FF9933;background-color:#FFFFAD;}.useA11y .objectBox-null:focus,.useA11y .objectBox-undefined:focus{background-color:#888888 !important;}.useA11y .logGroup.opened > .logRow{border-bottom:1px solid #ffffff;}.logGroup{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding:0 !important;border:none !important;}.logGroupBody{display:none;margin-left:16px;border-left:1px solid #D7D7D7;border-top:1px solid #D7D7D7;background:#FFFFFF;}.logGroup > .logRow{background-color:transparent !important;font-weight:bold;}.logGroup.opened > .logRow{border-bottom:none;}.logGroup.opened > .logGroupBody{display:block;}.logRow-command > .objectBox-text{font-family:Monaco,monospace;color:#0000FF;white-space:pre-wrap;}.logRow-info,.logRow-warn,.logRow-error,.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-left:22px;background-repeat:no-repeat;background-position:4px 2px;}.logRow-assert,.logRow-warningMessage,.logRow-errorMessage{padding-top:0;padding-bottom:0;}.logRow-info,.logRow-info .objectLink-sourceLink{background-color:#FFFFFF;}.logRow-warn,.logRow-warningMessage,.logRow-warn .objectLink-sourceLink,.logRow-warningMessage .objectLink-sourceLink{background-color:cyan;}.logRow-error,.logRow-assert,.logRow-errorMessage,.logRow-error .objectLink-sourceLink,.logRow-errorMessage .objectLink-sourceLink{background-color:LightYellow;}.logRow-error,.logRow-assert,.logRow-errorMessage{color:#FF0000;}.logRow-info{}.logRow-warn,.logRow-warningMessage{}.logRow-error,.logRow-assert,.logRow-errorMessage{}.objectBox-string,.objectBox-text,.objectBox-number,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-string,.objectBox-text,.objectLink-textNode{white-space:pre-wrap;}.objectBox-number,.objectLink-styleRule,.objectLink-element,.objectLink-textNode{color:#000088;}.objectBox-string{color:#FF0000;}.objectLink-function,.objectBox-stackTrace,.objectLink-profile{color:DarkGreen;}.objectBox-null,.objectBox-undefined{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-exception{padding:0 2px 0 18px;color:red;}.objectLink-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.errorTitle{margin-top:0px;margin-bottom:1px;padding-top:2px;padding-bottom:2px;}.errorTrace{margin-left:17px;}.errorSourceBox{margin:2px 0;}.errorSource-none{display:none;}.errorSource-syntax > .errorBreak{visibility:hidden;}.errorSource{cursor:pointer;font-family:Monaco,monospace;color:DarkGreen;}.errorSource:hover{text-decoration:underline;}.errorBreak{cursor:pointer;display:none;margin:0 6px 0 0;width:13px;height:14px;vertical-align:bottom;opacity:0.1;}.hasBreakSwitch .errorBreak{display:inline;}.breakForError .errorBreak{opacity:1;}.assertDescription{margin:0;}.logRow-profile > .logRow > .objectBox-text{font-family:Lucida Grande,Tahoma,sans-serif;color:#000000;}.logRow-profile > .logRow > .objectBox-text:last-child{color:#555555;font-style:italic;}.logRow-profile.opened > .logRow{padding-bottom:4px;}.profilerRunning > .logRow{padding-left:22px !important;}.profileSizer{width:100%;overflow-x:auto;overflow-y:scroll;}.profileTable{border-bottom:1px solid #D7D7D7;padding:0 0 4px 0;}.profileTable tr[odd="1"]{background-color:#F5F5F5;vertical-align:middle;}.profileTable a{vertical-align:middle;}.profileTable td{padding:1px 4px 0 4px;}.headerCell{cursor:pointer;-moz-user-select:none;border-bottom:1px solid #9C9C9C;padding:0 !important;font-weight:bold;}.headerCellBox{padding:2px 4px;border-left:1px solid #D9D9D9;border-right:1px solid #9C9C9C;}.headerCell:hover:active{}.headerSorted{}.headerSorted > .headerCellBox{border-right-color:#6B7C93;}.headerSorted.sortedAscending > .headerCellBox{}.headerSorted:hover:active{}.linkCell{text-align:right;}.linkCell > .objectLink-sourceLink{position:static;}.logRow-stackTrace{padding-top:0;background:#f8f8f8;}.logRow-stackTrace > .objectBox-stackFrame{position:relative;padding-top:2px;}.objectLink-object{font-family:Lucida Grande,sans-serif;font-weight:bold;color:DarkGreen;white-space:pre-wrap;}.objectProp-object{color:DarkGreen;}.objectProps{color:#000;font-weight:normal;}.objectPropName{color:#777;}.objectProps .objectProp-string{color:#f55;}.objectProps .objectProp-number{color:#55a;}.objectProps .objectProp-object{color:#585;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.selectorHidden > .selectorTag{color:#5F82D9;}.selectorHidden > .selectorId{color:#888888;}.selectorHidden > .selectorClass{color:#D86060;}.selectorValue{font-family:Lucida Grande,sans-serif;font-style:italic;color:#555555;}.panelNode.searching .logRow{display:none;}.logRow.matched{display:block !important;}.logRow.matching{position:absolute;left:-1000px;top:-1000px;max-width:0;max-height:0;overflow:hidden;}.objectLeftBrace,.objectRightBrace,.objectEqual,.objectComma,.arrayLeftBracket,.arrayRightBracket,.arrayComma{font-family:Monaco,monospace;}.objectLeftBrace,.objectRightBrace,.arrayLeftBracket,.arrayRightBracket{font-weight:bold;}.objectLeftBrace,.arrayLeftBracket{margin-right:4px;}.objectRightBrace,.arrayRightBracket{margin-left:4px;}.logRow-dir{padding:0;}.logRow-errorMessage .hasTwisty .errorTitle,.logRow-spy .spyHead .spyTitle,.logGroup .logRow{cursor:pointer;padding-left:18px;background-repeat:no-repeat;background-position:3px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle{background-position:2px 3px;}.logRow-errorMessage > .hasTwisty > .errorTitle:hover,.logRow-spy .spyHead .spyTitle:hover,.logGroup > .logRow:hover{text-decoration:underline;}.logRow-spy{padding:0 !important;}.logRow-spy,.logRow-spy .objectLink-sourceLink{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/group.gif) repeat-x #FFFFFF;padding-right:4px;right:0;}.logRow-spy.opened{padding-bottom:4px;border-bottom:none;}.spyTitle{color:#000000;font-weight:bold;-moz-box-sizing:padding-box;overflow:hidden;z-index:100;padding-left:18px;}.spyCol{padding:0;white-space:nowrap;height:16px;}.spyTitleCol:hover > .objectLink-sourceLink,.spyTitleCol:hover > .spyTime,.spyTitleCol:hover > .spyStatus,.spyTitleCol:hover > .spyTitle{display:none;}.spyFullTitle{display:none;-moz-user-select:none;max-width:100%;background-color:Transparent;}.spyTitleCol:hover > .spyFullTitle{display:block;}.spyStatus{padding-left:10px;color:rgb(128,128,128);}.spyTime{margin-left:4px;margin-right:4px;color:rgb(128,128,128);}.spyIcon{margin-right:4px;margin-left:4px;width:16px;height:16px;vertical-align:middle;background:transparent no-repeat 0 0;display:none;}.loading .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/loading_16.gif);display:block;}.logRow-spy.loaded:not(.error) .spyHead .spyRow .spyIcon{width:0;margin:0;}.logRow-spy.error .spyHead .spyRow .spyIcon{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon-sm.png);display:block;background-position:2px 2px;}.logRow-spy .spyHead .netInfoBody{display:none;}.logRow-spy.opened .spyHead .netInfoBody{margin-top:10px;display:block;}.logRow-spy.error .spyTitle,.logRow-spy.error .spyStatus,.logRow-spy.error .spyTime{color:red;}.logRow-spy.loading .spyResponseText{font-style:italic;color:#888888;}.caption{font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#444444;}.warning{padding:10px;font-family:Lucida Grande,Tahoma,sans-serif;font-weight:bold;color:#888888;}.panelNode-dom{overflow-x:hidden !important;}.domTable{font-size:1em;width:100%;table-layout:fixed;background:#fff;}.domTableIE{width:auto;}.memberLabelCell{padding:2px 0 2px 0;vertical-align:top;}.memberValueCell{padding:1px 0 1px 5px;display:block;overflow:hidden;}.memberLabel{display:block;cursor:default;-moz-user-select:none;overflow:hidden;padding-left:18px;background-color:#FFFFFF;text-decoration:none;}.memberRow.hasChildren .memberLabelCell .memberLabel:hover{cursor:pointer;color:blue;text-decoration:underline;}.userLabel{color:#000000;font-weight:bold;}.userClassLabel{color:#E90000;font-weight:bold;}.userFunctionLabel{color:#025E2A;font-weight:bold;}.domLabel{color:#000000;}.domFunctionLabel{color:#025E2A;}.ordinalLabel{color:SlateBlue;font-weight:bold;}.scopesRow{padding:2px 18px;background-color:LightYellow;border-bottom:5px solid #BEBEBE;color:#666666;}.scopesLabel{background-color:LightYellow;}.watchEditCell{padding:2px 18px;background-color:LightYellow;border-bottom:1px solid #BEBEBE;color:#666666;}.editor-watchNewRow,.editor-memberRow{font-family:Monaco,monospace !important;}.editor-memberRow{padding:1px 0 !important;}.editor-watchRow{padding-bottom:0 !important;}.watchRow > .memberLabelCell{font-family:Monaco,monospace;padding-top:1px;padding-bottom:1px;}.watchRow > .memberLabelCell > .memberLabel{background-color:transparent;}.watchRow > .memberValueCell{padding-top:2px;padding-bottom:2px;}.watchRow > .memberLabelCell,.watchRow > .memberValueCell{background-color:#F5F5F5;border-bottom:1px solid #BEBEBE;}.watchToolbox{z-index:2147483647;position:absolute;right:0;padding:1px 2px;}#fbConsole{overflow-x:hidden !important;}#fbCSS{font:1em Monaco,monospace;padding:0 7px;}#fbstylesheetButtons select,#fbScriptButtons select{font:11px Lucida Grande,Tahoma,sans-serif;margin-top:1px;padding-left:3px;background:#fafafa;border:1px inset #fff;width:220px;outline:none;}.Selector{margin-top:10px}.CSSItem{margin-left:4%}.CSSText{padding-left:20px;}.CSSProperty{color:#005500;}.CSSValue{padding-left:5px; color:#000088;}#fbHTMLStatusBar{display:inline;}.fbToolbarButtons{display:none;}.fbStatusSeparator{display:block;float:left;padding-top:4px;}#fbStatusBarBox{display:none;}#fbToolbarContent{display:block;position:absolute;_position:absolute;top:0;padding-top:4px;height:23px;clip:rect(0,2048px,27px,0);}.fbTabMenuTarget{display:none !important;float:left;width:10px;height:10px;margin-top:6px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTarget.png);}.fbTabMenuTarget:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuTargetHover.png);}.fbShadow{float:left;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadowAlpha.png) no-repeat bottom right !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/shadow2.gif) no-repeat bottom right;margin:10px 0 0 10px !important;margin:10px 0 0 5px;}.fbShadowContent{display:block;position:relative;background-color:#fff;border:1px solid #a9a9a9;top:-6px;left:-6px;}.fbMenu{display:none;position:absolute;font-size:11px;z-index:2147483647;}.fbMenuContent{padding:2px;}.fbMenuSeparator{display:block;position:relative;padding:1px 18px 0;text-decoration:none;color:#000;cursor:default;background:#ACA899;margin:4px 0;}.fbMenuOption{display:block;position:relative;padding:2px 18px;text-decoration:none;color:#000;cursor:default;}.fbMenuOption:hover{color:#fff;background:#316AC5;}.fbMenuGroup{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right 0;}.fbMenuGroup:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuGroupSelected{color:#fff;background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuPin.png) no-repeat right -17px;}.fbMenuChecked{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px 0;}.fbMenuChecked:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuCheckbox.png) no-repeat 4px -17px;}.fbMenuRadioSelected{background:transparent url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px 0;}.fbMenuRadioSelected:hover{background:#316AC5 url(https://getfirebug.com/releases/lite/latest/skin/xp/tabMenuRadio.png) no-repeat 4px -17px;}.fbMenuShortcut{padding-right:85px;}.fbMenuShortcutKey{position:absolute;right:0;top:2px;width:77px;}#fbFirebugMenu{top:22px;left:0;}.fbMenuDisabled{color:#ACA899 !important;}#fbFirebugSettingsMenu{left:245px;top:99px;}#fbConsoleMenu{top:42px;left:48px;}.fbIconButton{display:block;}.fbIconButton{display:block;}.fbIconButton{display:block;float:left;height:20px;width:20px;color:#000;margin-right:2px;text-decoration:none;cursor:default;}.fbIconButton:hover{position:relative;top:-1px;left:-1px;margin-right:0;_margin-right:1px;color:#333;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbIconPressed{position:relative;margin-right:0;_margin-right:1px;top:0 !important;left:0 !important;height:19px;color:#333 !important;border:1px solid #bbb !important;border-bottom:1px solid #cfcfcf !important;border-right:1px solid #ddd !important;}#fbErrorPopup{position:absolute;right:0;bottom:0;height:19px;width:75px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;z-index:999;}#fbErrorPopupContent{position:absolute;right:0;top:1px;height:18px;width:75px;_width:74px;border-left:1px solid #aca899;}#fbErrorIndicator{position:absolute;top:2px;right:5px;}.fbBtnInspectActive{background:#aaa;color:#fff !important;}.fbBody{margin:0;padding:0;overflow:hidden;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;background:#fff;}.clear{clear:both;}#fbMiniChrome{display:none;right:0;height:27px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;margin-left:1px;}#fbMiniContent{display:block;position:relative;left:-1px;right:0;top:1px;height:25px;border-left:1px solid #aca899;}#fbToolbarSearch{float:right;border:1px solid #ccc;margin:0 5px 0 0;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.png) no-repeat 4px 2px !important;background:#fff url(https://getfirebug.com/releases/lite/latest/skin/xp/search.gif) no-repeat 4px 2px;padding-left:20px;font-size:11px;}#fbToolbarErrors{float:right;margin:1px 4px 0 0;font-size:11px;}#fbLeftToolbarErrors{float:left;margin:7px 0px 0 5px;font-size:11px;}.fbErrors{padding-left:20px;height:14px;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) no-repeat !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif) no-repeat;color:#f00;font-weight:bold;}#fbMiniErrors{display:inline;display:none;float:right;margin:5px 2px 0 5px;}#fbMiniIcon{float:right;margin:3px 4px 0;height:20px;width:20px;float:right;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;cursor:pointer;}#fbChrome{font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;position:absolute;_position:static;top:0;left:0;height:100%;width:100%;border-collapse:collapse;border-spacing:0;background:#fff;overflow:hidden;}#fbChrome > tbody > tr > td{padding:0;}#fbTop{height:49px;}#fbToolbar{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;height:27px;font-size:11px;}#fbPanelBarBox{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;height:22px;}#fbContent{height:100%;vertical-align:top;}#fbBottom{height:18px;background:#fff;}#fbToolbarIcon{float:left;padding:0 5px 0;}#fbToolbarIcon a{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -135px;}#fbToolbarButtons{padding:0 2px 0 5px;}#fbToolbarButtons{padding:0 2px 0 5px;}.fbButton{text-decoration:none;display:block;float:left;color:#000;padding:4px 6px 4px 7px;cursor:default;}.fbButton:hover{color:#333;background:#f5f5ef url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBg.png);padding:3px 5px 3px 6px;border:1px solid #fff;border-bottom:1px solid #bbb;border-right:1px solid #bbb;}.fbBtnPressed{background:#e3e3db url(https://getfirebug.com/releases/lite/latest/skin/xp/buttonBgHover.png) !important;padding:3px 4px 2px 6px !important;margin:1px 0 0 1px !important;border:1px solid #ACA899 !important;border-color:#ACA899 #ECEBE3 #ECEBE3 #ACA899 !important;}#fbStatusBarBox{top:4px;cursor:default;}.fbToolbarSeparator{overflow:hidden;border:1px solid;border-color:transparent #fff transparent #777;_border-color:#eee #fff #eee #777;height:7px;margin:6px 3px;float:left;}.fbBtnSelected{font-weight:bold;}.fbStatusBar{color:#aca899;}.fbStatusBar a{text-decoration:none;color:black;}.fbStatusBar a:hover{color:blue;cursor:pointer;}#fbWindowButtons{position:absolute;white-space:nowrap;right:0;top:0;height:17px;width:48px;padding:5px;z-index:6;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 0;}#fbPanelBar1{width:1024px; z-index:8;left:0;white-space:nowrap;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;left:4px;}#fbPanelBar2Box{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #dbd9c9 0 -27px;position:absolute;height:22px;width:300px; z-index:9;right:0;}#fbPanelBar2{position:absolute;width:290px; height:22px;padding-left:4px;}.fbPanel{display:none;}#fbPanelBox1,#fbPanelBox2{max-height:inherit;height:100%;font-size:1em;}#fbPanelBox2{background:#fff;}#fbPanelBox2{width:300px;background:#fff;}#fbPanel2{margin-left:6px;background:#fff;}#fbLargeCommandLine{display:none;position:absolute;z-index:9;top:27px;right:0;width:294px;height:201px;border-width:0;margin:0;padding:2px 0 0 2px;resize:none;outline:none;font-size:11px;overflow:auto;border-top:1px solid #B9B7AF;_right:-1px;_border-left:1px solid #fff;}#fbLargeCommandButtons{display:none;background:#ECE9D8;bottom:0;right:0;width:294px;height:21px;padding-top:1px;position:fixed;border-top:1px solid #ACA899;z-index:9;}#fbSmallCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/down.png) no-repeat;position:absolute;right:2px;bottom:3px;z-index:99;}#fbSmallCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/downHover.png) no-repeat;}.hide{overflow:hidden !important;position:fixed !important;display:none !important;visibility:hidden !important;}#fbCommand{height:18px;}#fbCommandBox{position:fixed;_position:absolute;width:100%;height:18px;bottom:0;overflow:hidden;z-index:9;background:#fff;border:0;border-top:1px solid #ccc;}#fbCommandIcon{position:absolute;color:#00f;top:2px;left:6px;display:inline;font:11px Monaco,monospace;z-index:10;}#fbCommandLine{position:absolute;width:100%;top:0;left:0;border:0;margin:0;padding:2px 0 2px 32px;font:11px Monaco,monospace;z-index:9;outline:none;}#fbLargeCommandLineIcon{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/up.png) no-repeat;position:absolute;right:1px;bottom:1px;z-index:10;}#fbLargeCommandLineIcon:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/upHover.png) no-repeat;}div.fbFitHeight{overflow:auto;position:relative;}.fbSmallButton{overflow:hidden;width:16px;height:16px;display:block;text-decoration:none;cursor:default;}#fbWindowButtons .fbSmallButton{float:right;}#fbWindow_btClose{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/min.png);}#fbWindow_btClose:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/minHover.png);}#fbWindow_btDetach{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detach.png);}#fbWindow_btDetach:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/detachHover.png);}#fbWindow_btDeactivate{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/off.png);}#fbWindow_btDeactivate:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/offHover.png);}.fbTab{text-decoration:none;display:none;float:left;width:auto;float:left;cursor:default;font-family:Lucida Grande,Tahoma,sans-serif;font-size:11px;font-weight:bold;height:22px;color:#565656;}.fbPanelBar span{float:left;}.fbPanelBar .fbTabL,.fbPanelBar .fbTabR{height:22px;width:8px;}.fbPanelBar .fbTabText{padding:4px 1px 0;}a.fbTab:hover{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -73px;}a.fbTab:hover .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -16px -96px;}a.fbTab:hover .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -24px -96px;}.fbSelectedTab{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) #f1f2ee 0 -50px !important;color:#000;}.fbSelectedTab .fbTabL{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) 0 -96px !important;}.fbSelectedTab .fbTabR{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/sprite.png) -8px -96px !important;}#fbHSplitter{position:fixed;_position:absolute;left:0;top:0;width:100%;height:5px;overflow:hidden;cursor:n-resize !important;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/pixel_transparent.gif);z-index:9;}#fbHSplitter.fbOnMovingHSplitter{height:100%;z-index:100;}.fbVSplitter{background:#ece9d8;color:#000;border:1px solid #716f64;border-width:0 1px;border-left-color:#aca899;width:4px;cursor:e-resize;overflow:hidden;right:294px;text-decoration:none;z-index:10;position:absolute;height:100%;top:27px;}div.lineNo{font:1em Monaco,monospace;position:relative;float:left;top:0;left:0;margin:0 5px 0 0;padding:0 5px 0 10px;background:#eee;color:#888;border-right:1px solid #ccc;text-align:right;}.sourceBox{position:absolute;}.sourceCode{font:1em Monaco,monospace;overflow:hidden;white-space:pre;display:inline;}.nodeControl{margin-top:3px;margin-left:-14px;float:left;width:9px;height:9px;overflow:hidden;cursor:default;background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_open.gif);_float:none;_display:inline;_position:absolute;}div.nodeMaximized{background:url(https://getfirebug.com/releases/lite/latest/skin/xp/tree_close.gif);}div.objectBox-element{padding:1px 3px;}.objectBox-selector{cursor:default;}.selectedElement{background:highlight;color:#fff !important;}.selectedElement span{color:#fff !important;}* html .selectedElement{position:relative;}@media screen and (-webkit-min-device-pixel-ratio:0){.selectedElement{background:#316AC5;color:#fff !important;}}.logRow *{font-size:1em;}.logRow{position:relative;border-bottom:1px solid #D7D7D7;padding:2px 4px 1px 6px;zbackground-color:#FFFFFF;}.logRow-command{font-family:Monaco,monospace;color:blue;}.objectBox-string,.objectBox-text,.objectBox-number,.objectBox-function,.objectLink-element,.objectLink-textNode,.objectLink-function,.objectBox-stackTrace,.objectLink-profile{font-family:Monaco,monospace;}.objectBox-null{padding:0 2px;border:1px solid #666666;background-color:#888888;color:#FFFFFF;}.objectBox-string{color:red;}.objectBox-number{color:#000088;}.objectBox-function{color:DarkGreen;}.objectBox-object{color:DarkGreen;font-weight:bold;font-family:Lucida Grande,sans-serif;}.objectBox-array{color:#000;}.logRow-info,.logRow-error,.logRow-warn{background:#fff no-repeat 2px 2px;padding-left:20px;padding-bottom:3px;}.logRow-info{background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/infoIcon.gif);}.logRow-warn{background-color:cyan;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/warningIcon.gif);}.logRow-error{background-color:LightYellow;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.png) !important;background-image:url(https://getfirebug.com/releases/lite/latest/skin/xp/errorIcon.gif);color:#f00;}.errorMessage{vertical-align:top;color:#f00;}.objectBox-sourceLink{position:absolute;right:4px;top:2px;padding-left:8px;font-family:Lucida Grande,sans-serif;font-weight:bold;color:#0000FF;}.selectorTag,.selectorId,.selectorClass{font-family:Monaco,monospace;font-weight:normal;}.selectorTag{color:#0000FF;}.selectorId{color:DarkBlue;}.selectorClass{color:red;}.objectBox-element{font-family:Monaco,monospace;color:#000088;}.nodeChildren{padding-left:26px;}.nodeTag{color:blue;cursor:pointer;}.nodeValue{color:#FF0000;font-weight:normal;}.nodeText,.nodeComment{margin:0 2px;vertical-align:top;}.nodeText{color:#333333;font-family:Monaco,monospace;}.nodeComment{color:DarkGreen;}.nodeHidden,.nodeHidden *{color:#888888;}.nodeHidden .nodeTag{color:#5F82D9;}.nodeHidden .nodeValue{color:#D86060;}.selectedElement .nodeHidden,.selectedElement .nodeHidden *{color:SkyBlue !important;}.log-object{}.property{position:relative;clear:both;height:15px;}.propertyNameCell{vertical-align:top;float:left;width:28%;position:absolute;left:0;z-index:0;}.propertyValueCell{float:right;width:68%;background:#fff;position:absolute;padding-left:5px;display:table-cell;right:0;z-index:1;}.propertyName{font-weight:bold;}.FirebugPopup{height:100% !important;}.FirebugPopup #fbWindowButtons{display:none !important;}.FirebugPopup #fbHSplitter{display:none !important;}',
  24241. HTML: '<table id="fbChrome" cellpadding="0" cellspacing="0" border="0"><tbody><tr><td id="fbTop" colspan="2"><div id="fbWindowButtons"><a id="fbWindow_btDeactivate" class="fbSmallButton fbHover" title="Deactivate Firebug for this web page">&nbsp;</a><a id="fbWindow_btDetach" class="fbSmallButton fbHover" title="Open Firebug in popup window">&nbsp;</a><a id="fbWindow_btClose" class="fbSmallButton fbHover" title="Minimize Firebug">&nbsp;</a></div><div id="fbToolbar"><div id="fbToolbarContent"><span id="fbToolbarIcon"><a id="fbFirebugButton" class="fbIconButton" class="fbHover" target="_blank">&nbsp;</a></span><span id="fbToolbarButtons"><span id="fbFixedButtons"><a id="fbChrome_btInspect" class="fbButton fbHover" title="Click an element in the page to inspect">Inspect</a></span><span id="fbConsoleButtons" class="fbToolbarButtons"><a id="fbConsole_btClear" class="fbButton fbHover" title="Clear the console">Clear</a></span></span><span id="fbStatusBarBox"><span class="fbToolbarSeparator"></span></span></div></div><div id="fbPanelBarBox"><div id="fbPanelBar1" class="fbPanelBar"><a id="fbConsoleTab" class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">Console</span><span class="fbTabMenuTarget"></span><span class="fbTabR"></span></a><a id="fbHTMLTab" class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">HTML</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">CSS</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">Script</span><span class="fbTabR"></span></a><a class="fbTab fbHover"><span class="fbTabL"></span><span class="fbTabText">DOM</span><span class="fbTabR"></span></a></div><div id="fbPanelBar2Box" class="hide"><div id="fbPanelBar2" class="fbPanelBar"></div></div></div><div id="fbHSplitter">&nbsp;</div></td></tr><tr id="fbContent"><td id="fbPanelBox1"><div id="fbPanel1" class="fbFitHeight"><div id="fbConsole" class="fbPanel"></div><div id="fbHTML" class="fbPanel"></div></div></td><td id="fbPanelBox2" class="hide"><div id="fbVSplitter" class="fbVSplitter">&nbsp;</div><div id="fbPanel2" class="fbFitHeight"><div id="fbHTML_Style" class="fbPanel"></div><div id="fbHTML_Layout" class="fbPanel"></div><div id="fbHTML_DOM" class="fbPanel"></div></div><textarea id="fbLargeCommandLine" class="fbFitHeight"></textarea><div id="fbLargeCommandButtons"><a id="fbCommand_btRun" class="fbButton fbHover">Run</a><a id="fbCommand_btClear" class="fbButton fbHover">Clear</a><a id="fbSmallCommandLineIcon" class="fbSmallButton fbHover"></a></div></td></tr><tr id="fbBottom" class="hide"><td id="fbCommand" colspan="2"><div id="fbCommandBox"><div id="fbCommandIcon">&gt;&gt;&gt;</div><input id="fbCommandLine" name="fbCommandLine" type="text"/><a id="fbLargeCommandLineIcon" class="fbSmallButton fbHover"></a></div></td></tr></tbody></table><span id="fbMiniChrome"><span id="fbMiniContent"><span id="fbMiniIcon" title="Open Firebug Lite"></span><span id="fbMiniErrors" class="fbErrors">2 errors</span></span></span>'
  24242. };
  24243. // ************************************************************************************************
  24244. }});
  24245. // ************************************************************************************************
  24246. FBL.initialize();
  24247. // ************************************************************************************************
  24248. })();