kissy.js 465 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103
  1. /*
  2. Copyright 2012, KISSY UI Library v1.30dev
  3. MIT Licensed
  4. build time: Jan 10 14:34
  5. */
  6. /*
  7. * @fileOverview a seed where KISSY grows up from , KISS Yeah !
  8. * @author lifesinger@gmail.com,yiminghe@gmail.com
  9. */
  10. (function (S, undefined) {
  11. /**
  12. * @namespace
  13. * @name KISSY
  14. */
  15. var host = this,
  16. meta = {
  17. /**
  18. * Copies all the properties of s to r.
  19. * @memberOf KISSY
  20. * @param {Object} r the augmented object
  21. * @param {Object} s the object need to augment
  22. * @param {boolean} [ov=true] whether overwrite existing property
  23. * @param {String[]} [wl] array of white-list properties
  24. * @param deep {boolean} whether recursive mix if encounter object
  25. * @return {Object} the augmented object
  26. */
  27. mix:function (r, s, ov, wl, deep) {
  28. if (!s || !r) {
  29. return r;
  30. }
  31. if (ov === undefined) {
  32. ov = true;
  33. }
  34. var i, p, len;
  35. if (wl && (len = wl.length)) {
  36. for (i = 0; i < len; i++) {
  37. p = wl[i];
  38. if (p in s) {
  39. _mix(p, r, s, ov, deep);
  40. }
  41. }
  42. } else {
  43. for (p in s) {
  44. // no hasOwnProperty judge !
  45. _mix(p, r, s, ov, deep);
  46. }
  47. }
  48. return r;
  49. }
  50. },
  51. _mix = function (p, r, s, ov, deep) {
  52. if (ov || !(p in r)) {
  53. var target = r[p], src = s[p];
  54. // prevent never-end loop
  55. if (target === src) {
  56. return;
  57. }
  58. // 来源是数组和对象,并且要求深度 mix
  59. if (deep && src && (S.isArray(src) || S.isPlainObject(src))) {
  60. // 目标值为对象或数组,直接 mix
  61. // 否则 新建一个和源值类型一样的空数组/对象,递归 mix
  62. var clone = target && (S.isArray(target) || S.isPlainObject(target)) ?
  63. target :
  64. (S.isArray(src) ? [] : {});
  65. r[p] = S.mix(clone, src, ov, undefined, true);
  66. } else if (src !== undefined) {
  67. r[p] = s[p];
  68. }
  69. }
  70. },
  71. // If KISSY is already defined, the existing KISSY object will not
  72. // be overwritten so that defined namespaces are preserved.
  73. seed = (host && host[S]) || {},
  74. guid = 0,
  75. EMPTY = '';
  76. // The host of runtime environment. specify by user's seed or <this>,
  77. // compatibled for '<this> is null' in unknown engine.
  78. host = seed.__HOST || (seed.__HOST = host || {});
  79. // shortcut and meta for seed.
  80. // override previous kissy
  81. S = host[S] = meta.mix(seed, meta);
  82. S.mix(S,
  83. /**
  84. * @lends KISSY
  85. */
  86. {
  87. /**
  88. * @private
  89. */
  90. configs:{},
  91. // S.app() with these members.
  92. __APP_MEMBERS:['namespace'],
  93. __APP_INIT_METHODS:['__init'],
  94. /**
  95. * The version of the library.
  96. * @type {String}
  97. */
  98. version:'1.30dev',
  99. /**
  100. * The build time of the library
  101. * @type {String}
  102. */
  103. buildTime:'20120110143426',
  104. /**
  105. * Returns a new object containing all of the properties of
  106. * all the supplied objects. The properties from later objects
  107. * will overwrite those in earlier objects. Passing in a
  108. * single object will create a shallow copy of it.
  109. * @param {...} m1 objects need to be merged
  110. * @return {Object} the new merged object
  111. */
  112. merge:function (m1) {
  113. var o = {}, i, l = arguments.length;
  114. for (i = 0; i < l; i++) {
  115. S.mix(o, arguments[i]);
  116. }
  117. return o;
  118. },
  119. /**
  120. * Applies prototype properties from the supplier to the receiver.
  121. * @param {Object} r received object
  122. * @param {...Object} s1 object need to augment
  123. * {boolean} [ov=true] whether overwrite existing property
  124. * {String[]} [wl] array of white-list properties
  125. * @return {Object} the augmented object
  126. */
  127. augment:function (r, s1) {
  128. var args = S.makeArray(arguments),
  129. len = args.length - 2,
  130. i = 1;
  131. r = args[0];
  132. ov = args[len];
  133. wl = args[len + 1];
  134. if (!S.isArray(wl)) {
  135. ov = wl;
  136. wl = undefined;
  137. len++;
  138. }
  139. if (!S.isBoolean(ov)) {
  140. ov = undefined;
  141. len++;
  142. }
  143. for (; i < len; i++) {
  144. S.mix(r.prototype, args[i].prototype || args[i], ov, wl);
  145. }
  146. return r;
  147. },
  148. /**
  149. * Utility to set up the prototype, constructor and superclass properties to
  150. * support an inheritance strategy that can chain constructors and methods.
  151. * Static members will not be inherited.
  152. * @param r {Function} the object to modify
  153. * @param s {Function} the object to inherit
  154. * @param px {Object} prototype properties to add/override
  155. * @param {Object} [sx] static properties to add/override
  156. * @return r {Object}
  157. */
  158. extend:function (r, s, px, sx) {
  159. if (!s || !r) {
  160. return r;
  161. }
  162. var create = Object.create ?
  163. function (proto, c) {
  164. return Object.create(proto, {
  165. constructor:{
  166. value:c
  167. }
  168. });
  169. } :
  170. function (proto, c) {
  171. function F() {
  172. }
  173. F.prototype = proto;
  174. var o = new F();
  175. o.constructor = c;
  176. return o;
  177. },
  178. sp = s.prototype,
  179. rp;
  180. // add prototype chain
  181. rp = create(sp, r);
  182. r.prototype = S.mix(rp, r.prototype);
  183. r.superclass = create(sp, s);
  184. // add prototype overrides
  185. if (px) {
  186. S.mix(rp, px);
  187. }
  188. // add object overrides
  189. if (sx) {
  190. S.mix(r, sx);
  191. }
  192. return r;
  193. },
  194. /****************************************************************************************
  195. * The KISSY System Framework *
  196. ****************************************************************************************/
  197. /**
  198. * Initializes KISSY
  199. */
  200. __init:function () {
  201. this.Config = this.Config || {};
  202. this.Env = this.Env || {};
  203. // NOTICE: '@DEBUG@' will replace with '' when compressing.
  204. // So, if loading source file, debug is on by default.
  205. // If loading min version, debug is turned off automatically.
  206. this.Config.debug = '@DEBUG@';
  207. },
  208. /**
  209. * Returns the namespace specified and creates it if it doesn't exist. Be careful
  210. * when naming packages. Reserved words may work in some browsers and not others.
  211. * <code>
  212. * S.namespace('KISSY.app'); // returns KISSY.app
  213. * S.namespace('app.Shop'); // returns KISSY.app.Shop
  214. * S.namespace('TB.app.Shop', true); // returns TB.app.Shop
  215. * </code>
  216. * @return {Object} A reference to the last namespace object created
  217. */
  218. namespace:function () {
  219. var args = S.makeArray(arguments),
  220. l = args.length,
  221. o = null, i, j, p,
  222. global = (args[l - 1] === true && l--);
  223. for (i = 0; i < l; i++) {
  224. p = (EMPTY + args[i]).split('.');
  225. o = global ? host : this;
  226. for (j = (host[p[0]] === o) ? 1 : 0; j < p.length; ++j) {
  227. o = o[p[j]] = o[p[j]] || { };
  228. }
  229. }
  230. return o;
  231. },
  232. /**
  233. * create app based on KISSY.
  234. * @param name {String} the app name
  235. * @param sx {Object} static properties to add/override
  236. * <code>
  237. * S.app('TB');
  238. * TB.namespace('app'); // returns TB.app
  239. * </code>
  240. * @return {Object} A reference to the app global object
  241. */
  242. app:function (name, sx) {
  243. var isStr = S.isString(name),
  244. O = isStr ? host[name] || {} : name,
  245. i = 0,
  246. len = S.__APP_INIT_METHODS.length;
  247. S.mix(O, this, true, S.__APP_MEMBERS);
  248. for (; i < len; i++) {
  249. S[S.__APP_INIT_METHODS[i]].call(O);
  250. }
  251. S.mix(O, S.isFunction(sx) ? sx() : sx);
  252. isStr && (host[name] = O);
  253. return O;
  254. },
  255. /**
  256. * set KISSY config
  257. * @param c
  258. * @param {Object[]} c.packages
  259. * @param {Array[]} c.map
  260. */
  261. config:function (c) {
  262. var configs, cfg, r;
  263. for (var p in c) {
  264. if (c.hasOwnProperty(p)) {
  265. if ((configs = this['configs']) &&
  266. (cfg = configs[p])) {
  267. r = cfg(c[p]);
  268. }
  269. }
  270. }
  271. return r;
  272. },
  273. /**
  274. * Prints debug info.
  275. * @param msg {String} the message to log.
  276. * @param {String} [cat] the log category for the message. Default
  277. * categories are "info", "warn", "error", "time" etc.
  278. * @param {String} [src] the source of the the message (opt)
  279. */
  280. log:function (msg, cat, src) {
  281. if (S.Config.debug) {
  282. if (src) {
  283. msg = src + ': ' + msg;
  284. }
  285. if (host['console'] !== undefined && console.log) {
  286. console[cat && console[cat] ? cat : 'log'](msg);
  287. }
  288. }
  289. },
  290. /**
  291. * Throws error message.
  292. */
  293. error:function (msg) {
  294. if (S.Config.debug) {
  295. throw msg;
  296. }
  297. },
  298. /*
  299. * Generate a global unique id.
  300. * @param {String} [pre] guid prefix
  301. * @return {String} the guid
  302. */
  303. guid:function (pre) {
  304. return (pre || EMPTY) + guid++;
  305. }
  306. });
  307. S.__init();
  308. return S;
  309. })('KISSY', undefined);
  310. /**
  311. * @fileOverview lang
  312. * @author lifesinger@gmail.com,yiminghe@gmail.com
  313. * @description this code can run in any ecmascript compliant environment
  314. */
  315. (function (S, undefined) {
  316. var host = S.__HOST,
  317. TRUE = true,
  318. FALSE = false,
  319. OP = Object.prototype,
  320. toString = OP.toString,
  321. hasOwnProperty = OP.hasOwnProperty,
  322. AP = Array.prototype,
  323. indexOf = AP.indexOf,
  324. lastIndexOf = AP.lastIndexOf,
  325. filter = AP.filter,
  326. every = AP.every,
  327. some = AP.some,
  328. //reduce = AP.reduce,
  329. trim = String.prototype.trim,
  330. map = AP.map,
  331. EMPTY = '',
  332. HEX_BASE = 16,
  333. CLONE_MARKER = '__~ks_cloned',
  334. COMPARE_MARKER = '__~ks_compared',
  335. STAMP_MARKER = '__~ks_stamped',
  336. RE_TRIM = /^[\s\xa0]+|[\s\xa0]+$/g,
  337. encode = encodeURIComponent,
  338. decode = decodeURIComponent,
  339. SEP = '&',
  340. EQ = '=',
  341. // [[Class]] -> type pairs
  342. class2type = {},
  343. // http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
  344. htmlEntities = {
  345. '&amp;':'&',
  346. '&gt;':'>',
  347. '&lt;':'<',
  348. '&#x60;':'`',
  349. '&#x2F;':'/',
  350. '&quot;':'"',
  351. '&#x27;':"'"
  352. },
  353. reverseEntities = {},
  354. escapeReg,
  355. unEscapeReg,
  356. // - # $ ^ * ( ) + [ ] { } | \ , . ?
  357. escapeRegExp = /[\-#$\^*()+\[\]{}|\\,.?\s]/g;
  358. (function () {
  359. for (var k in htmlEntities) {
  360. if (htmlEntities.hasOwnProperty(k)) {
  361. reverseEntities[htmlEntities[k]] = k;
  362. }
  363. }
  364. })();
  365. function getEscapeReg() {
  366. if (escapeReg) {
  367. return escapeReg
  368. }
  369. var str = EMPTY;
  370. S.each(htmlEntities, function (entity) {
  371. str += entity + '|';
  372. });
  373. str = str.slice(0, -1);
  374. return escapeReg = new RegExp(str, "g");
  375. }
  376. function getUnEscapeReg() {
  377. if (unEscapeReg) {
  378. return unEscapeReg
  379. }
  380. var str = EMPTY;
  381. S.each(reverseEntities, function (entity) {
  382. str += entity + '|';
  383. });
  384. str += '&#(\\d{1,5});';
  385. return unEscapeReg = new RegExp(str, "g");
  386. }
  387. function isValidParamValue(val) {
  388. var t = typeof val;
  389. // If the type of val is null, undefined, number, string, boolean, return true.
  390. return val == null || (t !== 'object' && t !== 'function');
  391. }
  392. S.mix(S,
  393. /**
  394. * @lends KISSY
  395. */
  396. {
  397. /**
  398. * stamp a object by guid
  399. * @param {Object} o object needed to be stamped
  400. * @param {boolean} [readOnly] while set marker on o if marker does not exist
  401. * @param {String} [marker] the marker will be set on Object
  402. * @return guid associated with this object
  403. */
  404. stamp:function (o, readOnly, marker) {
  405. if (!o) {
  406. return o
  407. }
  408. marker = marker || STAMP_MARKER;
  409. var guid = o[marker];
  410. if (guid) {
  411. return guid;
  412. } else if (!readOnly) {
  413. try {
  414. guid = o[marker] = S.guid(marker);
  415. }
  416. catch (e) {
  417. guid = undefined;
  418. }
  419. }
  420. return guid;
  421. },
  422. /**
  423. * empty function
  424. */
  425. noop:function () {
  426. },
  427. /**
  428. * Determine the internal JavaScript [[Class]] of an object.
  429. */
  430. type:function (o) {
  431. return o == null ?
  432. String(o) :
  433. class2type[toString.call(o)] || 'object';
  434. },
  435. /**
  436. * whether o === null
  437. * @param o
  438. */
  439. isNull:function (o) {
  440. return o === null;
  441. },
  442. /**
  443. * whether o === undefined
  444. * @param o
  445. */
  446. isUndefined:function (o) {
  447. return o === undefined;
  448. },
  449. /**
  450. * Checks to see if an object is empty.
  451. */
  452. isEmptyObject:function (o) {
  453. for (var p in o) {
  454. if (p !== undefined) {
  455. return FALSE;
  456. }
  457. }
  458. return TRUE;
  459. },
  460. /**
  461. * Checks to see if an object is a plain object (created using "{}"
  462. * or "new Object()" or "new FunctionClass()").
  463. */
  464. isPlainObject:function (o) {
  465. /**
  466. * note by yiminghe
  467. * isPlainObject(node=document.getElementById("xx")) -> false
  468. * toString.call(node) : ie678 == '[object Object]',other =='[object HTMLElement]'
  469. * 'isPrototypeOf' in node : ie678 === false ,other === true
  470. * refer http://lifesinger.org/blog/2010/12/thinking-of-isplainobject/
  471. */
  472. return o && toString.call(o) === '[object Object]' && 'isPrototypeOf' in o;
  473. },
  474. /**
  475. * 两个目标是否内容相同
  476. * @param a 比较目标1
  477. * @param b 比较目标2
  478. * @returns {boolean} a.equals(b)
  479. */
  480. equals:function (a, b, /*internal use*/mismatchKeys, /*internal use*/mismatchValues) {
  481. // inspired by jasmine
  482. mismatchKeys = mismatchKeys || [];
  483. mismatchValues = mismatchValues || [];
  484. if (a === b) {
  485. return TRUE;
  486. }
  487. if (a === undefined || a === null || b === undefined || b === null) {
  488. // need type coercion
  489. return a == null && b == null;
  490. }
  491. if (a instanceof Date && b instanceof Date) {
  492. return a.getTime() == b.getTime();
  493. }
  494. if (S.isString(a) && S.isString(b)) {
  495. return (a == b);
  496. }
  497. if (S.isNumber(a) && S.isNumber(b)) {
  498. return (a == b);
  499. }
  500. if (typeof a === "object" && typeof b === "object") {
  501. return compareObjects(a, b, mismatchKeys, mismatchValues);
  502. }
  503. // Straight check
  504. return (a === b);
  505. },
  506. /**
  507. * Creates a deep copy of a plain object or array. Others are returned untouched.
  508. * @param input
  509. * @param {Function} [filter] filter function
  510. * @returns the new cloned object
  511. * @see http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data
  512. */
  513. clone:function (input, filter) {
  514. // 稍微改改就和规范一样了 :)
  515. // Let memory be an association list of pairs of objects,
  516. // initially empty. This is used to handle duplicate references.
  517. // In each pair of objects, one is called the source object
  518. // and the other the destination object.
  519. var memory = {},
  520. ret = cloneInternal(input, filter, memory);
  521. S.each(memory, function (v) {
  522. // 清理在源对象上做的标记
  523. v = v.input;
  524. if (v[CLONE_MARKER]) {
  525. try {
  526. delete v[CLONE_MARKER];
  527. } catch (e) {
  528. S.log("delete CLONE_MARKER error : ");
  529. v[CLONE_MARKER] = undefined;
  530. }
  531. }
  532. });
  533. memory = null;
  534. return ret;
  535. },
  536. /**
  537. * Removes the whitespace from the beginning and end of a string.
  538. * @function
  539. */
  540. trim:trim ?
  541. function (str) {
  542. return str == null ? EMPTY : trim.call(str);
  543. } :
  544. function (str) {
  545. return str == null ? EMPTY : str.toString().replace(RE_TRIM, EMPTY);
  546. },
  547. /**
  548. * Substitutes keywords in a string using an object/array.
  549. * Removes undefined keywords and ignores escaped keywords.
  550. * @param {String} str template string
  551. * @param {Object} o json data
  552. * @param {RegExp} regexp to match a piece of template string
  553. */
  554. substitute:function (str, o, regexp) {
  555. if (!S.isString(str)
  556. || !S.isPlainObject(o)) {
  557. return str;
  558. }
  559. return str.replace(regexp || /\\?\{([^{}]+)\}/g, function (match, name) {
  560. if (match.charAt(0) === '\\') {
  561. return match.slice(1);
  562. }
  563. return (o[name] === undefined) ? EMPTY : o[name];
  564. });
  565. },
  566. /**
  567. * Executes the supplied function on each item in the array.
  568. * @param object {Object} the object to iterate
  569. * @param fn {Function} the function to execute on each item. The function
  570. * receives three arguments: the value, the index, the full array.
  571. * @param {Object} [context]
  572. */
  573. each:function (object, fn, context) {
  574. if (object) {
  575. var key,
  576. val,
  577. i = 0,
  578. length = object && object.length,
  579. isObj = length === undefined || S.type(object) === 'function';
  580. context = context || host;
  581. if (isObj) {
  582. for (key in object) {
  583. // can not use hasOwnProperty
  584. if (fn.call(context, object[key], key, object) === FALSE) {
  585. break;
  586. }
  587. }
  588. } else {
  589. for (val = object[0];
  590. i < length && fn.call(context, val, i, object) !== FALSE; val = object[++i]) {
  591. }
  592. }
  593. }
  594. return object;
  595. },
  596. /**
  597. * Search for a specified value within an array.
  598. * @param item individual item to be searched
  599. * @function
  600. * @param {Array} arr the array of items where item will be search
  601. * @returns {number} item's index in array
  602. */
  603. indexOf:indexOf ?
  604. function (item, arr) {
  605. return indexOf.call(arr, item);
  606. } :
  607. function (item, arr) {
  608. for (var i = 0, len = arr.length; i < len; ++i) {
  609. if (arr[i] === item) {
  610. return i;
  611. }
  612. }
  613. return -1;
  614. },
  615. /**
  616. * Returns the index of the last item in the array
  617. * that contains the specified value, -1 if the
  618. * value isn't found.
  619. * @function
  620. * @param item individual item to be searched
  621. * @param {Array} arr the array of items where item will be search
  622. * @returns {number} item's last index in array
  623. */
  624. lastIndexOf:(lastIndexOf) ?
  625. function (item, arr) {
  626. return lastIndexOf.call(arr, item);
  627. } :
  628. function (item, arr) {
  629. for (var i = arr.length - 1; i >= 0; i--) {
  630. if (arr[i] === item) {
  631. break;
  632. }
  633. }
  634. return i;
  635. },
  636. /**
  637. * Returns a copy of the array with the duplicate entries removed
  638. * @param a {Array} the array to find the subset of unique for
  639. * @param [override] {Boolean}
  640. * if override is true, S.unique([a, b, a]) => [b, a]
  641. * if override is false, S.unique([a, b, a]) => [a, b]
  642. * @return {Array} a copy of the array with duplicate entries removed
  643. */
  644. unique:function (a, override) {
  645. var b = a.slice();
  646. if (override) {
  647. b.reverse();
  648. }
  649. var i = 0,
  650. n,
  651. item;
  652. while (i < b.length) {
  653. item = b[i];
  654. while ((n = S.lastIndexOf(item, b)) !== i) {
  655. b.splice(n, 1);
  656. }
  657. i += 1;
  658. }
  659. if (override) {
  660. b.reverse();
  661. }
  662. return b;
  663. },
  664. /**
  665. * Search for a specified value index within an array.
  666. * @param item individual item to be searched
  667. * @param {Array} arr the array of items where item will be search
  668. * @returns {boolean} the item exists in arr
  669. */
  670. inArray:function (item, arr) {
  671. return S.indexOf(item, arr) > -1;
  672. },
  673. /**
  674. * Executes the supplied function on each item in the array.
  675. * Returns a new array containing the items that the supplied
  676. * function returned true for.
  677. * @function
  678. * @param arr {Array} the array to iterate
  679. * @param fn {Function} the function to execute on each item
  680. * @param [context] {Object} optional context object
  681. * @return {Array} The items on which the supplied function
  682. * returned true. If no items matched an empty array is
  683. * returned.
  684. */
  685. filter:filter ?
  686. function (arr, fn, context) {
  687. return filter.call(arr, fn, context || this);
  688. } :
  689. function (arr, fn, context) {
  690. var ret = [];
  691. S.each(arr, function (item, i, arr) {
  692. if (fn.call(context || this, item, i, arr)) {
  693. ret.push(item);
  694. }
  695. });
  696. return ret;
  697. },
  698. /**
  699. * Executes the supplied function on each item in the array.
  700. * Returns a new array containing the items that the supplied
  701. * function returned for.
  702. * @function
  703. * @param arr {Array} the array to iterate
  704. * @param fn {Function} the function to execute on each item
  705. * @param [context] {Object} optional context object
  706. * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map
  707. * @return {Array} The items on which the supplied function
  708. * returned
  709. */
  710. map:map ?
  711. function (arr, fn, context) {
  712. return map.call(arr, fn, context || this);
  713. } :
  714. function (arr, fn, context) {
  715. var len = arr.length,
  716. res = new Array(len);
  717. for (var i = 0; i < len; i++) {
  718. var el = S.isString(arr) ? arr.charAt(i) : arr[i];
  719. if (el
  720. ||
  721. //ie<9 in invalid when typeof arr == string
  722. i in arr) {
  723. res[i] = fn.call(context || this, el, i, arr);
  724. }
  725. }
  726. return res;
  727. },
  728. /**
  729. * Executes the supplied function on each item in the array.
  730. * Returns a value which is accumulation of the value that the supplied
  731. * function returned.
  732. *
  733. * @param arr {Array} the array to iterate
  734. * @param callback {Function} the function to execute on each item
  735. * @param initialValue {number} optional context object
  736. * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/reduce
  737. * @return {Array} The items on which the supplied function returned
  738. */
  739. reduce:/*
  740. NaN ?
  741. reduce ? function(arr, callback, initialValue) {
  742. return arr.reduce(callback, initialValue);
  743. } : */function (arr, callback, initialValue) {
  744. var len = arr.length;
  745. if (typeof callback !== "function") {
  746. throw new TypeError("callback is not function!");
  747. }
  748. // no value to return if no initial value and an empty array
  749. if (len === 0 && arguments.length == 2) {
  750. throw new TypeError("arguments invalid");
  751. }
  752. var k = 0;
  753. var accumulator;
  754. if (arguments.length >= 3) {
  755. accumulator = arguments[2];
  756. }
  757. else {
  758. do {
  759. if (k in arr) {
  760. accumulator = arr[k++];
  761. break;
  762. }
  763. // if array contains no values, no initial value to return
  764. k += 1;
  765. if (k >= len) {
  766. throw new TypeError();
  767. }
  768. }
  769. while (TRUE);
  770. }
  771. while (k < len) {
  772. if (k in arr) {
  773. accumulator = callback.call(undefined, accumulator, arr[k], k, arr);
  774. }
  775. k++;
  776. }
  777. return accumulator;
  778. },
  779. /**
  780. * Tests whether all elements in the array pass the test implemented by the provided function.
  781. * @function
  782. * @param arr {Array} the array to iterate
  783. * @param callback {Function} the function to execute on each item
  784. * @param [context] {Object} optional context object
  785. * @returns {boolean} whether all elements in the array pass the test implemented by the provided function.
  786. */
  787. every:every ?
  788. function (arr, fn, context) {
  789. return every.call(arr, fn, context || this);
  790. } :
  791. function (arr, fn, context) {
  792. var len = arr && arr.length || 0;
  793. for (var i = 0; i < len; i++) {
  794. if (i in arr && !fn.call(context, arr[i], i, arr)) {
  795. return FALSE;
  796. }
  797. }
  798. return TRUE;
  799. },
  800. /**
  801. * Tests whether some element in the array passes the test implemented by the provided function.
  802. * @function
  803. * @param arr {Array} the array to iterate
  804. * @param callback {Function} the function to execute on each item
  805. * @param [context] {Object} optional context object
  806. * @returns {boolean} whether some element in the array passes the test implemented by the provided function.
  807. */
  808. some:some ?
  809. function (arr, fn, context) {
  810. return some.call(arr, fn, context || this);
  811. } :
  812. function (arr, fn, context) {
  813. var len = arr && arr.length || 0;
  814. for (var i = 0; i < len; i++) {
  815. if (i in arr && fn.call(context, arr[i], i, arr)) {
  816. return TRUE;
  817. }
  818. }
  819. return FALSE;
  820. },
  821. /**
  822. * Creates a new function that, when called, itself calls this function in the context of the provided this value,
  823. * with a given sequence of arguments preceding any provided when the new function was called.
  824. * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
  825. * @param {Function} fn internal called function
  826. * @param {Object} obj context in which fn runs
  827. * @param {...} arg1 extra arguments
  828. * @returns {Function} new function with context and arguments
  829. */
  830. bind:function (fn, obj, arg1) {
  831. var slice = [].slice,
  832. args = slice.call(arguments, 2),
  833. fNOP = function () {
  834. },
  835. bound = function () {
  836. return fn.apply(this instanceof fNOP ? this : obj,
  837. args.concat(slice.call(arguments)));
  838. };
  839. fNOP.prototype = fn.prototype;
  840. bound.prototype = new fNOP();
  841. return bound;
  842. },
  843. /**
  844. * Gets current date in milliseconds.
  845. * @function
  846. * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/now
  847. * http://j-query.blogspot.com/2011/02/timing-ecmascript-5-datenow-function.html
  848. * http://kangax.github.com/es5-compat-table/
  849. */
  850. now:Date.now || function () {
  851. return +new Date();
  852. },
  853. /**
  854. * frequently used in taobao cookie about nick
  855. */
  856. fromUnicode:function (str) {
  857. return str.replace(/\\u([a-f\d]{4})/ig, function (m, u) {
  858. return String.fromCharCode(parseInt(u, HEX_BASE));
  859. });
  860. },
  861. /**
  862. * get escaped string from html
  863. * @see http://yiminghe.javaeye.com/blog/788929
  864. * http://wonko.com/post/html-escaping
  865. * @param str {string} text2html show
  866. */
  867. escapeHTML:function (str) {
  868. return str.replace(getEscapeReg(), function (m) {
  869. return reverseEntities[m];
  870. });
  871. },
  872. /**
  873. * get escaped regexp string for construct regexp
  874. * @param str
  875. */
  876. escapeRegExp:function (str) {
  877. return str.replace(escapeRegExp, '\\$&');
  878. },
  879. /**
  880. * un-escape html to string
  881. * @param str {string} html2text
  882. */
  883. unEscapeHTML:function (str) {
  884. return str.replace(getUnEscapeReg(), function (m, n) {
  885. return htmlEntities[m] || String.fromCharCode(+n);
  886. });
  887. },
  888. /**
  889. * Converts object to a true array.
  890. * @param o {object|Array} array like object or array
  891. * @return {Array} native Array
  892. */
  893. makeArray:function (o) {
  894. if (o == null) {
  895. return [];
  896. }
  897. if (S.isArray(o)) {
  898. return o;
  899. }
  900. // The strings and functions also have 'length'
  901. if (typeof o.length !== 'number' || S.isString(o) || S.isFunction(o)) {
  902. return [o];
  903. }
  904. var ret = [];
  905. for (var i = 0, l = o.length; i < l; i++) {
  906. ret[i] = o[i];
  907. }
  908. return ret;
  909. },
  910. /**
  911. * Creates a serialized string of an array or object.
  912. * @example
  913. * <code>
  914. * {foo: 1, bar: 2} // -> 'foo=1&bar=2'
  915. * {foo: 1, bar: [2, 3]} // -> 'foo=1&bar=2&bar=3'
  916. * {foo: '', bar: 2} // -> 'foo=&bar=2'
  917. * {foo: undefined, bar: 2} // -> 'foo=undefined&bar=2'
  918. * {foo: true, bar: 2} // -> 'foo=true&bar=2'
  919. * </code>
  920. * @param {Object} o json data
  921. * @param {String} [sep='&'] separator between each pair of data
  922. * @param {String} [eq='='] separator between key and value of data
  923. * @param {boolean} [arr=true] whether add '[]' to array key of data
  924. * @return {String}
  925. */
  926. param:function (o, sep, eq, arr) {
  927. if (!S.isPlainObject(o)) {
  928. return EMPTY;
  929. }
  930. sep = sep || SEP;
  931. eq = eq || EQ;
  932. if (S.isUndefined(arr)) {
  933. arr = TRUE;
  934. }
  935. var buf = [], key, val;
  936. for (key in o) {
  937. if (o.hasOwnProperty(key)) {
  938. val = o[key];
  939. key = encode(key);
  940. // val is valid non-array value
  941. if (isValidParamValue(val)) {
  942. buf.push(key, eq, encode(val + EMPTY), sep);
  943. }
  944. // val is not empty array
  945. else if (S.isArray(val) && val.length) {
  946. for (var i = 0, len = val.length; i < len; ++i) {
  947. if (isValidParamValue(val[i])) {
  948. buf.push(key,
  949. (arr ? encode("[]") : EMPTY),
  950. eq, encode(val[i] + EMPTY), sep);
  951. }
  952. }
  953. }
  954. // ignore other cases, including empty array, Function, RegExp, Date etc.
  955. }
  956. }
  957. buf.pop();
  958. return buf.join(EMPTY);
  959. },
  960. /**
  961. * Parses a URI-like query string and returns an object composed of parameter/value pairs.
  962. * @example
  963. * <code>
  964. * 'section=blog&id=45' // -> {section: 'blog', id: '45'}
  965. * 'section=blog&tag=js&tag=doc' // -> {section: 'blog', tag: ['js', 'doc']}
  966. * 'tag=ruby%20on%20rails' // -> {tag: 'ruby on rails'}
  967. * 'id=45&raw' // -> {id: '45', raw: ''}
  968. * </code>
  969. * @param {String} str param string
  970. * @param {String} [sep='&'] separator between each pair of data
  971. * @param {String} [eq='='] separator between key and value of data
  972. * @returns {Object} json data
  973. */
  974. unparam:function (str, sep, eq) {
  975. if (!S.isString(str) || !(str = S.trim(str))) {
  976. return {};
  977. }
  978. sep = sep || SEP;
  979. eq = eq || EQ;
  980. var ret = {},
  981. pairs = str.split(sep),
  982. pair, key, val,
  983. i = 0, len = pairs.length;
  984. for (; i < len; ++i) {
  985. pair = pairs[i].split(eq);
  986. key = decode(pair[0]);
  987. try {
  988. val = decode(pair[1] || EMPTY);
  989. } catch (e) {
  990. S.log(e + "decodeURIComponent error : " + pair[1], "error");
  991. val = pair[1] || EMPTY;
  992. }
  993. if (S.endsWith(key, "[]")) {
  994. key = key.substring(0, key.length - 2);
  995. }
  996. if (hasOwnProperty.call(ret, key)) {
  997. if (S.isArray(ret[key])) {
  998. ret[key].push(val);
  999. } else {
  1000. ret[key] = [ret[key], val];
  1001. }
  1002. } else {
  1003. ret[key] = val;
  1004. }
  1005. }
  1006. return ret;
  1007. },
  1008. /**
  1009. * Executes the supplied function in the context of the supplied
  1010. * object 'when' milliseconds later. Executes the function a
  1011. * single time unless periodic is set to true.
  1012. * @param fn {Function|String} the function to execute or the name of the method in
  1013. * the 'o' object to execute.
  1014. * @param when {Number} the number of milliseconds to wait until the fn is executed.
  1015. * @param {Boolean} [periodic] if true, executes continuously at supplied interval
  1016. * until canceled.
  1017. * @param {Object} [context] the context object.
  1018. * @param [data] that is provided to the function. This accepts either a single
  1019. * item or an array. If an array is provided, the function is executed with
  1020. * one parameter for each array item. If you need to pass a single array
  1021. * parameter, it needs to be wrapped in an array [myarray].
  1022. * @return {Object} a timer object. Call the cancel() method on this object to stop
  1023. * the timer.
  1024. */
  1025. later:function (fn, when, periodic, context, data) {
  1026. when = when || 0;
  1027. var m = fn,
  1028. d = S.makeArray(data),
  1029. f,
  1030. r;
  1031. if (S.isString(fn)) {
  1032. m = context[fn];
  1033. }
  1034. if (!m) {
  1035. S.error('method undefined');
  1036. }
  1037. f = function () {
  1038. m.apply(context, d);
  1039. };
  1040. r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
  1041. return {
  1042. id:r,
  1043. interval:periodic,
  1044. cancel:function () {
  1045. if (this.interval) {
  1046. clearInterval(r);
  1047. } else {
  1048. clearTimeout(r);
  1049. }
  1050. }
  1051. };
  1052. },
  1053. /**
  1054. * test whether a string start with a specified substring
  1055. * @param {String} str the whole string
  1056. * @param {String} prefix a specified substring
  1057. * @returns {boolean} whether str start with prefix
  1058. */
  1059. startsWith:function (str, prefix) {
  1060. return str.lastIndexOf(prefix, 0) === 0;
  1061. },
  1062. /**
  1063. * test whether a string end with a specified substring
  1064. * @param {String} str the whole string
  1065. * @param {String} suffix a specified substring
  1066. * @returns {boolean} whether str end with suffix
  1067. */
  1068. endsWith:function (str, suffix) {
  1069. var ind = str.length - suffix.length;
  1070. return ind >= 0 && str.indexOf(suffix, ind) == ind;
  1071. },
  1072. /**
  1073. * Throttles a call to a method based on the time between calls.
  1074. * @param {function} fn The function call to throttle.
  1075. * @param {object} [context] context fn to run
  1076. * @param {Number} [ms] The number of milliseconds to throttle the method call.
  1077. * Passing a -1 will disable the throttle. Defaults to 150.
  1078. * @return {function} Returns a wrapped function that calls fn throttled.
  1079. */
  1080. throttle:function (fn, ms, context) {
  1081. ms = ms || 150;
  1082. if (ms === -1) {
  1083. return (function () {
  1084. fn.apply(context || this, arguments);
  1085. });
  1086. }
  1087. var last = S.now();
  1088. return (function () {
  1089. var now = S.now();
  1090. if (now - last > ms) {
  1091. last = now;
  1092. fn.apply(context || this, arguments);
  1093. }
  1094. });
  1095. },
  1096. /**
  1097. * buffers a call between a fixed time
  1098. * @param {function} fn
  1099. * @param {object} [context]
  1100. * @param {Number} ms
  1101. * @return {function} Returns a wrapped function that calls fn buffered.
  1102. */
  1103. buffer:function (fn, ms, context) {
  1104. ms = ms || 150;
  1105. if (ms === -1) {
  1106. return (function () {
  1107. fn.apply(context || this, arguments);
  1108. });
  1109. }
  1110. var bufferTimer = null;
  1111. function f() {
  1112. f.stop();
  1113. bufferTimer = S.later(fn, ms, FALSE, context || this, arguments);
  1114. }
  1115. f.stop = function () {
  1116. if (bufferTimer) {
  1117. bufferTimer.cancel();
  1118. bufferTimer = 0;
  1119. }
  1120. };
  1121. return f;
  1122. }
  1123. });
  1124. // for idea ..... auto-hint
  1125. S.mix(S,
  1126. /**
  1127. * @lends KISSY
  1128. */
  1129. {
  1130. /**
  1131. * test whether o is boolean
  1132. * @function
  1133. * @param o
  1134. * @returns {boolean}
  1135. */
  1136. isBoolean:isValidParamValue,
  1137. /**
  1138. * test whether o is number
  1139. * @function
  1140. * @param o
  1141. * @returns {boolean}
  1142. */
  1143. isNumber:isValidParamValue,
  1144. /**
  1145. * test whether o is String
  1146. * @function
  1147. * @param o
  1148. * @returns {boolean}
  1149. */
  1150. isString:isValidParamValue,
  1151. /**
  1152. * test whether o is function
  1153. * @function
  1154. * @param o
  1155. * @returns {boolean}
  1156. */
  1157. isFunction:isValidParamValue,
  1158. /**
  1159. * test whether o is Array
  1160. * @function
  1161. * @param o
  1162. * @returns {boolean}
  1163. */
  1164. isArray:isValidParamValue,
  1165. /**
  1166. * test whether o is Date
  1167. * @function
  1168. * @param o
  1169. * @returns {boolean}
  1170. */
  1171. isDate:isValidParamValue,
  1172. /**
  1173. * test whether o is RegExp
  1174. * @function
  1175. * @param o
  1176. * @returns {boolean}
  1177. */
  1178. isRegExp:isValidParamValue,
  1179. /**
  1180. * test whether o is Object
  1181. * @function
  1182. * @param o
  1183. * @returns {boolean}
  1184. */
  1185. isObject:isValidParamValue
  1186. });
  1187. S.each('Boolean Number String Function Array Date RegExp Object'.split(' '),
  1188. function (name, lc) {
  1189. // populate the class2type map
  1190. class2type['[object ' + name + ']'] = (lc = name.toLowerCase());
  1191. // add isBoolean/isNumber/...
  1192. S['is' + name] = function (o) {
  1193. return S.type(o) == lc;
  1194. }
  1195. });
  1196. function cloneInternal(input, f, memory) {
  1197. var destination = input,
  1198. isArray,
  1199. isPlainObject,
  1200. k,
  1201. stamp;
  1202. if (!input) {
  1203. return destination;
  1204. }
  1205. // If input is the source object of a pair of objects in memory,
  1206. // then return the destination object in that pair of objects .
  1207. // and abort these steps.
  1208. if (input[CLONE_MARKER]) {
  1209. // 对应的克隆后对象
  1210. return memory[input[CLONE_MARKER]].destination;
  1211. } else if (typeof input === "object") {
  1212. // 引用类型要先记录
  1213. var constructor = input.constructor;
  1214. if (S.inArray(constructor, [Boolean, String, Number, Date, RegExp])) {
  1215. destination = new constructor(input.valueOf());
  1216. }
  1217. // ImageData , File, Blob , FileList .. etc
  1218. else if (isArray = S.isArray(input)) {
  1219. destination = f ? S.filter(input, f) : input.concat();
  1220. } else if (isPlainObject = S.isPlainObject(input)) {
  1221. destination = {};
  1222. }
  1223. // Add a mapping from input (the source object)
  1224. // to output (the destination object) to memory.
  1225. // 做标记
  1226. input[CLONE_MARKER] = (stamp = S.guid());
  1227. // 存储源对象以及克隆后的对象
  1228. memory[stamp] = {destination:destination, input:input};
  1229. }
  1230. // If input is an Array object or an Object object,
  1231. // then, for each enumerable property in input,
  1232. // add a new property to output having the same name,
  1233. // and having a value created from invoking the internal structured cloning algorithm recursively
  1234. // with the value of the property as the "input" argument and memory as the "memory" argument.
  1235. // The order of the properties in the input and output objects must be the same.
  1236. // clone it
  1237. if (isArray) {
  1238. for (var i = 0; i < destination.length; i++) {
  1239. destination[i] = cloneInternal(destination[i], f, memory);
  1240. }
  1241. } else if (isPlainObject) {
  1242. for (k in input) {
  1243. if (input.hasOwnProperty(k)) {
  1244. if (k !== CLONE_MARKER &&
  1245. (!f || (f.call(input, input[k], k, input) !== FALSE))) {
  1246. destination[k] = cloneInternal(input[k], f, memory);
  1247. }
  1248. }
  1249. }
  1250. }
  1251. return destination;
  1252. }
  1253. function compareObjects(a, b, mismatchKeys, mismatchValues) {
  1254. // 两个比较过了,无需再比较,防止循环比较
  1255. if (a[COMPARE_MARKER] === b && b[COMPARE_MARKER] === a) {
  1256. return TRUE;
  1257. }
  1258. a[COMPARE_MARKER] = b;
  1259. b[COMPARE_MARKER] = a;
  1260. var hasKey = function (obj, keyName) {
  1261. return (obj !== null && obj !== undefined) && obj[keyName] !== undefined;
  1262. };
  1263. for (var property in b) {
  1264. if (b.hasOwnProperty(property)) {
  1265. if (!hasKey(a, property) && hasKey(b, property)) {
  1266. mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
  1267. }
  1268. }
  1269. }
  1270. for (property in a) {
  1271. if (a.hasOwnProperty(property)) {
  1272. if (!hasKey(b, property) && hasKey(a, property)) {
  1273. mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
  1274. }
  1275. }
  1276. }
  1277. for (property in b) {
  1278. if (b.hasOwnProperty(property)) {
  1279. if (property == COMPARE_MARKER) {
  1280. continue;
  1281. }
  1282. if (!S.equals(a[property], b[property], mismatchKeys, mismatchValues)) {
  1283. mismatchValues.push("'" + property + "' was '" + (b[property] ? (b[property].toString()) : b[property])
  1284. + "' in expected, but was '" +
  1285. (a[property] ? (a[property].toString()) : a[property]) + "' in actual.");
  1286. }
  1287. }
  1288. }
  1289. if (S.isArray(a) && S.isArray(b) && a.length != b.length) {
  1290. mismatchValues.push("arrays were not the same length");
  1291. }
  1292. delete a[COMPARE_MARKER];
  1293. delete b[COMPARE_MARKER];
  1294. return (mismatchKeys.length === 0 && mismatchValues.length === 0);
  1295. }
  1296. })(KISSY, undefined);
  1297. /**
  1298. * implement Promise specification by KISSY
  1299. * @author yiminghe@gmail.com
  1300. */
  1301. (function (S) {
  1302. })(KISSY);
  1303. /**
  1304. * refer
  1305. * - http://wiki.commonjs.org/wiki/Promises
  1306. * - https://github.com/kriskowal/q
  1307. **//**
  1308. * @fileOverview setup data structure for kissy loader
  1309. * @author yiminghe@gmail.com
  1310. */
  1311. (function(S){
  1312. if("require" in this) {
  1313. return;
  1314. }
  1315. S.__loader={};
  1316. S.__loaderUtils={};
  1317. S.__loaderData={};
  1318. })(KISSY);/**
  1319. * @fileOverview status constants
  1320. * @author yiminghe@gmail.com
  1321. */
  1322. (function(S, data) {
  1323. if ("require" in this) {
  1324. return;
  1325. }
  1326. // 脚本(loadQueue)/模块(mod) 公用状态
  1327. S.mix(data, {
  1328. "INIT":0,
  1329. "LOADING" : 1,
  1330. "LOADED" : 2,
  1331. "ERROR" : 3,
  1332. // 模块特有
  1333. "ATTACHED" : 4
  1334. });
  1335. })(KISSY, KISSY.__loaderData);/**
  1336. * @fileOverview utils for kissy loader
  1337. * @author yiminghe@gmail.com
  1338. */
  1339. (function(S, loader, utils) {
  1340. if ("require" in this) {
  1341. return;
  1342. }
  1343. var ua = navigator.userAgent,doc = document;
  1344. S.mix(utils, {
  1345. docHead:function() {
  1346. return doc.getElementsByTagName('head')[0] || doc.documentElement;
  1347. },
  1348. isWebKit:!!ua.match(/AppleWebKit/),
  1349. IE : !!ua.match(/MSIE/),
  1350. isCss:function(url) {
  1351. return /\.css(?:\?|$)/i.test(url);
  1352. },
  1353. isLinkNode:function(n) {
  1354. return n.nodeName.toLowerCase() == 'link';
  1355. },
  1356. /**
  1357. * resolve relative part of path
  1358. * x/../y/z -> y/z
  1359. * x/./y/z -> x/y/z
  1360. * @param path uri path
  1361. * @return {string} resolved path
  1362. * @description similar to path.normalize in nodejs
  1363. */
  1364. normalizePath:function(path) {
  1365. var paths = path.split("/"),
  1366. re = [],
  1367. p;
  1368. for (var i = 0; i < paths.length; i++) {
  1369. p = paths[i];
  1370. if (p == ".") {
  1371. } else if (p == "..") {
  1372. re.pop();
  1373. } else {
  1374. re.push(p);
  1375. }
  1376. }
  1377. return re.join("/");
  1378. },
  1379. /**
  1380. * 根据当前模块以及依赖模块的相对路径,得到依赖模块的绝对路径
  1381. * @param moduleName 当前模块
  1382. * @param depName 依赖模块
  1383. * @return {string|Array} 依赖模块的绝对路径
  1384. * @description similar to path.resolve in nodejs
  1385. */
  1386. normalDepModuleName:function normalDepModuleName(moduleName, depName) {
  1387. if (!depName) {
  1388. return depName;
  1389. }
  1390. if (S.isArray(depName)) {
  1391. for (var i = 0; i < depName.length; i++) {
  1392. depName[i] = normalDepModuleName(moduleName, depName[i]);
  1393. }
  1394. return depName;
  1395. }
  1396. if (startsWith(depName, "../") || startsWith(depName, "./")) {
  1397. var anchor = "",index;
  1398. // x/y/z -> x/y/
  1399. if ((index = moduleName.lastIndexOf("/")) != -1) {
  1400. anchor = moduleName.substring(0, index + 1);
  1401. }
  1402. return normalizePath(anchor + depName);
  1403. } else if (depName.indexOf("./") != -1
  1404. || depName.indexOf("../") != -1) {
  1405. return normalizePath(depName);
  1406. } else {
  1407. return depName;
  1408. }
  1409. },
  1410. //去除后缀名,要考虑时间戳?
  1411. removePostfix:function (path) {
  1412. return path.replace(/(-min)?\.js[^/]*$/i, "");
  1413. },
  1414. /**
  1415. * 路径正则化,不能是相对地址
  1416. * 相对地址则转换成相对页面的绝对地址
  1417. * 用途:
  1418. * package path 相对地址则相对于当前页面获取绝对地址
  1419. */
  1420. normalBasePath:function (path) {
  1421. path = S.trim(path);
  1422. // path 为空时,不能变成 "/"
  1423. if (path && path.charAt(path.length - 1) != '/') {
  1424. path += "/";
  1425. }
  1426. /**
  1427. * 一定要正则化,防止出现 ../ 等相对路径
  1428. * 考虑本地路径
  1429. */
  1430. if (!path.match(/^(http(s)?)|(file):/i)
  1431. && !startsWith(path, "/")) {
  1432. path = loader.__pagePath + path;
  1433. }
  1434. return normalizePath(path);
  1435. },
  1436. /**
  1437. * 相对路径文件名转换为绝对路径
  1438. * @param path
  1439. */
  1440. absoluteFilePath:function(path) {
  1441. path = utils.normalBasePath(path);
  1442. return path.substring(0, path.length - 1);
  1443. },
  1444. //http://wiki.commonjs.org/wiki/Packages/Mappings/A
  1445. //如果模块名以 / 结尾,自动加 index
  1446. indexMapping:function (names) {
  1447. for (var i = 0; i < names.length; i++) {
  1448. if (names[i].match(/\/$/)) {
  1449. names[i] += "index";
  1450. }
  1451. }
  1452. return names;
  1453. }
  1454. });
  1455. var startsWith = S.startsWith,normalizePath = utils.normalizePath;
  1456. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  1457. * @fileOverview script/css load across browser
  1458. * @author yiminghe@gmail.com
  1459. */
  1460. (function(S, utils) {
  1461. if ("require" in this) {
  1462. return;
  1463. }
  1464. var CSS_POLL_INTERVAL = 30,
  1465. /**
  1466. * central poll for link node
  1467. */
  1468. timer = 0,
  1469. monitors = {
  1470. /**
  1471. * node.id:[callback]
  1472. */
  1473. };
  1474. function startCssTimer() {
  1475. if (!timer) {
  1476. S.log("start css polling");
  1477. cssPoll();
  1478. }
  1479. }
  1480. // single thread is ok
  1481. function cssPoll() {
  1482. for (var url in monitors) {
  1483. var callbacks = monitors[url],
  1484. node = callbacks.node,
  1485. loaded = 0;
  1486. if (utils.isWebKit) {
  1487. if (node['sheet']) {
  1488. S.log("webkit loaded : " + url);
  1489. loaded = 1;
  1490. }
  1491. } else if (node['sheet']) {
  1492. try {
  1493. var cssRules;
  1494. if (cssRules = node['sheet'].cssRules) {
  1495. S.log('firefox ' + cssRules + ' loaded : ' + url);
  1496. loaded = 1;
  1497. }
  1498. } catch(ex) {
  1499. // S.log('firefox ' + ex.name + ' ' + ex.code + ' ' + url);
  1500. // if (ex.name === 'NS_ERROR_DOM_SECURITY_ERR') {
  1501. if (ex.code === 1000) {
  1502. S.log('firefox ' + ex.name + ' loaded : ' + url);
  1503. loaded = 1;
  1504. }
  1505. }
  1506. }
  1507. if (loaded) {
  1508. for (var i = 0; i < callbacks.length; i++) {
  1509. callbacks[i].call(node);
  1510. }
  1511. delete monitors[url];
  1512. }
  1513. }
  1514. if (S.isEmptyObject(monitors)) {
  1515. timer = 0;
  1516. S.log("end css polling");
  1517. } else {
  1518. timer = setTimeout(cssPoll, CSS_POLL_INTERVAL);
  1519. }
  1520. }
  1521. S.mix(utils, {
  1522. scriptOnload:document.addEventListener ?
  1523. function(node, callback) {
  1524. if (utils.isLinkNode(node)) {
  1525. return utils.styleOnload(node, callback);
  1526. }
  1527. node.addEventListener('load', callback, false);
  1528. } :
  1529. function(node, callback) {
  1530. if (utils.isLinkNode(node)) {
  1531. return utils.styleOnload(node, callback);
  1532. }
  1533. var oldCallback = node.onreadystatechange;
  1534. node.onreadystatechange = function() {
  1535. var rs = node.readyState;
  1536. if (/loaded|complete/i.test(rs)) {
  1537. node.onreadystatechange = null;
  1538. oldCallback && oldCallback();
  1539. callback.call(this);
  1540. }
  1541. };
  1542. },
  1543. /**
  1544. * monitor css onload across browsers
  1545. * 暂时不考虑如何判断失败,如 404 等
  1546. * @see
  1547. * - firefox 不可行(结论4错误):
  1548. * - http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/
  1549. * - 全浏览器兼容
  1550. * - http://lifesinger.org/lab/2011/load-js-css/css-preload.html
  1551. * - 其他
  1552. * - http://www.zachleat.com/web/load-css-dynamically/
  1553. */
  1554. styleOnload:window.attachEvent ?
  1555. // ie/opera
  1556. function(node, callback) {
  1557. // whether to detach using function wrapper?
  1558. function t() {
  1559. node.detachEvent('onload', t);
  1560. S.log('ie/opera loaded : ' + node.href);
  1561. callback.call(node);
  1562. }
  1563. node.attachEvent('onload', t);
  1564. } :
  1565. // refer : http://lifesinger.org/lab/2011/load-js-css/css-preload.html
  1566. // 暂时不考虑如何判断失败,如 404 等
  1567. function(node, callback) {
  1568. var href = node.href,arr;
  1569. arr = monitors[href] = monitors[href] || [];
  1570. arr.node = node;
  1571. arr.push(callback);
  1572. startCssTimer();
  1573. }
  1574. });
  1575. })(KISSY, KISSY.__loaderUtils);/**
  1576. * @fileOverview getScript support for css and js callback after load
  1577. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1578. */
  1579. (function (S, utils) {
  1580. if ("require" in this) {
  1581. return;
  1582. }
  1583. var MILLISECONDS_OF_SECOND = 1000,
  1584. scriptOnload = utils.scriptOnload;
  1585. S.mix(S, {
  1586. /**
  1587. * load a css file from server using http get ,after css file load ,execute success callback
  1588. * @param url css file url
  1589. * @param success callback
  1590. * @param charset
  1591. * @private
  1592. */
  1593. getStyle:function (url, success, charset) {
  1594. var doc = document,
  1595. head = utils.docHead(),
  1596. node = doc.createElement('link'),
  1597. config = success;
  1598. if (S.isPlainObject(config)) {
  1599. success = config.success;
  1600. charset = config.charset;
  1601. }
  1602. node.href = url;
  1603. node.rel = 'stylesheet';
  1604. if (charset) {
  1605. node.charset = charset;
  1606. }
  1607. if (success) {
  1608. utils.scriptOnload(node, success);
  1609. }
  1610. head.appendChild(node);
  1611. return node;
  1612. },
  1613. /**
  1614. * Load a JavaScript/Css file from the server using a GET HTTP request, then execute it.
  1615. * @example
  1616. * <code>
  1617. * getScript(url, success, charset);
  1618. * or
  1619. * getScript(url, {
  1620. * charset: string
  1621. * success: fn,
  1622. * error: fn,
  1623. * timeout: number
  1624. * });
  1625. * </code>
  1626. * @param {String} url resource's url
  1627. * @param {Function|Object} [success] success callback or config
  1628. * @param {Function} [success.success] success callback
  1629. * @param {Function} [success.error] error callback
  1630. * @param {Number} [success.timeout] timeout (s)
  1631. * @param {String} [success.charset] charset of current resource
  1632. * @param {String} [charset] charset of current resource
  1633. * @returns {HTMLElement} script/style node
  1634. * @memberOf KISSY
  1635. */
  1636. getScript:function (url, success, charset) {
  1637. if (utils.isCss(url)) {
  1638. return S.getStyle(url, success, charset);
  1639. }
  1640. var doc = document,
  1641. head = doc.head || doc.getElementsByTagName("head")[0],
  1642. node = doc.createElement('script'),
  1643. config = success,
  1644. error,
  1645. timeout,
  1646. timer;
  1647. if (S.isPlainObject(config)) {
  1648. success = config.success;
  1649. error = config.error;
  1650. timeout = config.timeout;
  1651. charset = config.charset;
  1652. }
  1653. function clearTimer() {
  1654. if (timer) {
  1655. timer.cancel();
  1656. timer = undefined;
  1657. }
  1658. }
  1659. node.src = url;
  1660. node.async = true;
  1661. if (charset) {
  1662. node.charset = charset;
  1663. }
  1664. if (success || error) {
  1665. scriptOnload(node, function () {
  1666. clearTimer();
  1667. S.isFunction(success) && success.call(node);
  1668. });
  1669. if (S.isFunction(error)) {
  1670. //标准浏览器
  1671. if (doc.addEventListener) {
  1672. node.addEventListener("error", function () {
  1673. clearTimer();
  1674. error.call(node);
  1675. }, false);
  1676. }
  1677. timer = S.later(function () {
  1678. timer = undefined;
  1679. error();
  1680. }, (timeout || this.Config.timeout) * MILLISECONDS_OF_SECOND);
  1681. }
  1682. }
  1683. head.insertBefore(node, head.firstChild);
  1684. return node;
  1685. }
  1686. });
  1687. })(KISSY, KISSY.__loaderUtils);/**
  1688. * @fileOverview add module definition
  1689. * @author yiminghe@gmail.com,lifesinger@gmail.com
  1690. */
  1691. (function (S, loader, utils, data) {
  1692. if ("require" in this) {
  1693. return;
  1694. }
  1695. var IE = utils.IE,
  1696. ATTACHED = data.ATTACHED,
  1697. mix = S.mix;
  1698. mix(loader,
  1699. /**
  1700. * @lends KISSY
  1701. */
  1702. {
  1703. /**
  1704. * Registers a module.
  1705. * @param {String} [name] module name
  1706. * @param {Function|Object} [def] entry point into the module that is used to bind module to KISSY
  1707. * @param {Object} [config] special config for this add
  1708. * @param {String[]} [config.requires] array of mod's name that current module requires
  1709. * @example
  1710. * <code>
  1711. * KISSY.add('module-name', function(S){ }, {requires: ['mod1']});
  1712. * KISSY.add({
  1713. * 'mod-name': {
  1714. * fullpath: 'url',
  1715. * requires: ['mod1','mod2']
  1716. * }
  1717. * });
  1718. * </code>
  1719. * @return {KISSY}
  1720. */
  1721. add:function (name, def, config) {
  1722. var self = this,
  1723. mods = self.Env.mods,
  1724. o;
  1725. // S.add(name, config) => S.add( { name: config } )
  1726. if (S.isString(name)
  1727. && !config
  1728. && S.isPlainObject(def)) {
  1729. o = {};
  1730. o[name] = def;
  1731. name = o;
  1732. }
  1733. // S.add( { name: config } )
  1734. if (S.isPlainObject(name)) {
  1735. S.each(name, function (v, k) {
  1736. v.name = k;
  1737. if (mods[k]) {
  1738. // 保留之前添加的配置
  1739. mix(v, mods[k], false);
  1740. }
  1741. });
  1742. mix(mods, name);
  1743. return self;
  1744. }
  1745. // S.add(name[, fn[, config]])
  1746. if (S.isString(name)) {
  1747. var host;
  1748. if (config && ( host = config.host )) {
  1749. var hostMod = mods[host];
  1750. if (!hostMod) {
  1751. S.log("module " + host + " can not be found !", "error");
  1752. //S.error("module " + host + " can not be found !");
  1753. return self;
  1754. }
  1755. if (self.__isAttached(host)) {
  1756. def.call(self, self);
  1757. } else {
  1758. //该 host 模块纯虚!
  1759. hostMod.fns = hostMod.fns || [];
  1760. hostMod.fns.push(def);
  1761. }
  1762. return self;
  1763. }
  1764. self.__registerModule(name, def, config);
  1765. //显示指定 add 不 attach
  1766. if (config && config['attach'] === false) {
  1767. return self;
  1768. }
  1769. // 和 1.1.7 以前版本保持兼容,不得已而为之
  1770. var mod = mods[name];
  1771. var requires = utils.normalDepModuleName(name, mod.requires);
  1772. if (self.__isAttached(requires)) {
  1773. //S.log(mod.name + " is attached when add !");
  1774. self.__attachMod(mod);
  1775. }
  1776. //调试用,为什么不在 add 时 attach
  1777. else if (this.Config.debug && !mod) {
  1778. var i, modNames;
  1779. i = (modNames = S.makeArray(requires)).length - 1;
  1780. for (; i >= 0; i--) {
  1781. var requireName = modNames[i];
  1782. var requireMod = mods[requireName] || {};
  1783. if (requireMod.status !== ATTACHED) {
  1784. S.log(mod.name + " not attached when added : depends " + requireName);
  1785. }
  1786. }
  1787. }
  1788. return self;
  1789. }
  1790. // S.add(fn,config);
  1791. if (S.isFunction(name)) {
  1792. config = def;
  1793. def = name;
  1794. if (IE) {
  1795. /*
  1796. Kris Zyp
  1797. 2010年10月21日, 上午11时34分
  1798. We actually had some discussions off-list, as it turns out the required
  1799. technique is a little different than described in this thread. Briefly,
  1800. to identify anonymous modules from scripts:
  1801. * In non-IE browsers, the onload event is sufficient, it always fires
  1802. immediately after the script is executed.
  1803. * In IE, if the script is in the cache, it actually executes *during*
  1804. the DOM insertion of the script tag, so you can keep track of which
  1805. script is being requested in case define() is called during the DOM
  1806. insertion.
  1807. * In IE, if the script is not in the cache, when define() is called you
  1808. can iterate through the script tags and the currently executing one will
  1809. have a script.readyState == "interactive"
  1810. See RequireJS source code if you need more hints.
  1811. Anyway, the bottom line from a spec perspective is that it is
  1812. implemented, it works, and it is possible. Hope that helps.
  1813. Kris
  1814. */
  1815. // http://groups.google.com/group/commonjs/browse_thread/thread/5a3358ece35e688e/43145ceccfb1dc02#43145ceccfb1dc02
  1816. // use onload to get module name is not right in ie
  1817. name = self.__findModuleNameByInteractive();
  1818. S.log("old_ie get modname by interactive : " + name);
  1819. self.__registerModule(name, def, config);
  1820. self.__startLoadModuleName = null;
  1821. self.__startLoadTime = 0;
  1822. } else {
  1823. // 其他浏览器 onload 时,关联模块名与模块定义
  1824. self.__currentModule = {
  1825. def:def,
  1826. config:config
  1827. };
  1828. }
  1829. return self;
  1830. }
  1831. S.log("invalid format for KISSY.add !", "error");
  1832. return self;
  1833. }
  1834. });
  1835. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);
  1836. /**
  1837. * @see https://github.com/amdjs/amdjs-api/wiki/AMD
  1838. **//**
  1839. * @fileOverview build full path from relative path and base path
  1840. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1841. */
  1842. (function (S, loader, utils, data) {
  1843. if ("require" in this) {
  1844. return;
  1845. }
  1846. S.mix(loader, {
  1847. __buildPath:function (mod, base) {
  1848. var self = this,
  1849. Config = self.Config;
  1850. base = base || Config.base;
  1851. build("fullpath", "path");
  1852. if (mod["cssfullpath"] !== data.LOADED) {
  1853. build("cssfullpath", "csspath");
  1854. }
  1855. function build(fullpath, path) {
  1856. if (!mod[fullpath] && mod[path]) {
  1857. //如果是 ./ 或 ../ 则相对当前模块路径
  1858. mod[path] = utils.normalDepModuleName(mod.name, mod[path]);
  1859. mod[fullpath] = base + mod[path];
  1860. }
  1861. // debug 模式下,加载非 min 版
  1862. if (mod[fullpath] && Config.debug) {
  1863. mod[fullpath] = mod[fullpath].replace(/-min/ig, "");
  1864. }
  1865. //刷新客户端缓存,加时间戳 tag
  1866. if (mod[fullpath]
  1867. && !(mod[fullpath].match(/\?t=/))
  1868. && mod.tag) {
  1869. mod[fullpath] += "?t=" + mod.tag;
  1870. }
  1871. if (mod[fullpath]) {
  1872. mod[fullpath] = self.__getMappedPath(mod[fullpath]);
  1873. }
  1874. }
  1875. }
  1876. });
  1877. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  1878. * @fileOverview logic for config.global , mainly for kissy.editor
  1879. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1880. */
  1881. (function(S, loader) {
  1882. if ("require" in this) {
  1883. return;
  1884. }
  1885. S.mix(loader, {
  1886. // 按需从 global 迁移模块定义到当前 loader 实例,并根据 global 设置 fullpath
  1887. __mixMod: function(name, global) {
  1888. // 从 __mixMods 调用过来时,可能本实例没有该模块的数据结构
  1889. var self = this,
  1890. mods = self.Env.mods,
  1891. gMods = global.Env.mods,
  1892. mod = mods[name] || {},
  1893. status = mod.status;
  1894. if (gMods[name]) {
  1895. S.mix(mod, S.clone(gMods[name]));
  1896. // status 属于实例,当有值时,不能被覆盖。
  1897. // 1. 只有没有初始值时,才从 global 上继承
  1898. // 2. 初始值为 0 时,也从 global 上继承
  1899. // 其他都保存自己的状态
  1900. if (status) {
  1901. mod.status = status;
  1902. }
  1903. }
  1904. // 来自 global 的 mod, path 也应该基于 global
  1905. self.__buildPath(mod, global.Config.base);
  1906. mods[name] = mod;
  1907. }
  1908. });
  1909. })(KISSY, KISSY.__loader);/**
  1910. * @fileOverview for ie ,find current executive script ,then infer module name
  1911. * @author yiminghe@gmail.com
  1912. */
  1913. (function (S, loader, utils) {
  1914. if ("require" in this) {
  1915. return;
  1916. }
  1917. S.mix(loader, {
  1918. //ie 特有,找到当前正在交互的脚本,根据脚本名确定模块名
  1919. // 如果找不到,返回发送前那个脚本
  1920. __findModuleNameByInteractive:function () {
  1921. var self = this,
  1922. scripts = document.getElementsByTagName("script"),
  1923. re,
  1924. script;
  1925. for (var i = 0; i < scripts.length; i++) {
  1926. script = scripts[i];
  1927. if (script.readyState == "interactive") {
  1928. re = script;
  1929. break;
  1930. }
  1931. }
  1932. if (!re) {
  1933. // sometimes when read module file from cache , interactive status is not triggered
  1934. // module code is executed right after inserting into dom
  1935. // i has to preserve module name before insert module script into dom , then get it back here
  1936. S.log("can not find interactive script,time diff : " + (+new Date() - self.__startLoadTime), "error");
  1937. S.log("old_ie get modname from cache : " + self.__startLoadModuleName);
  1938. return self.__startLoadModuleName;
  1939. //S.error("找不到 interactive 状态的 script");
  1940. }
  1941. // src 必定是绝对路径
  1942. // or re.hasAttribute ? re.src : re.getAttribute('src', 4);
  1943. // http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
  1944. var src = utils.absoluteFilePath(re.src);
  1945. // S.log("interactive src :" + src);
  1946. // 注意:模块名不包含后缀名以及参数,所以去除
  1947. // 系统模块去除系统路径
  1948. // 需要 base norm , 防止 base 被指定为相对路径
  1949. self.Config.base = utils.normalBasePath(self.Config.base);
  1950. if (src.lastIndexOf(self.Config.base, 0)
  1951. === 0) {
  1952. return utils.removePostfix(src.substring(self.Config.base.length));
  1953. }
  1954. var packages = self.Config.packages;
  1955. //外部模块去除包路径,得到模块名
  1956. for (var p in packages) {
  1957. if (packages.hasOwnProperty(p)) {
  1958. var p_path = packages[p].path;
  1959. if (packages.hasOwnProperty(p) &&
  1960. src.lastIndexOf(p_path, 0) === 0) {
  1961. return utils.removePostfix(src.substring(p_path.length));
  1962. }
  1963. }
  1964. }
  1965. S.log("interactive script does not have package config :" + src, "error");
  1966. }
  1967. });
  1968. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  1969. * @fileOverview load a single mod (js or css)
  1970. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1971. */
  1972. (function(S, loader, utils, data) {
  1973. if ("require" in this) {
  1974. return;
  1975. }
  1976. var IE = utils.IE,
  1977. LOADING = data.LOADING,
  1978. LOADED = data.LOADED,
  1979. ERROR = data.ERROR,
  1980. ATTACHED = data.ATTACHED;
  1981. S.mix(loader, {
  1982. /**
  1983. * Load a single module.
  1984. */
  1985. __load: function(mod, callback, cfg) {
  1986. var self = this,
  1987. url = mod['fullpath'],
  1988. isCss = utils.isCss(url),
  1989. // 这个是全局的,防止多实例对同一模块的重复下载
  1990. loadQueque = S.Env._loadQueue,
  1991. status = loadQueque[url],
  1992. node = status;
  1993. mod.status = mod.status || 0;
  1994. // 可能已经由其它模块触发加载
  1995. if (mod.status < LOADING && status) {
  1996. // 该模块是否已经载入到 global ?
  1997. mod.status = status === LOADED ? LOADED : LOADING;
  1998. }
  1999. // 1.20 兼容 1.1x 处理:加载 cssfullpath 配置的 css 文件
  2000. // 仅发出请求,不做任何其它处理
  2001. if (S.isString(mod["cssfullpath"])) {
  2002. S.getScript(mod["cssfullpath"]);
  2003. mod["cssfullpath"] = mod.csspath = LOADED;
  2004. }
  2005. if (mod.status < LOADING && url) {
  2006. mod.status = LOADING;
  2007. if (IE && !isCss) {
  2008. self.__startLoadModuleName = mod.name;
  2009. self.__startLoadTime = Number(+new Date());
  2010. }
  2011. node = S.getScript(url, {
  2012. success: function() {
  2013. if (isCss) {
  2014. } else {
  2015. //载入 css 不需要这步了
  2016. //标准浏览器下:外部脚本执行后立即触发该脚本的 load 事件,ie9 还是不行
  2017. if (self.__currentModule) {
  2018. S.log("standard browser get modname after load : " + mod.name);
  2019. self.__registerModule(mod.name, self.__currentModule.def,
  2020. self.__currentModule.config);
  2021. self.__currentModule = null;
  2022. }
  2023. // 模块载入后,如果需要也要混入对应 global 上模块定义
  2024. mixGlobal();
  2025. if (mod.fns && mod.fns.length > 0) {
  2026. } else {
  2027. _modError();
  2028. }
  2029. }
  2030. if (mod.status != ERROR) {
  2031. S.log(mod.name + ' is loaded.', 'info');
  2032. }
  2033. _scriptOnComplete();
  2034. },
  2035. error: function() {
  2036. _modError();
  2037. _scriptOnComplete();
  2038. },
  2039. charset: mod.charset
  2040. });
  2041. loadQueque[url] = node;
  2042. }
  2043. // 已经在加载中,需要添加回调到 script onload 中
  2044. // 注意:没有考虑 error 情形
  2045. else if (mod.status === LOADING) {
  2046. utils.scriptOnload(node, function() {
  2047. // 模块载入后,如果需要也要混入对应 global 上模块定义
  2048. mixGlobal();
  2049. _scriptOnComplete();
  2050. });
  2051. }
  2052. // 是内嵌代码,或者已经 loaded
  2053. else {
  2054. // 也要混入对应 global 上模块定义
  2055. mixGlobal();
  2056. callback();
  2057. }
  2058. function _modError() {
  2059. S.log(mod.name + ' is not loaded! can not find module in path : ' + mod['fullpath'], 'error');
  2060. mod.status = ERROR;
  2061. }
  2062. function mixGlobal() {
  2063. // 对于动态下载下来的模块,loaded 后,global 上有可能更新 mods 信息
  2064. // 需要同步到 instance 上去
  2065. // 注意:要求 mod 对应的文件里,仅修改该 mod 信息
  2066. if (cfg.global) {
  2067. self.__mixMod(mod.name, cfg.global);
  2068. }
  2069. }
  2070. function _scriptOnComplete() {
  2071. loadQueque[url] = LOADED;
  2072. if (mod.status !== ERROR) {
  2073. // 注意:当多个模块依赖同一个下载中的模块A下,模块A仅需 attach 一次
  2074. // 因此要加上下面的 !== 判断,否则会出现重复 attach,
  2075. // 比如编辑器里动态加载时,被依赖的模块会重复
  2076. if (mod.status !== ATTACHED) {
  2077. mod.status = LOADED;
  2078. }
  2079. callback();
  2080. }
  2081. }
  2082. }
  2083. });
  2084. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  2085. * @fileOverview loader
  2086. * @author lifesinger@gmail.com,yiminghe@gmail.com,lijing00333@163.com
  2087. * @description constant member and common method holder
  2088. */
  2089. (function(S, loader, data) {
  2090. if ("require" in this) {
  2091. return;
  2092. }
  2093. var ATTACHED = data.ATTACHED,
  2094. mix = S.mix;
  2095. mix(loader, {
  2096. // 当前页面所在的目录
  2097. // http://xx.com/y/z.htm#!/f/g
  2098. // ->
  2099. // http://xx.com/y/
  2100. __pagePath:location.href.replace(location.hash, "").replace(/[^/]*$/i, ""),
  2101. //firefox,ie9,chrome 如果add没有模块名,模块定义先暂存这里
  2102. __currentModule:null,
  2103. //ie6,7,8开始载入脚本的时间
  2104. __startLoadTime:0,
  2105. //ie6,7,8开始载入脚本对应的模块名
  2106. __startLoadModuleName:null,
  2107. __isAttached: function(modNames) {
  2108. var mods = this.Env.mods,
  2109. ret = true;
  2110. S.each(modNames, function(name) {
  2111. var mod = mods[name];
  2112. if (!mod || mod.status !== ATTACHED) {
  2113. ret = false;
  2114. return ret;
  2115. }
  2116. });
  2117. return ret;
  2118. }
  2119. });
  2120. })(KISSY, KISSY.__loader, KISSY.__loaderData);
  2121. /**
  2122. * 2011-01-04 chengyu<yiminghe@gmail.com> refactor:
  2123. *
  2124. * adopt requirejs :
  2125. *
  2126. * 1. packages(cfg) , cfg :{
  2127. * name : 包名,用于指定业务模块前缀
  2128. * path: 前缀包名对应的路径
  2129. * charset: 该包下所有文件的编码
  2130. *
  2131. * 2. add(moduleName,function(S,depModule){return function(){}},{requires:["depModuleName"]});
  2132. * moduleName add 时可以不写
  2133. * depModuleName 可以写相对地址 (./ , ../),相对于 moduleName
  2134. *
  2135. * 3. S.use(["dom"],function(S,DOM){
  2136. * });
  2137. * 依赖注入,发生于 add 和 use 时期
  2138. *
  2139. * 4. add,use 不支持 css loader ,getScript 仍然保留支持
  2140. *
  2141. * 5. 部分更新模块文件代码 x/y?t=2011 ,加载过程中注意去除事件戳,仅在载入文件时使用
  2142. *
  2143. * demo : http://lite-ext.googlecode.com/svn/trunk/lite-ext/playground/module_package/index.html
  2144. *
  2145. * 2011-03-01 yiminghe@gmail.com note:
  2146. *
  2147. * compatibility
  2148. *
  2149. * 1. 保持兼容性,不得已而为之
  2150. * 支持 { host : }
  2151. * 如果 requires 都已经 attached,支持 add 后立即 attach
  2152. * 支持 { attach : false } 显示控制 add 时是否 attach
  2153. * 支持 { global : Editor } 指明模块来源
  2154. *
  2155. *
  2156. * 2011-05-04 初步拆分文件,tmd 乱了
  2157. */
  2158. /**
  2159. * @fileOverview package mechanism
  2160. * @author yiminghe@gmail.com
  2161. */
  2162. (function (S, loader, utils) {
  2163. if ("require" in this) {
  2164. return;
  2165. }
  2166. /**
  2167. * 包声明
  2168. * biz -> .
  2169. * 表示遇到 biz/x
  2170. * 在当前网页路径找 biz/x.js
  2171. * @private
  2172. */
  2173. S.configs.packages = function (cfgs) {
  2174. var ps;
  2175. ps = S.Config.packages = S.Config.packages || {};
  2176. S.each(cfgs, function (cfg) {
  2177. ps[cfg.name] = cfg;
  2178. //注意正则化
  2179. cfg.path = cfg.path && utils.normalBasePath(cfg.path);
  2180. cfg.tag = cfg.tag && encodeURIComponent(cfg.tag);
  2181. });
  2182. };
  2183. S.mix(loader, {
  2184. __getPackagePath:function (mod) {
  2185. //缓存包路径,未申明的包的模块都到核心模块中找
  2186. if (mod.packagepath) {
  2187. return mod.packagepath;
  2188. }
  2189. var self = this,
  2190. //一个模块合并到了另一个模块文件中去
  2191. modName = mod.name,
  2192. packages = self.Config.packages || {},
  2193. pName = "",
  2194. p_def;
  2195. for (var p in packages) {
  2196. if (packages.hasOwnProperty(p)) {
  2197. if (S.startsWith(modName, p) &&
  2198. p.length > pName) {
  2199. pName = p;
  2200. }
  2201. }
  2202. }
  2203. p_def = packages[pName];
  2204. mod.charset = p_def && p_def.charset || mod.charset;
  2205. if (p_def) {
  2206. mod.tag = p_def.tag;
  2207. } else {
  2208. // kissy 自身组件的事件戳后缀
  2209. mod.tag = encodeURIComponent(S.Config.tag || S.buildTime);
  2210. }
  2211. return mod.packagepath = (p_def && p_def.path) || self.Config.base;
  2212. }
  2213. });
  2214. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  2215. * @fileOverview register module ,associate module name with module factory(definition)
  2216. * @author yiminghe@gmail.com,lifesinger@gmail.com
  2217. */
  2218. (function(S, loader,data) {
  2219. if ("require" in this) {
  2220. return;
  2221. }
  2222. var LOADED = data.LOADED,
  2223. mix = S.mix;
  2224. mix(loader, {
  2225. //注册模块,将模块和定义 factory 关联起来
  2226. __registerModule:function(name, def, config) {
  2227. config = config || {};
  2228. var self = this,
  2229. mods = self.Env.mods,
  2230. mod = mods[name] || {};
  2231. // 注意:通过 S.add(name[, fn[, config]]) 注册的代码,无论是页面中的代码,
  2232. // 还是 js 文件里的代码,add 执行时,都意味着该模块已经 LOADED
  2233. mix(mod, { name: name, status: LOADED });
  2234. if (mod.fns && mod.fns.length) {
  2235. S.log(name + " is defined more than once");
  2236. //S.error(name + " is defined more than once");
  2237. }
  2238. //支持 host,一个模块多个 add factory
  2239. mod.fns = mod.fns || [];
  2240. mod.fns.push(def);
  2241. mix((mods[name] = mod), config);
  2242. }
  2243. });
  2244. })(KISSY, KISSY.__loader, KISSY.__loaderData);/**
  2245. * @fileOverview use and attach mod
  2246. * @author yiminghe@gmail.com,lifesinger@gmail.com
  2247. */
  2248. (function (S, loader, utils, data) {
  2249. if ("require" in this) {
  2250. return;
  2251. }
  2252. var LOADED = data.LOADED,
  2253. ATTACHED = data.ATTACHED;
  2254. S.mix(loader,
  2255. /**
  2256. * @lends KISSY
  2257. */
  2258. {
  2259. /**
  2260. * Start load specific mods, and fire callback when these mods and requires are attached.
  2261. * @example
  2262. * <code>
  2263. * S.use('mod-name', callback, config);
  2264. * S.use('mod1,mod2', callback, config);
  2265. * </code>
  2266. * @param {String|String[]} modNames names of mods to be loaded,if string then separated by space
  2267. * @param {Function} callback callback when modNames are all loaded,
  2268. * with KISSY as first argument and mod's value as the following argumwnts
  2269. * @param {Object} cfg special config for this use
  2270. */
  2271. use:function (modNames, callback, cfg) {
  2272. if (S.isString(modNames)) {
  2273. modNames = modNames.replace(/\s+/g, "").split(',');
  2274. }
  2275. utils.indexMapping(modNames);
  2276. cfg = cfg || {};
  2277. var self = this,
  2278. fired;
  2279. // 已经全部 attached, 直接执行回调即可
  2280. if (self.__isAttached(modNames)) {
  2281. var mods = self.__getModules(modNames);
  2282. callback && callback.apply(self, mods);
  2283. return;
  2284. }
  2285. // 有尚未 attached 的模块
  2286. S.each(modNames, function (modName) {
  2287. // 从 name 开始调用,防止不存在模块
  2288. self.__attachModByName(modName, function () {
  2289. if (!fired &&
  2290. self.__isAttached(modNames)) {
  2291. fired = true;
  2292. var mods = self.__getModules(modNames);
  2293. callback && callback.apply(self, mods);
  2294. }
  2295. }, cfg);
  2296. });
  2297. return self;
  2298. },
  2299. __getModules:function (modNames) {
  2300. var self = this,
  2301. mods = [self];
  2302. S.each(modNames, function (modName) {
  2303. if (!utils.isCss(modName)) {
  2304. mods.push(self.require(modName));
  2305. }
  2306. });
  2307. return mods;
  2308. },
  2309. /**
  2310. * get module's value defined by define function
  2311. * @param {string} moduleName
  2312. * @private
  2313. */
  2314. require:function (moduleName) {
  2315. var self = this,
  2316. mods = self.Env.mods,
  2317. mod = mods[moduleName],
  2318. re = self['onRequire'] && self['onRequire'](mod);
  2319. if (re !== undefined) {
  2320. return re;
  2321. }
  2322. return mod && mod.value;
  2323. },
  2324. // 加载指定模块名模块,如果不存在定义默认定义为内部模块
  2325. __attachModByName:function (modName, callback, cfg) {
  2326. var self = this,
  2327. mods = self.Env.mods;
  2328. var mod = mods[modName];
  2329. //没有模块定义
  2330. if (!mod) {
  2331. // 默认 js/css 名字
  2332. // 不指定 .js 默认为 js
  2333. // 指定为 css 载入 .css
  2334. var componentJsName = self.Config['componentJsName'] ||
  2335. function (m) {
  2336. var suffix = "js", match;
  2337. if (match = m.match(/(.+)\.(js|css)$/i)) {
  2338. suffix = match[2];
  2339. m = match[1];
  2340. }
  2341. return m + '-min.' + suffix;
  2342. },
  2343. path = componentJsName(modName);
  2344. mod = {
  2345. path:path,
  2346. charset:'utf-8'
  2347. };
  2348. //添加模块定义
  2349. mods[modName] = mod;
  2350. }
  2351. mod.name = modName;
  2352. if (mod && mod.status === ATTACHED) {
  2353. callback();
  2354. return;
  2355. }
  2356. // 先从 global 里取
  2357. if (cfg.global) {
  2358. self.__mixMod(modName, cfg.global);
  2359. }
  2360. self.__attach(mod, callback, cfg);
  2361. },
  2362. /**
  2363. * Attach a module and all required modules.
  2364. */
  2365. __attach:function (mod, callback, cfg) {
  2366. var self = this,
  2367. r,
  2368. rMod,
  2369. i,
  2370. attached = 0,
  2371. mods = self.Env.mods,
  2372. //复制一份当前的依赖项出来,防止 add 后修改!
  2373. requires = (mod['requires'] || []).concat();
  2374. mod['requires'] = requires;
  2375. /**
  2376. * check cyclic dependency between mods
  2377. * @private
  2378. */
  2379. function cyclicCheck() {
  2380. var __allRequires,
  2381. myName = mod.name,
  2382. r, r2, rmod,
  2383. r__allRequires,
  2384. requires = mod.requires;
  2385. // one mod's all requires mods to run its callback
  2386. __allRequires = mod.__allRequires = mod.__allRequires || {};
  2387. for (var i = 0; i < requires.length; i++) {
  2388. r = requires[i];
  2389. rmod = mods[r];
  2390. __allRequires[r] = 1;
  2391. if (rmod && (r__allRequires = rmod.__allRequires)) {
  2392. for (r2 in r__allRequires) {
  2393. if (r__allRequires.hasOwnProperty(r2)) {
  2394. __allRequires[r2] = 1;
  2395. }
  2396. }
  2397. }
  2398. }
  2399. if (__allRequires[myName]) {
  2400. var t = [];
  2401. for (r in __allRequires) {
  2402. if (__allRequires.hasOwnProperty(r)) {
  2403. t.push(r);
  2404. }
  2405. }
  2406. S.error("find cyclic dependency by mod " + myName + " between mods : " + t.join(","));
  2407. }
  2408. }
  2409. if (S.Config.debug) {
  2410. cyclicCheck();
  2411. }
  2412. // attach all required modules
  2413. for (i = 0; i < requires.length; i++) {
  2414. r = requires[i] = utils.normalDepModuleName(mod.name, requires[i]);
  2415. rMod = mods[r];
  2416. if (rMod && rMod.status === ATTACHED) {
  2417. //no need
  2418. } else {
  2419. self.__attachModByName(r, fn, cfg);
  2420. }
  2421. }
  2422. // load and attach this module
  2423. self.__buildPath(mod, self.__getPackagePath(mod));
  2424. self.__load(mod, function () {
  2425. // add 可能改了 config,这里重新取下
  2426. mod['requires'] = mod['requires'] || [];
  2427. var newRequires = mod['requires'],
  2428. needToLoad = [];
  2429. //本模块下载成功后串行下载 require
  2430. for (i = 0; i < newRequires.length; i++) {
  2431. r = newRequires[i] = utils.normalDepModuleName(mod.name, newRequires[i]);
  2432. var rMod = mods[r],
  2433. inA = S.inArray(r, requires);
  2434. //已经处理过了或将要处理
  2435. if (rMod &&
  2436. rMod.status === ATTACHED
  2437. //已经正在处理了
  2438. || inA) {
  2439. //no need
  2440. } else {
  2441. //新增的依赖项
  2442. needToLoad.push(r);
  2443. }
  2444. }
  2445. if (needToLoad.length) {
  2446. for (i = 0; i < needToLoad.length; i++) {
  2447. self.__attachModByName(needToLoad[i], fn, cfg);
  2448. }
  2449. } else {
  2450. fn();
  2451. }
  2452. }, cfg);
  2453. function fn() {
  2454. if (!attached &&
  2455. self.__isAttached(mod['requires'])) {
  2456. if (mod.status === LOADED) {
  2457. self.__attachMod(mod);
  2458. }
  2459. if (mod.status === ATTACHED) {
  2460. attached = 1;
  2461. callback();
  2462. }
  2463. }
  2464. }
  2465. },
  2466. __attachMod:function (mod) {
  2467. var self = this,
  2468. fns = mod.fns;
  2469. if (fns) {
  2470. S.each(fns, function (fn) {
  2471. var value;
  2472. if (S.isFunction(fn)) {
  2473. value = fn.apply(self, self.__getModules(mod['requires']));
  2474. } else {
  2475. value = fn;
  2476. }
  2477. mod.value = mod.value || value;
  2478. });
  2479. }
  2480. mod.status = ATTACHED;
  2481. }
  2482. });
  2483. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  2484. * @fileOverview map mechanism
  2485. * @author yiminghe@gmail.com
  2486. */
  2487. (function (S, loader) {
  2488. if ("require" in this) {
  2489. return;
  2490. }
  2491. /**
  2492. * modify current module path
  2493. * @private
  2494. * @param rules
  2495. * @example
  2496. * <code>
  2497. * [
  2498. * [/(.+-)min(.js(\?t=\d+)?)$/,"$1$2"],
  2499. * [/(.+-)min(.js(\?t=\d+)?)$/,function(_,m1,m2){
  2500. * return m1+m2;
  2501. * }]
  2502. * ]
  2503. * </code>
  2504. */
  2505. S.configs.map = function (rules) {
  2506. S.Config.mappedRules = (S.Config.mappedRules || []).concat(rules);
  2507. };
  2508. S.mix(loader, {
  2509. __getMappedPath:function (path) {
  2510. var __mappedRules = S.Config.mappedRules || [];
  2511. for (var i = 0; i < __mappedRules.length; i++) {
  2512. var m, rule = __mappedRules[i];
  2513. if (m = path.match(rule[0])) {
  2514. return path.replace(rule[0], rule[1]);
  2515. }
  2516. }
  2517. return path;
  2518. }
  2519. });
  2520. })(KISSY, KISSY.__loader);/**
  2521. * @fileOverview mix loader into S and infer KISSy baseUrl if not set
  2522. * @author lifesinger@gmail.com,yiminghe@gmail.com
  2523. */
  2524. (function (S, loader, utils) {
  2525. if ("require" in this) {
  2526. return;
  2527. }
  2528. S.mix(S, loader);
  2529. /**
  2530. * get base from src
  2531. * @param src script source url
  2532. * @return base for kissy
  2533. * @example:
  2534. * http://a.tbcdn.cn/s/kissy/1.1.6/??kissy-min.js,suggest/suggest-pkg-min.js
  2535. * http://a.tbcdn.cn/??s/kissy/1.1.6/kissy-min.js,s/kissy/1.1.5/suggest/suggest-pkg-min.js
  2536. * http://a.tbcdn.cn/??s/kissy/1.1.6/suggest/suggest-pkg-min.js,s/kissy/1.1.5/kissy-min.js
  2537. * http://a.tbcdn.cn/s/kissy/1.1.6/kissy-min.js?t=20101215.js
  2538. * @notice: custom combo rules, such as yui3:
  2539. * <script src="path/to/kissy" data-combo-prefix="combo?" data-combo-sep="&"></script>
  2540. */
  2541. // notice: timestamp
  2542. var baseReg = /^(.*)(seed|kissy)(-aio)?(-min)?\.js[^/]*/i,
  2543. baseTestReg = /(seed|kissy)(-aio)?(-min)?\.js/i;
  2544. function getBaseUrl(script) {
  2545. var src = utils.absoluteFilePath(script.src),
  2546. prefix = script.getAttribute('data-combo-prefix') || '??',
  2547. sep = script.getAttribute('data-combo-sep') || ',',
  2548. parts = src.split(sep),
  2549. base,
  2550. part0 = parts[0],
  2551. index = part0.indexOf(prefix);
  2552. // no combo
  2553. if (index == -1) {
  2554. base = src.replace(baseReg, '$1');
  2555. } else {
  2556. base = part0.substring(0, index);
  2557. var part01 = part0.substring(index + 2, part0.length);
  2558. // combo first
  2559. // notice use match better than test
  2560. if (part01.match(baseTestReg)) {
  2561. base += part01.replace(baseReg, '$1');
  2562. }
  2563. // combo after first
  2564. else {
  2565. S.each(parts, function (part) {
  2566. if (part.match(baseTestReg)) {
  2567. base += part.replace(baseReg, '$1');
  2568. return false;
  2569. }
  2570. });
  2571. }
  2572. }
  2573. return base;
  2574. }
  2575. /**
  2576. * Initializes loader.
  2577. */
  2578. S.__initLoader = function () {
  2579. var self = this;
  2580. self.Env.mods = self.Env.mods || {}; // all added mods
  2581. };
  2582. S.Env._loadQueue = {}; // information for loading and loaded mods
  2583. S.__initLoader();
  2584. (function () {
  2585. // get base from current script file path
  2586. var scripts = document.getElementsByTagName('script'),
  2587. currentScript = scripts[scripts.length - 1],
  2588. base = getBaseUrl(currentScript);
  2589. S.Config.base = utils.normalBasePath(base);
  2590. // the default timeout for getScript
  2591. S.Config.timeout = 10;
  2592. })();
  2593. S.mix(S.configs, {
  2594. base:function (base) {
  2595. S.Config.base = utils.normalBasePath(base);
  2596. },
  2597. timeout:function (v) {
  2598. S.Config.timeout = v;
  2599. },
  2600. debug:function (v) {
  2601. S.Config.debug = v;
  2602. }
  2603. });
  2604. // for S.app working properly
  2605. S.each(loader, function (v, k) {
  2606. S.__APP_MEMBERS.push(k);
  2607. });
  2608. S.__APP_INIT_METHODS.push('__initLoader');
  2609. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  2610. * @fileOverview web.js
  2611. * @author lifesinger@gmail.com,yiminghe@gmail.com
  2612. * @description this code can only run at browser environment
  2613. */
  2614. (function (S, undefined) {
  2615. var win = S.__HOST,
  2616. doc = win['document'],
  2617. docElem = doc.documentElement,
  2618. EMPTY = '',
  2619. // Is the DOM ready to be used? Set to true once it occurs.
  2620. isReady = false,
  2621. // The functions to execute on DOM ready.
  2622. readyList = [],
  2623. // The number of poll times.
  2624. POLL_RETRYS = 500,
  2625. // The poll interval in milliseconds.
  2626. POLL_INTERVAL = 40,
  2627. // #id or id
  2628. RE_IDSTR = /^#?([\w-]+)$/,
  2629. RE_NOT_WHITE = /\S/;
  2630. S.mix(S,
  2631. /**
  2632. * @lends KISSY
  2633. */
  2634. {
  2635. /**
  2636. * A crude way of determining if an object is a window
  2637. */
  2638. isWindow:function (o) {
  2639. return S.type(o) === 'object'
  2640. && 'setInterval' in o
  2641. && 'document' in o
  2642. && o.document.nodeType == 9;
  2643. },
  2644. /**
  2645. * get xml representation of data
  2646. * @param {String} data
  2647. */
  2648. parseXML:function (data) {
  2649. var xml;
  2650. try {
  2651. // Standard
  2652. if (window.DOMParser) {
  2653. xml = new DOMParser().parseFromString(data, "text/xml");
  2654. } else { // IE
  2655. xml = new ActiveXObject("Microsoft.XMLDOM");
  2656. xml.async = "false";
  2657. xml.loadXML(data);
  2658. }
  2659. } catch (e) {
  2660. S.log("parseXML error : ");
  2661. S.log(e);
  2662. xml = undefined;
  2663. }
  2664. if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
  2665. S.error("Invalid XML: " + data);
  2666. }
  2667. return xml;
  2668. },
  2669. /**
  2670. * Evalulates a script in a global context.
  2671. */
  2672. globalEval:function (data) {
  2673. if (data && RE_NOT_WHITE.test(data)) {
  2674. // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
  2675. ( window.execScript || function (data) {
  2676. window[ "eval" ].call(window, data);
  2677. } )(data);
  2678. }
  2679. },
  2680. /**
  2681. * Specify a function to execute when the DOM is fully loaded.
  2682. * @param fn {Function} A function to execute after the DOM is ready
  2683. * <code>
  2684. * KISSY.ready(function(S){ });
  2685. * </code>
  2686. * @return {KISSY}
  2687. */
  2688. ready:function (fn) {
  2689. // If the DOM is already ready
  2690. if (isReady) {
  2691. // Execute the function immediately
  2692. fn.call(win, this);
  2693. } else {
  2694. // Remember the function for later
  2695. readyList.push(fn);
  2696. }
  2697. return this;
  2698. },
  2699. /**
  2700. * Executes the supplied callback when the item with the supplied id is found.
  2701. * @param id <String> The id of the element, or an array of ids to look for.
  2702. * @param fn <Function> What to execute when the element is found.
  2703. */
  2704. available:function (id, fn) {
  2705. id = (id + EMPTY).match(RE_IDSTR)[1];
  2706. if (!id || !S.isFunction(fn)) {
  2707. return;
  2708. }
  2709. var retryCount = 1,
  2710. node,
  2711. timer = S.later(function () {
  2712. if ((node = doc.getElementById(id)) && (fn(node) || 1) ||
  2713. ++retryCount > POLL_RETRYS) {
  2714. timer.cancel();
  2715. }
  2716. }, POLL_INTERVAL, true);
  2717. }
  2718. });
  2719. /**
  2720. * Binds ready events.
  2721. */
  2722. function _bindReady() {
  2723. var doScroll = docElem.doScroll,
  2724. eventType = doScroll ? 'onreadystatechange' : 'DOMContentLoaded',
  2725. COMPLETE = 'complete',
  2726. fire = function () {
  2727. _fireReady();
  2728. };
  2729. // Catch cases where ready() is called after the
  2730. // browser event has already occurred.
  2731. if (doc.readyState === COMPLETE) {
  2732. return fire();
  2733. }
  2734. // w3c mode
  2735. if (doc.addEventListener) {
  2736. function domReady() {
  2737. doc.removeEventListener(eventType, domReady, false);
  2738. fire();
  2739. }
  2740. doc.addEventListener(eventType, domReady, false);
  2741. // A fallback to window.onload, that will always work
  2742. win.addEventListener('load', fire, false);
  2743. }
  2744. // IE event model is used
  2745. else {
  2746. function stateChange() {
  2747. if (doc.readyState === COMPLETE) {
  2748. doc.detachEvent(eventType, stateChange);
  2749. fire();
  2750. }
  2751. }
  2752. // ensure firing before onload, maybe late but safe also for iframes
  2753. doc.attachEvent(eventType, stateChange);
  2754. // A fallback to window.onload, that will always work.
  2755. win.attachEvent('onload', fire);
  2756. // If IE and not a frame
  2757. // continually check to see if the document is ready
  2758. var notframe = false;
  2759. try {
  2760. notframe = (win['frameElement'] === null);
  2761. } catch (e) {
  2762. S.log("frameElement error : ");
  2763. S.log(e);
  2764. }
  2765. if (doScroll && notframe) {
  2766. function readyScroll() {
  2767. try {
  2768. // Ref: http://javascript.nwbox.com/IEContentLoaded/
  2769. doScroll('left');
  2770. fire();
  2771. } catch (ex) {
  2772. //S.log("detect document ready : " + ex);
  2773. setTimeout(readyScroll, POLL_INTERVAL);
  2774. }
  2775. }
  2776. readyScroll();
  2777. }
  2778. }
  2779. return 0;
  2780. }
  2781. /**
  2782. * Executes functions bound to ready event.
  2783. */
  2784. function _fireReady() {
  2785. if (isReady) {
  2786. return;
  2787. }
  2788. // Remember that the DOM is ready
  2789. isReady = true;
  2790. // If there are functions bound, to execute
  2791. if (readyList) {
  2792. // Execute all of them
  2793. var fn, i = 0;
  2794. while (fn = readyList[i++]) {
  2795. fn.call(win, S);
  2796. }
  2797. // Reset the list of functions
  2798. readyList = null;
  2799. }
  2800. }
  2801. // If url contains '?ks-debug', debug mode will turn on automatically.
  2802. if (location && (location.search || EMPTY).indexOf('ks-debug') !== -1) {
  2803. S.Config.debug = true;
  2804. }
  2805. /**
  2806. * bind on start
  2807. * in case when you bind but the DOMContentLoaded has triggered
  2808. * then you has to wait onload
  2809. * worst case no callback at all
  2810. */
  2811. _bindReady();
  2812. })(KISSY, undefined);
  2813. /*
  2814. Copyright 2011, KISSY UI Library v1.30dev
  2815. MIT Licensed
  2816. build time: Dec 31 15:26
  2817. */
  2818. /**
  2819. * @fileOverview ua
  2820. * @author lifesinger@gmail.com
  2821. */
  2822. KISSY.add('ua/base', function() {
  2823. var ua = navigator.userAgent,
  2824. EMPTY = '', MOBILE = 'mobile',
  2825. core = EMPTY, shell = EMPTY, m,
  2826. IE_DETECT_RANGE = [6, 9], v, end,
  2827. VERSION_PLACEHOLDER = '{{version}}',
  2828. IE_DETECT_TPL = '<!--[if IE ' + VERSION_PLACEHOLDER + ']><s></s><![endif]-->',
  2829. div = document.createElement('div'), s,
  2830. o = {
  2831. // browser core type
  2832. //webkit: 0,
  2833. //trident: 0,
  2834. //gecko: 0,
  2835. //presto: 0,
  2836. // browser type
  2837. //chrome: 0,
  2838. //safari: 0,
  2839. //firefox: 0,
  2840. //ie: 0,
  2841. //opera: 0
  2842. //mobile: '',
  2843. //core: '',
  2844. //shell: ''
  2845. },
  2846. numberify = function(s) {
  2847. var c = 0;
  2848. // convert '1.2.3.4' to 1.234
  2849. return parseFloat(s.replace(/\./g, function() {
  2850. return (c++ === 0) ? '.' : '';
  2851. }));
  2852. };
  2853. // try to use IE-Conditional-Comment detect IE more accurately
  2854. // IE10 doesn't support this method, @ref: http://blogs.msdn.com/b/ie/archive/2011/07/06/html5-parsing-in-ie10.aspx
  2855. div.innerHTML = IE_DETECT_TPL.replace(VERSION_PLACEHOLDER, '');
  2856. s = div.getElementsByTagName('s');
  2857. if (s.length > 0) {
  2858. shell = 'ie';
  2859. o[core = 'trident'] = 0.1; // Trident detected, look for revision
  2860. // Get the Trident's accurate version
  2861. if ((m = ua.match(/Trident\/([\d.]*)/)) && m[1]) {
  2862. o[core] = numberify(m[1]);
  2863. }
  2864. // Detect the accurate version
  2865. // 注意:
  2866. // o.shell = ie, 表示外壳是 ie
  2867. // 但 o.ie = 7, 并不代表外壳是 ie7, 还有可能是 ie8 的兼容模式
  2868. // 对于 ie8 的兼容模式,还要通过 documentMode 去判断。但此处不能让 o.ie = 8, 否则
  2869. // 很多脚本判断会失误。因为 ie8 的兼容模式表现行为和 ie7 相同,而不是和 ie8 相同
  2870. for (v = IE_DETECT_RANGE[0],end = IE_DETECT_RANGE[1]; v <= end; v++) {
  2871. div.innerHTML = IE_DETECT_TPL.replace(VERSION_PLACEHOLDER, v);
  2872. if (s.length > 0) {
  2873. o[shell] = v;
  2874. break;
  2875. }
  2876. }
  2877. } else {
  2878. // WebKit
  2879. if ((m = ua.match(/AppleWebKit\/([\d.]*)/)) && m[1]) {
  2880. o[core = 'webkit'] = numberify(m[1]);
  2881. // Chrome
  2882. if ((m = ua.match(/Chrome\/([\d.]*)/)) && m[1]) {
  2883. o[shell = 'chrome'] = numberify(m[1]);
  2884. }
  2885. // Safari
  2886. else if ((m = ua.match(/\/([\d.]*) Safari/)) && m[1]) {
  2887. o[shell = 'safari'] = numberify(m[1]);
  2888. }
  2889. // Apple Mobile
  2890. if (/ Mobile\//.test(ua)) {
  2891. o[MOBILE] = 'apple'; // iPad, iPhone or iPod Touch
  2892. }
  2893. // Other WebKit Mobile Browsers
  2894. else if ((m = ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/))) {
  2895. o[MOBILE] = m[0].toLowerCase(); // Nokia N-series, Android, webOS, ex: NokiaN95
  2896. }
  2897. }
  2898. // NOT WebKit
  2899. else {
  2900. // Presto
  2901. // ref: http://www.useragentstring.com/pages/useragentstring.php
  2902. if ((m = ua.match(/Presto\/([\d.]*)/)) && m[1]) {
  2903. o[core = 'presto'] = numberify(m[1]);
  2904. // Opera
  2905. if ((m = ua.match(/Opera\/([\d.]*)/)) && m[1]) {
  2906. o[shell = 'opera'] = numberify(m[1]); // Opera detected, look for revision
  2907. if ((m = ua.match(/Opera\/.* Version\/([\d.]*)/)) && m[1]) {
  2908. o[shell] = numberify(m[1]);
  2909. }
  2910. // Opera Mini
  2911. if ((m = ua.match(/Opera Mini[^;]*/)) && m) {
  2912. o[MOBILE] = m[0].toLowerCase(); // ex: Opera Mini/2.0.4509/1316
  2913. }
  2914. // Opera Mobile
  2915. // ex: Opera/9.80 (Windows NT 6.1; Opera Mobi/49; U; en) Presto/2.4.18 Version/10.00
  2916. // issue: 由于 Opera Mobile 有 Version/ 字段,可能会与 Opera 混淆,同时对于 Opera Mobile 的版本号也比较混乱
  2917. else if ((m = ua.match(/Opera Mobi[^;]*/)) && m) {
  2918. o[MOBILE] = m[0];
  2919. }
  2920. }
  2921. // NOT WebKit or Presto
  2922. } else {
  2923. // MSIE
  2924. // 由于最开始已经使用了 IE 条件注释判断,因此落到这里的唯一可能性只有 IE10+
  2925. if ((m = ua.match(/MSIE\s([^;]*)/)) && m[1]) {
  2926. o[core = 'trident'] = 0.1; // Trident detected, look for revision
  2927. o[shell = 'ie'] = numberify(m[1]);
  2928. // Get the Trident's accurate version
  2929. if ((m = ua.match(/Trident\/([\d.]*)/)) && m[1]) {
  2930. o[core] = numberify(m[1]);
  2931. }
  2932. // NOT WebKit, Presto or IE
  2933. } else {
  2934. // Gecko
  2935. if ((m = ua.match(/Gecko/))) {
  2936. o[core = 'gecko'] = 0.1; // Gecko detected, look for revision
  2937. if ((m = ua.match(/rv:([\d.]*)/)) && m[1]) {
  2938. o[core] = numberify(m[1]);
  2939. }
  2940. // Firefox
  2941. if ((m = ua.match(/Firefox\/([\d.]*)/)) && m[1]) {
  2942. o[shell = 'firefox'] = numberify(m[1]);
  2943. }
  2944. }
  2945. }
  2946. }
  2947. }
  2948. }
  2949. o.core = core;
  2950. o.shell = shell;
  2951. o._numberify = numberify;
  2952. return o;
  2953. });
  2954. /**
  2955. * NOTES:
  2956. *
  2957. * 2011.11.08
  2958. * - ie < 10 使用条件注释判断内核,更精确 by gonghaocn@gmail.com
  2959. *
  2960. * 2010.03
  2961. * - jQuery, YUI 等类库都推荐用特性探测替代浏览器嗅探。特性探测的好处是能自动适应未来设备和未知设备,比如
  2962. * if(document.addEventListener) 假设 IE9 支持标准事件,则代码不用修改,就自适应了“未来浏览器”。
  2963. * 对于未知浏览器也是如此。但是,这并不意味着浏览器嗅探就得彻底抛弃。当代码很明确就是针对已知特定浏览器的,
  2964. * 同时并非是某个特性探测可以解决时,用浏览器嗅探反而能带来代码的简洁,同时也也不会有什么后患。总之,一切
  2965. * 皆权衡。
  2966. * - UA.ie && UA.ie < 8 并不意味着浏览器就不是 IE8, 有可能是 IE8 的兼容模式。进一步的判断需要使用 documentMode.
  2967. *
  2968. * TODO:
  2969. * - test mobile
  2970. * - 3Q 大战后,360 去掉了 UA 信息中的 360 信息,需采用 res 方法去判断
  2971. *
  2972. */
  2973. /**
  2974. * @fileOverview ua-extra
  2975. * @author gonghao<gonghao@ghsky.com>
  2976. */
  2977. KISSY.add('ua/extra', function(S, UA) {
  2978. var ua = navigator.userAgent,
  2979. m, external, shell,
  2980. o = { },
  2981. numberify = UA._numberify;
  2982. /**
  2983. * 说明:
  2984. * @子涯总结的各国产浏览器的判断依据: http://spreadsheets0.google.com/ccc?key=tluod2VGe60_ceDrAaMrfMw&hl=zh_CN#gid=0
  2985. * 根据 CNZZ 2009 年度浏览器占用率报告,优化了判断顺序:http://www.tanmi360.com/post/230.htm
  2986. * 如果检测出浏览器,但是具体版本号未知用 0.1 作为标识
  2987. * 世界之窗 & 360 浏览器,在 3.x 以下的版本都无法通过 UA 或者特性检测进行判断,所以目前只要检测到 UA 关键字就认为起版本号为 3
  2988. */
  2989. // 360Browser
  2990. if (m = ua.match(/360SE/)) {
  2991. o[shell = 'se360'] = 3; // issue: 360Browser 2.x cannot be recognised, so if recognised default set verstion number to 3
  2992. }
  2993. // Maxthon
  2994. else if ((m = ua.match(/Maxthon/)) && (external = window.external)) {
  2995. // issue: Maxthon 3.x in IE-Core cannot be recognised and it doesn't have exact version number
  2996. // but other maxthon versions all have exact version number
  2997. shell = 'maxthon';
  2998. try {
  2999. o[shell] = numberify(external['max_version']);
  3000. } catch(ex) {
  3001. o[shell] = 0.1;
  3002. }
  3003. }
  3004. // TT
  3005. else if (m = ua.match(/TencentTraveler\s([\d.]*)/)) {
  3006. o[shell = 'tt'] = m[1] ? numberify(m[1]) : 0.1;
  3007. }
  3008. // TheWorld
  3009. else if (m = ua.match(/TheWorld/)) {
  3010. o[shell = 'theworld'] = 3; // issue: TheWorld 2.x cannot be recognised, so if recognised default set verstion number to 3
  3011. }
  3012. // Sougou
  3013. else if (m = ua.match(/SE\s([\d.]*)/)) {
  3014. o[shell = 'sougou'] = m[1] ? numberify(m[1]) : 0.1;
  3015. }
  3016. // If the browser has shell(no matter IE-core or Webkit-core or others), set the shell key
  3017. shell && (o.shell = shell);
  3018. S.mix(UA, o);
  3019. return UA;
  3020. }, {
  3021. requires:["ua/base"]
  3022. });
  3023. /**
  3024. * @fileOverview ua
  3025. */
  3026. KISSY.add("ua", function(S,UA) {
  3027. return UA;
  3028. }, {
  3029. requires:["ua/extra"]
  3030. });
  3031. /*
  3032. Copyright 2012, KISSY UI Library v1.30dev
  3033. MIT Licensed
  3034. build time: Jan 10 14:34
  3035. */
  3036. /**
  3037. * @fileOverview dom-attr
  3038. * @author yiminghe@gmail.com,lifesinger@gmail.com
  3039. */
  3040. KISSY.add('dom/attr', function (S, DOM, UA, undefined) {
  3041. var doc = document,
  3042. docElement = doc.documentElement,
  3043. oldIE = !docElement.hasAttribute,
  3044. TEXT = docElement.textContent === undefined ?
  3045. 'innerText' : 'textContent',
  3046. EMPTY = '',
  3047. nodeName = DOM._nodeName,
  3048. isElementNode = DOM._isElementNode,
  3049. rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
  3050. rfocusable = /^(?:button|input|object|select|textarea)$/i,
  3051. rclickable = /^a(?:rea)?$/i,
  3052. rinvalidChar = /:|^on/,
  3053. rreturn = /\r/g,
  3054. attrFix = {
  3055. },
  3056. attrFn = {
  3057. val:1,
  3058. css:1,
  3059. html:1,
  3060. text:1,
  3061. data:1,
  3062. width:1,
  3063. height:1,
  3064. offset:1,
  3065. scrollTop:1,
  3066. scrollLeft:1
  3067. },
  3068. attrHooks = {
  3069. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  3070. tabindex:{
  3071. get:function (el) {
  3072. // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  3073. var attributeNode = el.getAttributeNode("tabindex");
  3074. return attributeNode && attributeNode.specified ?
  3075. parseInt(attributeNode.value, 10) :
  3076. rfocusable.test(el.nodeName) || rclickable.test(el.nodeName) && el.href ?
  3077. 0 :
  3078. undefined;
  3079. }
  3080. },
  3081. // 在标准浏览器下,用 getAttribute 获取 style 值
  3082. // IE7- 下,需要用 cssText 来获取
  3083. // 统一使用 cssText
  3084. style:{
  3085. get:function (el) {
  3086. return el.style.cssText;
  3087. },
  3088. set:function (el, val) {
  3089. el.style.cssText = val;
  3090. }
  3091. }
  3092. },
  3093. propFix = {
  3094. "hidefocus":"hideFocus",
  3095. tabindex:"tabIndex",
  3096. readonly:"readOnly",
  3097. "for":"htmlFor",
  3098. "class":"className",
  3099. maxlength:"maxLength",
  3100. cellspacing:"cellSpacing",
  3101. "cellpadding":"cellPadding",
  3102. rowspan:"rowSpan",
  3103. colspan:"colSpan",
  3104. usemap:"useMap",
  3105. frameborder:"frameBorder",
  3106. "contenteditable":"contentEditable"
  3107. },
  3108. // Hook for boolean attributes
  3109. // if bool is false
  3110. // - standard browser returns null
  3111. // - ie<8 return false
  3112. // - so norm to undefined
  3113. boolHook = {
  3114. get:function (elem, name) {
  3115. // 转发到 prop 方法
  3116. return DOM.prop(elem, name) ?
  3117. // 根据 w3c attribute , true 时返回属性名字符串
  3118. name.toLowerCase() :
  3119. undefined;
  3120. },
  3121. set:function (elem, value, name) {
  3122. var propName;
  3123. if (value === false) {
  3124. // Remove boolean attributes when set to false
  3125. DOM.removeAttr(elem, name);
  3126. } else {
  3127. // 直接设置 true,因为这是 bool 类属性
  3128. propName = propFix[ name ] || name;
  3129. if (propName in elem) {
  3130. // Only set the IDL specifically if it already exists on the element
  3131. elem[ propName ] = true;
  3132. }
  3133. elem.setAttribute(name, name.toLowerCase());
  3134. }
  3135. return name;
  3136. }
  3137. },
  3138. propHooks = {},
  3139. // get attribute value from attribute node , only for ie
  3140. attrNodeHook = {
  3141. },
  3142. valHooks = {
  3143. option:{
  3144. get:function (elem) {
  3145. // 当没有设定 value 时,标准浏览器 option.value === option.text
  3146. // ie7- 下,没有设定 value 时,option.value === '', 需要用 el.attributes.value 来判断是否有设定 value
  3147. var val = elem.attributes.value;
  3148. return !val || val.specified ? elem.value : elem.text;
  3149. }
  3150. },
  3151. select:{
  3152. // 对于 select, 特别是 multiple type, 存在很严重的兼容性问题
  3153. get:function (elem) {
  3154. var index = elem.selectedIndex,
  3155. options = elem.options,
  3156. one = elem.type === "select-one";
  3157. // Nothing was selected
  3158. if (index < 0) {
  3159. return null;
  3160. } else if (one) {
  3161. return DOM.val(options[index]);
  3162. }
  3163. // Loop through all the selected options
  3164. var ret = [], i = 0, len = options.length;
  3165. for (; i < len; ++i) {
  3166. if (options[i].selected) {
  3167. ret.push(DOM.val(options[i]));
  3168. }
  3169. }
  3170. // Multi-Selects return an array
  3171. return ret;
  3172. },
  3173. set:function (elem, value) {
  3174. var values = S.makeArray(value),
  3175. opts = elem.options;
  3176. S.each(opts, function (opt) {
  3177. opt.selected = S.inArray(DOM.val(opt), values);
  3178. });
  3179. if (!values.length) {
  3180. elem.selectedIndex = -1;
  3181. }
  3182. return values;
  3183. }
  3184. }};
  3185. function isTextNode(elem) {
  3186. return DOM._nodeTypeIs(elem, DOM.TEXT_NODE);
  3187. }
  3188. if (oldIE) {
  3189. // get attribute value from attribute node for ie
  3190. attrNodeHook = {
  3191. get:function (elem, name) {
  3192. var ret;
  3193. ret = elem.getAttributeNode(name);
  3194. // Return undefined if nodeValue is empty string
  3195. return ret && ret.nodeValue !== "" ?
  3196. ret.nodeValue :
  3197. undefined;
  3198. },
  3199. set:function (elem, value, name) {
  3200. // Check form objects in IE (multiple bugs related)
  3201. // Only use nodeValue if the attribute node exists on the form
  3202. var ret = elem.getAttributeNode(name);
  3203. if (ret) {
  3204. ret.nodeValue = value;
  3205. } else {
  3206. try {
  3207. var attr = elem.ownerDocument.createAttribute(name);
  3208. attr.value = value;
  3209. elem.setAttributeNode(attr);
  3210. }
  3211. catch (e) {
  3212. // It's a real failure only if setAttribute also fails.
  3213. // http://msdn.microsoft.com/en-us/library/ms536739(v=vs.85).aspx
  3214. // 0 : Match sAttrName regardless of case.
  3215. return elem.setAttribute(name, value, 0);
  3216. }
  3217. }
  3218. }
  3219. };
  3220. // ie6,7 不区分 attribute 与 property
  3221. attrFix = propFix;
  3222. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  3223. attrHooks.tabIndex = attrHooks.tabindex;
  3224. // fix ie bugs
  3225. // 不光是 href, src, 还有 rowspan 等非 mapping 属性,也需要用第 2 个参数来获取原始值
  3226. // 注意 colSpan rowSpan 已经由 propFix 转为大写
  3227. S.each([ "href", "src", "width", "height", "colSpan", "rowSpan" ], function (name) {
  3228. attrHooks[ name ] = {
  3229. get:function (elem) {
  3230. var ret = elem.getAttribute(name, 2);
  3231. return ret === null ? undefined : ret;
  3232. }
  3233. };
  3234. });
  3235. // button 元素的 value 属性和其内容冲突
  3236. // <button value='xx'>zzz</button>
  3237. valHooks.button = attrHooks.value = attrNodeHook;
  3238. }
  3239. // Radios and checkboxes getter/setter
  3240. S.each([ "radio", "checkbox" ], function (r) {
  3241. valHooks[ r ] = {
  3242. get:function (elem) {
  3243. // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
  3244. return elem.getAttribute("value") === null ? "on" : elem.value;
  3245. },
  3246. set:function (elem, value) {
  3247. if (S.isArray(value)) {
  3248. return elem.checked = S.inArray(DOM.val(elem), value);
  3249. }
  3250. }
  3251. };
  3252. });
  3253. function getProp(elem, name) {
  3254. name = propFix[ name ] || name;
  3255. var hook = propHooks[ name ];
  3256. if (hook && hook.get) {
  3257. return hook.get(elem, name);
  3258. } else {
  3259. return elem[ name ];
  3260. }
  3261. }
  3262. S.mix(DOM, {
  3263. /**
  3264. * 自定义属性不推荐使用,使用 .data
  3265. * @param selector
  3266. * @param name
  3267. * @param [value]
  3268. */
  3269. prop:function (selector, name, value) {
  3270. var elems = DOM.query(selector);
  3271. // supports hash
  3272. if (S.isPlainObject(name)) {
  3273. for (var k in name) {
  3274. DOM.prop(elems, k, name[k]);
  3275. }
  3276. return;
  3277. }
  3278. // Try to normalize/fix the name
  3279. name = propFix[ name ] || name;
  3280. var hook = propHooks[ name ];
  3281. if (value !== undefined) {
  3282. for (var i = elems.length - 1; i >= 0; i--) {
  3283. var elem = elems[i];
  3284. if (hook && hook.set) {
  3285. hook.set(elem, value, name);
  3286. } else {
  3287. elem[ name ] = value;
  3288. }
  3289. }
  3290. } else {
  3291. if (elems.length) {
  3292. return getProp(elems[0], name);
  3293. }
  3294. }
  3295. },
  3296. /**
  3297. * 是否其中一个元素包含指定 property
  3298. * @param selector
  3299. * @param name
  3300. */
  3301. hasProp:function (selector, name) {
  3302. var elems = DOM.query(selector);
  3303. for (var i = 0; i < elems.length; i++) {
  3304. var el = elems[i];
  3305. if (getProp(el, name) !== undefined) {
  3306. return true;
  3307. }
  3308. }
  3309. return false;
  3310. },
  3311. /**
  3312. * 不推荐使用,使用 .data .removeData
  3313. * @param selector
  3314. * @param name
  3315. */
  3316. removeProp:function (selector, name) {
  3317. name = propFix[ name ] || name;
  3318. var elems = DOM.query(selector);
  3319. for (var i = elems.length - 1; i >= 0; i--) {
  3320. var el = elems[i];
  3321. try {
  3322. el[ name ] = undefined;
  3323. delete el[ name ];
  3324. } catch (e) {
  3325. // S.log("delete el property error : ");
  3326. //S.log(e);
  3327. }
  3328. }
  3329. },
  3330. /**
  3331. * Gets the value of an attribute for the first element in the set of matched elements or
  3332. * Sets an attribute for the set of matched elements.
  3333. */
  3334. attr:function (selector, name, val, pass) {
  3335. /*
  3336. Hazards From Caja Note:
  3337. - In IE[67], el.setAttribute doesn't work for attributes like
  3338. 'class' or 'for'. IE[67] expects you to set 'className' or
  3339. 'htmlFor'. Caja use setAttributeNode solves this problem.
  3340. - In IE[67], <input> elements can shadow attributes. If el is a
  3341. form that contains an <input> named x, then el.setAttribute(x, y)
  3342. will set x's value rather than setting el's attribute. Using
  3343. setAttributeNode solves this problem.
  3344. - In IE[67], the style attribute can only be modified by setting
  3345. el.style.cssText. Neither setAttribute nor setAttributeNode will
  3346. work. el.style.cssText isn't bullet-proof, since it can be
  3347. shadowed by <input> elements.
  3348. - In IE[67], you can never change the type of an <button> element.
  3349. setAttribute('type') silently fails, but setAttributeNode
  3350. throws an exception. caja : the silent failure. KISSY throws error.
  3351. - In IE[67], you can never change the type of an <input> element.
  3352. setAttribute('type') throws an exception. We want the exception.
  3353. - In IE[67], setAttribute is case-sensitive, unless you pass 0 as a
  3354. 3rd argument. setAttributeNode is case-insensitive.
  3355. - Trying to set an invalid name like ":" is supposed to throw an
  3356. error. In IE[678] and Opera 10, it fails without an error.
  3357. */
  3358. var els = DOM.query(selector);
  3359. // supports hash
  3360. if (S.isPlainObject(name)) {
  3361. pass = val;
  3362. for (var k in name) {
  3363. if (name.hasOwnProperty(k)) {
  3364. DOM.attr(els, k, name[k], pass);
  3365. }
  3366. }
  3367. return;
  3368. }
  3369. if (!(name = S.trim(name))) {
  3370. return;
  3371. }
  3372. // attr functions
  3373. if (pass && attrFn[name]) {
  3374. return DOM[name](selector, val);
  3375. }
  3376. // scrollLeft
  3377. name = name.toLowerCase();
  3378. if (pass && attrFn[name]) {
  3379. return DOM[name](selector, val);
  3380. }
  3381. // custom attrs
  3382. name = attrFix[name] || name;
  3383. var attrNormalizer,
  3384. el = els[0],
  3385. ret;
  3386. if (rboolean.test(name)) {
  3387. attrNormalizer = boolHook;
  3388. }
  3389. // only old ie?
  3390. else if (rinvalidChar.test(name)) {
  3391. attrNormalizer = attrNodeHook;
  3392. } else {
  3393. attrNormalizer = attrHooks[name];
  3394. }
  3395. if (val === undefined) {
  3396. if (el && el.nodeType === DOM.ELEMENT_NODE) {
  3397. // browsers index elements by id/name on forms, give priority to attributes.
  3398. if (nodeName(el, "form")) {
  3399. attrNormalizer = attrNodeHook;
  3400. }
  3401. if (attrNormalizer && attrNormalizer.get) {
  3402. return attrNormalizer.get(el, name);
  3403. }
  3404. ret = el.getAttribute(name);
  3405. // standard browser non-existing attribute return null
  3406. // ie<8 will return undefined , because it return property
  3407. // so norm to undefined
  3408. return ret === null ? undefined : ret;
  3409. }
  3410. } else {
  3411. for (var i = els.length - 1; i >= 0; i--) {
  3412. el = els[i];
  3413. if (el && el.nodeType === DOM.ELEMENT_NODE) {
  3414. if (nodeName(el, "form")) {
  3415. attrNormalizer = attrNodeHook;
  3416. }
  3417. if (attrNormalizer && attrNormalizer.set) {
  3418. attrNormalizer.set(el, val, name);
  3419. } else {
  3420. // convert the value to a string (all browsers do this but IE)
  3421. el.setAttribute(name, EMPTY + val);
  3422. }
  3423. }
  3424. }
  3425. }
  3426. },
  3427. /**
  3428. * Removes the attribute of the matched elements.
  3429. */
  3430. removeAttr:function (selector, name) {
  3431. name = name.toLowerCase();
  3432. name = attrFix[name] || name;
  3433. var els = DOM.query(selector), el, i;
  3434. for (i = els.length - 1; i >= 0; i--) {
  3435. el = els[i];
  3436. if (isElementNode(el)) {
  3437. var propName;
  3438. el.removeAttribute(name);
  3439. // Set corresponding property to false for boolean attributes
  3440. if (rboolean.test(name) && (propName = propFix[ name ] || name) in el) {
  3441. el[ propName ] = false;
  3442. }
  3443. }
  3444. }
  3445. },
  3446. /**
  3447. * 是否其中一个元素包含指定属性
  3448. */
  3449. hasAttr:oldIE ?
  3450. function (selector, name) {
  3451. name = name.toLowerCase();
  3452. var elems = DOM.query(selector);
  3453. // from ppk :http://www.quirksmode.org/dom/w3c_core.html
  3454. // IE5-7 doesn't return the value of a style attribute.
  3455. // var $attr = el.attributes[name];
  3456. for (var i = 0; i < elems.length; i++) {
  3457. var el = elems[i];
  3458. var $attr = el.getAttributeNode(name);
  3459. if ($attr && $attr.specified) {
  3460. return true;
  3461. }
  3462. }
  3463. return false;
  3464. }
  3465. :
  3466. function (selector, name) {
  3467. var elems = DOM.query(selector);
  3468. for (var i = 0; i < elems.length; i++) {
  3469. var el = elems[i];
  3470. //使用原生实现
  3471. if (el.hasAttribute(name)) {
  3472. return true;
  3473. }
  3474. }
  3475. return false;
  3476. },
  3477. /**
  3478. * Gets the current value of the first element in the set of matched or
  3479. * Sets the value of each element in the set of matched elements.
  3480. */
  3481. val:function (selector, value) {
  3482. var hook, ret;
  3483. //getter
  3484. if (value === undefined) {
  3485. var elem = DOM.get(selector);
  3486. if (elem) {
  3487. hook = valHooks[ elem.nodeName.toLowerCase() ] || valHooks[ elem.type ];
  3488. if (hook && "get" in hook && (ret = hook.get(elem, "value")) !== undefined) {
  3489. return ret;
  3490. }
  3491. ret = elem.value;
  3492. return typeof ret === "string" ?
  3493. // handle most common string cases
  3494. ret.replace(rreturn, "") :
  3495. // handle cases where value is null/undefined or number
  3496. ret == null ? "" : ret;
  3497. }
  3498. return;
  3499. }
  3500. var els = DOM.query(selector), i;
  3501. for (i = els.length - 1; i >= 0; i--) {
  3502. elem = els[i];
  3503. if (elem.nodeType !== 1) {
  3504. return;
  3505. }
  3506. var val = value;
  3507. // Treat null/undefined as ""; convert numbers to string
  3508. if (val == null) {
  3509. val = "";
  3510. } else if (typeof val === "number") {
  3511. val += "";
  3512. } else if (S.isArray(val)) {
  3513. val = S.map(val, function (value) {
  3514. return value == null ? "" : value + "";
  3515. });
  3516. }
  3517. hook = valHooks[ elem.nodeName.toLowerCase() ] || valHooks[ elem.type ];
  3518. // If set returns undefined, fall back to normal setting
  3519. if (!hook || !("set" in hook) || hook.set(elem, val, "value") === undefined) {
  3520. elem.value = val;
  3521. }
  3522. }
  3523. },
  3524. /**
  3525. * Gets the text context of the first element in the set of matched elements or
  3526. * Sets the text content of the matched elements.
  3527. */
  3528. text:function (selector, val) {
  3529. // getter
  3530. if (val === undefined) {
  3531. // supports css selector/Node/NodeList
  3532. var el = DOM.get(selector);
  3533. // only gets value on supported nodes
  3534. if (isElementNode(el)) {
  3535. return el[TEXT] || EMPTY;
  3536. }
  3537. else if (isTextNode(el)) {
  3538. return el.nodeValue;
  3539. }
  3540. return undefined;
  3541. }
  3542. // setter
  3543. else {
  3544. var els = DOM.query(selector), i;
  3545. for (i = els.length - 1; i >= 0; i--) {
  3546. el = els[i];
  3547. if (isElementNode(el)) {
  3548. el[TEXT] = val;
  3549. }
  3550. else if (isTextNode(el)) {
  3551. el.nodeValue = val;
  3552. }
  3553. }
  3554. }
  3555. }
  3556. });
  3557. return DOM;
  3558. }, {
  3559. requires:["./base", "ua"]
  3560. }
  3561. );
  3562. /**
  3563. * NOTES:
  3564. * 承玉:2011-06-03
  3565. * - 借鉴 jquery 1.6,理清 attribute 与 property
  3566. *
  3567. * 承玉:2011-01-28
  3568. * - 处理 tabindex,顺便重构
  3569. *
  3570. * 2010.03
  3571. * - 在 jquery/support.js 中,special attrs 里还有 maxlength, cellspacing,
  3572. * rowspan, colspan, useap, frameboder, 但测试发现,在 Grade-A 级浏览器中
  3573. * 并无兼容性问题。
  3574. * - 当 colspan/rowspan 属性值设置有误时,ie7- 会自动纠正,和 href 一样,需要传递
  3575. * 第 2 个参数来解决。jQuery 未考虑,存在兼容性 bug.
  3576. * - jQuery 考虑了未显式设定 tabindex 时引发的兼容问题,kissy 里忽略(太不常用了)
  3577. * - jquery/attributes.js: Safari mis-reports the default selected
  3578. * property of an option 在 Safari 4 中已修复。
  3579. *
  3580. */
  3581. /**
  3582. * @fileOverview dom
  3583. * @author yiminghe@gmail.com,lifesinger@gmail.com
  3584. */
  3585. KISSY.add('dom/base', function(S, UA, undefined) {
  3586. function nodeTypeIs(node, val) {
  3587. return node && node.nodeType === val;
  3588. }
  3589. var NODE_TYPE = {
  3590. /**
  3591. * enumeration of dom node type
  3592. * @type Number
  3593. */
  3594. ELEMENT_NODE : 1,
  3595. "ATTRIBUTE_NODE" : 2,
  3596. TEXT_NODE:3,
  3597. "CDATA_SECTION_NODE" : 4,
  3598. "ENTITY_REFERENCE_NODE": 5,
  3599. "ENTITY_NODE" : 6,
  3600. "PROCESSING_INSTRUCTION_NODE" :7,
  3601. COMMENT_NODE : 8,
  3602. DOCUMENT_NODE : 9,
  3603. "DOCUMENT_TYPE_NODE" : 10,
  3604. DOCUMENT_FRAGMENT_NODE : 11,
  3605. "NOTATION_NODE" : 12
  3606. };
  3607. var DOM = {
  3608. _isCustomDomain :function (win) {
  3609. win = win || window;
  3610. var domain = win.document.domain,
  3611. hostname = win.location.hostname;
  3612. return domain != hostname &&
  3613. domain != ( '[' + hostname + ']' ); // IPv6 IP support
  3614. },
  3615. _genEmptyIframeSrc:function(win) {
  3616. win = win || window;
  3617. if (UA['ie'] && DOM._isCustomDomain(win)) {
  3618. return 'javascript:void(function(){' + encodeURIComponent("" +
  3619. "document.open();" +
  3620. "document.domain='" +
  3621. win.document.domain
  3622. + "';" +
  3623. "document.close();") + "}())";
  3624. }
  3625. },
  3626. _NODE_TYPE:NODE_TYPE,
  3627. /**
  3628. * 是不是 element node
  3629. */
  3630. _isElementNode: function(elem) {
  3631. return nodeTypeIs(elem, DOM.ELEMENT_NODE);
  3632. },
  3633. /**
  3634. * elem 为 window 时,直接返回
  3635. * elem 为 document 时,返回关联的 window
  3636. * elem 为 undefined 时,返回当前 window
  3637. * 其它值,返回 false
  3638. */
  3639. _getWin: function(elem) {
  3640. return (elem && ('scrollTo' in elem) && elem['document']) ?
  3641. elem :
  3642. nodeTypeIs(elem, DOM.DOCUMENT_NODE) ?
  3643. elem.defaultView || elem.parentWindow :
  3644. (elem === undefined || elem === null) ?
  3645. window : false;
  3646. },
  3647. _nodeTypeIs: nodeTypeIs,
  3648. // Ref: http://lifesinger.github.com/lab/2010/nodelist.html
  3649. _isNodeList:function(o) {
  3650. // 注1:ie 下,有 window.item, typeof node.item 在 ie 不同版本下,返回值不同
  3651. // 注2:select 等元素也有 item, 要用 !node.nodeType 排除掉
  3652. // 注3:通过 namedItem 来判断不可靠
  3653. // 注4:getElementsByTagName 和 querySelectorAll 返回的集合不同
  3654. // 注5: 考虑 iframe.contentWindow
  3655. return o && !o.nodeType && o.item && !o.setTimeout;
  3656. },
  3657. _nodeName:function(e, name) {
  3658. return e && e.nodeName.toLowerCase() === name.toLowerCase();
  3659. }
  3660. };
  3661. S.mix(DOM, NODE_TYPE);
  3662. return DOM;
  3663. }, {
  3664. requires:['ua']
  3665. });
  3666. /**
  3667. * 2011-08
  3668. * - 添加键盘枚举值,方便依赖程序清晰
  3669. */
  3670. /**
  3671. * @fileOverview dom-class
  3672. * @author lifesinger@gmail.com
  3673. */
  3674. KISSY.add('dom/class', function (S, DOM, undefined) {
  3675. var SPACE = ' ',
  3676. REG_SPLIT = /[\.\s]\s*\.?/,
  3677. REG_CLASS = /[\n\t]/g;
  3678. function norm(elemClass) {
  3679. return (SPACE + elemClass + SPACE).replace(REG_CLASS, SPACE);
  3680. }
  3681. S.mix(DOM, {
  3682. /**
  3683. * Determine whether any of the matched elements are assigned the given class.
  3684. */
  3685. hasClass:function (selector, value) {
  3686. return batch(selector, value, function (elem, classNames, cl) {
  3687. var elemClass = elem.className;
  3688. if (elemClass) {
  3689. var className = norm(elemClass),
  3690. j = 0,
  3691. ret = true;
  3692. for (; j < cl; j++) {
  3693. if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
  3694. ret = false;
  3695. break;
  3696. }
  3697. }
  3698. if (ret) {
  3699. return true;
  3700. }
  3701. }
  3702. }, true);
  3703. },
  3704. /**
  3705. * Adds the specified class(es) to each of the set of matched elements.
  3706. */
  3707. addClass:function (selector, value) {
  3708. batch(selector, value, function (elem, classNames, cl) {
  3709. var elemClass = elem.className;
  3710. if (!elemClass) {
  3711. elem.className = value;
  3712. } else {
  3713. var className = norm(elemClass),
  3714. setClass = elemClass,
  3715. j = 0;
  3716. for (; j < cl; j++) {
  3717. if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
  3718. setClass += SPACE + classNames[j];
  3719. }
  3720. }
  3721. elem.className = S.trim(setClass);
  3722. }
  3723. }, undefined);
  3724. },
  3725. /**
  3726. * Remove a single class, multiple classes, or all classes from each element in the set of matched elements.
  3727. */
  3728. removeClass:function (selector, value) {
  3729. batch(selector, value, function (elem, classNames, cl) {
  3730. var elemClass = elem.className;
  3731. if (elemClass) {
  3732. if (!cl) {
  3733. elem.className = '';
  3734. } else {
  3735. var className = norm(elemClass),
  3736. j = 0,
  3737. needle;
  3738. for (; j < cl; j++) {
  3739. needle = SPACE + classNames[j] + SPACE;
  3740. // 一个 cls 有可能多次出现:'link link2 link link3 link'
  3741. while (className.indexOf(needle) >= 0) {
  3742. className = className.replace(needle, SPACE);
  3743. }
  3744. }
  3745. elem.className = S.trim(className);
  3746. }
  3747. }
  3748. }, undefined);
  3749. },
  3750. /**
  3751. * Replace a class with another class for matched elements.
  3752. * If no oldClassName is present, the newClassName is simply added.
  3753. */
  3754. replaceClass:function (selector, oldClassName, newClassName) {
  3755. DOM.removeClass(selector, oldClassName);
  3756. DOM.addClass(selector, newClassName);
  3757. },
  3758. /**
  3759. * Add or remove one or more classes from each element in the set of
  3760. * matched elements, depending on either the class's presence or the
  3761. * value of the switch argument.
  3762. * @param state {Boolean} optional boolean to indicate whether class
  3763. * should be added or removed regardless of current state.
  3764. */
  3765. toggleClass:function (selector, value, state) {
  3766. var isBool = S.isBoolean(state), has;
  3767. batch(selector, value, function (elem, classNames, cl) {
  3768. var j = 0, className;
  3769. for (; j < cl; j++) {
  3770. className = classNames[j];
  3771. has = isBool ? !state : DOM.hasClass(elem, className);
  3772. DOM[has ? 'removeClass' : 'addClass'](elem, className);
  3773. }
  3774. }, undefined);
  3775. }
  3776. });
  3777. function batch(selector, value, fn, resultIsBool) {
  3778. if (!(value = S.trim(value))) {
  3779. return resultIsBool ? false : undefined;
  3780. }
  3781. var elems = DOM.query(selector),
  3782. len = elems.length,
  3783. tmp = value.split(REG_SPLIT),
  3784. elem,
  3785. ret;
  3786. var classNames = [];
  3787. for (var i = 0; i < tmp.length; i++) {
  3788. var t = S.trim(tmp[i]);
  3789. if (t) {
  3790. classNames.push(t);
  3791. }
  3792. }
  3793. for (i = 0; i < len; i++) {
  3794. elem = elems[i];
  3795. if (DOM._isElementNode(elem)) {
  3796. ret = fn(elem, classNames, classNames.length);
  3797. if (ret !== undefined) {
  3798. return ret;
  3799. }
  3800. }
  3801. }
  3802. if (resultIsBool) {
  3803. return false;
  3804. }
  3805. return undefined;
  3806. }
  3807. return DOM;
  3808. }, {
  3809. requires:["dom/base"]
  3810. });
  3811. /**
  3812. * NOTES:
  3813. * - hasClass/addClass/removeClass 的逻辑和 jQuery 保持一致
  3814. * - toggleClass 不支持 value 为 undefined 的情形(jQuery 支持)
  3815. */
  3816. /**
  3817. * @fileOverview dom-create
  3818. * @author lifesinger@gmail.com,yiminghe@gmail.com
  3819. */
  3820. KISSY.add('dom/create', function (S, DOM, UA, undefined) {
  3821. var doc = document,
  3822. ie = UA['ie'],
  3823. nodeTypeIs = DOM._nodeTypeIs,
  3824. isElementNode = DOM._isElementNode,
  3825. isString = S.isString,
  3826. DIV = 'div',
  3827. PARENT_NODE = 'parentNode',
  3828. DEFAULT_DIV = doc.createElement(DIV),
  3829. rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
  3830. RE_TAG = /<([\w:]+)/,
  3831. rleadingWhitespace = /^\s+/,
  3832. lostLeadingWhitespace = ie && ie < 9,
  3833. rhtml = /<|&#?\w+;/,
  3834. RE_SIMPLE_TAG = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
  3835. // help compression
  3836. function getElementsByTagName(el, tag) {
  3837. return el.getElementsByTagName(tag);
  3838. }
  3839. function cleanData(els) {
  3840. var Event = S.require("event");
  3841. if (Event) {
  3842. Event.detach(els);
  3843. }
  3844. DOM.removeData(els);
  3845. }
  3846. S.mix(DOM, {
  3847. /**
  3848. * Creates a new HTMLElement using the provided html string.
  3849. */
  3850. create:function (html, props, ownerDoc, _trim/*internal*/) {
  3851. var ret = null;
  3852. if (!html) {
  3853. return ret;
  3854. }
  3855. if (html.nodeType) {
  3856. return DOM.clone(html);
  3857. }
  3858. if (!isString(html)) {
  3859. return ret;
  3860. }
  3861. if (_trim === undefined) {
  3862. _trim = true;
  3863. }
  3864. if (_trim) {
  3865. html = S.trim(html);
  3866. }
  3867. var creators = DOM._creators,
  3868. holder,
  3869. whitespaceMatch,
  3870. context = ownerDoc || doc,
  3871. m,
  3872. tag = DIV,
  3873. k,
  3874. nodes;
  3875. if (!rhtml.test(html)) {
  3876. ret = context.createTextNode(html);
  3877. }
  3878. // 简单 tag, 比如 DOM.create('<p>')
  3879. else if ((m = RE_SIMPLE_TAG.exec(html))) {
  3880. ret = context.createElement(m[1]);
  3881. }
  3882. // 复杂情况,比如 DOM.create('<img src="sprite.png" />')
  3883. else {
  3884. // Fix "XHTML"-style tags in all browsers
  3885. html = html.replace(rxhtmlTag, "<$1><" + "/$2>");
  3886. if ((m = RE_TAG.exec(html)) && (k = m[1])) {
  3887. tag = k.toLowerCase();
  3888. }
  3889. holder = (creators[tag] || creators[DIV])(html, context);
  3890. // ie 把前缀空白吃掉了
  3891. if (lostLeadingWhitespace && (whitespaceMatch = html.match(rleadingWhitespace))) {
  3892. holder.insertBefore(context.createTextNode(whitespaceMatch[0]), holder.firstChild);
  3893. }
  3894. nodes = holder.childNodes;
  3895. if (nodes.length === 1) {
  3896. // return single node, breaking parentNode ref from "fragment"
  3897. ret = nodes[0][PARENT_NODE].removeChild(nodes[0]);
  3898. }
  3899. else if (nodes.length) {
  3900. // return multiple nodes as a fragment
  3901. ret = nl2frag(nodes, context);
  3902. } else {
  3903. S.error(html + " : create node error");
  3904. }
  3905. }
  3906. return attachProps(ret, props);
  3907. },
  3908. _creators:{
  3909. div:function (html, ownerDoc) {
  3910. var frag = ownerDoc && ownerDoc != doc ? ownerDoc.createElement(DIV) : DEFAULT_DIV;
  3911. // html 为 <style></style> 时不行,必须有其他元素?
  3912. frag['innerHTML'] = "m<div>" + html + "<" + "/div>";
  3913. return frag.lastChild;
  3914. }
  3915. },
  3916. /**
  3917. * Gets/Sets the HTML contents of the HTMLElement.
  3918. * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false).
  3919. * @param {Function} callback (optional) For async script loading you can be notified when the update completes.
  3920. */
  3921. html:function (selector, val, loadScripts, callback) {
  3922. // supports css selector/Node/NodeList
  3923. var els = DOM.query(selector),
  3924. el = els[0];
  3925. if (!el) {
  3926. return
  3927. }
  3928. // getter
  3929. if (val === undefined) {
  3930. // only gets value on the first of element nodes
  3931. if (isElementNode(el)) {
  3932. return el['innerHTML'];
  3933. } else {
  3934. return null;
  3935. }
  3936. }
  3937. // setter
  3938. else {
  3939. var success = false, i, elem;
  3940. val += "";
  3941. // faster
  3942. if (!val.match(/<(?:script|style)/i) &&
  3943. (!lostLeadingWhitespace || !val.match(rleadingWhitespace)) &&
  3944. !creatorsMap[ (val.match(RE_TAG) || ["", ""])[1].toLowerCase() ]) {
  3945. try {
  3946. for (i = els.length - 1; i >= 0; i--) {
  3947. elem = els[i];
  3948. if (isElementNode(elem)) {
  3949. cleanData(getElementsByTagName(elem, "*"));
  3950. elem.innerHTML = val;
  3951. }
  3952. }
  3953. success = true;
  3954. } catch (e) {
  3955. // a <= "<a>"
  3956. // a.innerHTML='<p>1</p>';
  3957. }
  3958. }
  3959. if (!success) {
  3960. val = DOM.create(val, 0, el.ownerDocument, false);
  3961. for (i = els.length - 1; i >= 0; i--) {
  3962. elem = els[i];
  3963. if (isElementNode(elem)) {
  3964. DOM.empty(elem);
  3965. DOM.append(val, elem, loadScripts);
  3966. }
  3967. }
  3968. }
  3969. callback && callback();
  3970. }
  3971. },
  3972. /**
  3973. * Remove the set of matched elements from the DOM.
  3974. * 不要使用 innerHTML='' 来清除元素,可能会造成内存泄露,要使用 DOM.remove()
  3975. * @param selector 选择器或元素集合
  3976. * @param {Boolean} [keepData=false] 删除元素时是否保留其上的数据,用于离线操作,提高性能
  3977. */
  3978. remove:function (selector, keepData) {
  3979. var el, els = DOM.query(selector), i;
  3980. for (i = els.length - 1; i >= 0; i--) {
  3981. el = els[i];
  3982. if (!keepData && isElementNode(el)) {
  3983. // 清理数据
  3984. var elChildren = getElementsByTagName(el, "*");
  3985. cleanData(elChildren);
  3986. cleanData(el);
  3987. }
  3988. if (el.parentNode) {
  3989. el.parentNode.removeChild(el);
  3990. }
  3991. }
  3992. },
  3993. /**
  3994. * clone node across browsers for the first node in selector
  3995. * @param selector 选择器或单个元素
  3996. * @param {Boolean} withDataAndEvent 复制节点是否包括和源节点同样的数据和事件
  3997. * @param {Boolean} deepWithDataAndEvent 复制节点的子孙节点是否包括和源节点子孙节点同样的数据和事件
  3998. * @see https://developer.mozilla.org/En/DOM/Node.cloneNode
  3999. * @returns 复制后的节点
  4000. */
  4001. clone:function (selector, deep, withDataAndEvent, deepWithDataAndEvent) {
  4002. var elem = DOM.get(selector);
  4003. if (!elem) {
  4004. return null;
  4005. }
  4006. // TODO
  4007. // ie bug :
  4008. // 1. ie<9 <script>xx</script> => <script></script>
  4009. // 2. ie will execute external script
  4010. var clone = elem.cloneNode(deep);
  4011. if (isElementNode(elem) ||
  4012. nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  4013. // IE copies events bound via attachEvent when using cloneNode.
  4014. // Calling detachEvent on the clone will also remove the events
  4015. // from the original. In order to get around this, we use some
  4016. // proprietary methods to clear the events. Thanks to MooTools
  4017. // guys for this hotness.
  4018. if (isElementNode(elem)) {
  4019. fixAttributes(elem, clone);
  4020. }
  4021. if (deep) {
  4022. processAll(fixAttributes, elem, clone);
  4023. }
  4024. }
  4025. // runtime 获得事件模块
  4026. if (withDataAndEvent) {
  4027. cloneWidthDataAndEvent(elem, clone);
  4028. if (deep && deepWithDataAndEvent) {
  4029. processAll(cloneWidthDataAndEvent, elem, clone);
  4030. }
  4031. }
  4032. return clone;
  4033. },
  4034. empty:function (selector) {
  4035. var els = DOM.query(selector), el, i;
  4036. for (i = els.length - 1; i >= 0; i--) {
  4037. el = els[i];
  4038. DOM.remove(el.childNodes);
  4039. }
  4040. },
  4041. _nl2frag:nl2frag
  4042. });
  4043. function processAll(fn, elem, clone) {
  4044. if (nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  4045. var eCs = elem.childNodes,
  4046. cloneCs = clone.childNodes,
  4047. fIndex = 0;
  4048. while (eCs[fIndex]) {
  4049. if (cloneCs[fIndex]) {
  4050. processAll(fn, eCs[fIndex], cloneCs[fIndex]);
  4051. }
  4052. fIndex++;
  4053. }
  4054. } else if (isElementNode(elem)) {
  4055. var elemChildren = getElementsByTagName(elem, "*"),
  4056. cloneChildren = getElementsByTagName(clone, "*"),
  4057. cIndex = 0;
  4058. while (elemChildren[cIndex]) {
  4059. if (cloneChildren[cIndex]) {
  4060. fn(elemChildren[cIndex], cloneChildren[cIndex]);
  4061. }
  4062. cIndex++;
  4063. }
  4064. }
  4065. }
  4066. // 克隆除了事件的 data
  4067. function cloneWidthDataAndEvent(src, dest) {
  4068. var Event = S.require('event');
  4069. if (isElementNode(dest) && !DOM.hasData(src)) {
  4070. return;
  4071. }
  4072. var srcData = DOM.data(src);
  4073. // 浅克隆,data 也放在克隆节点上
  4074. for (var d in srcData) {
  4075. DOM.data(dest, d, srcData[d]);
  4076. }
  4077. // 事件要特殊点
  4078. if (Event) {
  4079. // _removeData 不需要?刚克隆出来本来就没
  4080. Event._removeData(dest);
  4081. Event._clone(src, dest);
  4082. }
  4083. }
  4084. // wierd ie cloneNode fix from jq
  4085. function fixAttributes(src, dest) {
  4086. // clearAttributes removes the attributes, which we don't want,
  4087. // but also removes the attachEvent events, which we *do* want
  4088. if (dest.clearAttributes) {
  4089. dest.clearAttributes();
  4090. }
  4091. // mergeAttributes, in contrast, only merges back on the
  4092. // original attributes, not the events
  4093. if (dest.mergeAttributes) {
  4094. dest.mergeAttributes(src);
  4095. }
  4096. var nodeName = dest.nodeName.toLowerCase(),
  4097. srcChilds = src.childNodes;
  4098. // IE6-8 fail to clone children inside object elements that use
  4099. // the proprietary classid attribute value (rather than the type
  4100. // attribute) to identify the type of content to display
  4101. if (nodeName === "object" && !dest.childNodes.length) {
  4102. for (var i = 0; i < srcChilds.length; i++) {
  4103. dest.appendChild(srcChilds[i].cloneNode(true));
  4104. }
  4105. // dest.outerHTML = src.outerHTML;
  4106. } else if (nodeName === "input" && (src.type === "checkbox" || src.type === "radio")) {
  4107. // IE6-8 fails to persist the checked state of a cloned checkbox
  4108. // or radio button. Worse, IE6-7 fail to give the cloned element
  4109. // a checked appearance if the defaultChecked value isn't also set
  4110. if (src.checked) {
  4111. dest['defaultChecked'] = dest.checked = src.checked;
  4112. }
  4113. // IE6-7 get confused and end up setting the value of a cloned
  4114. // checkbox/radio button to an empty string instead of "on"
  4115. if (dest.value !== src.value) {
  4116. dest.value = src.value;
  4117. }
  4118. // IE6-8 fails to return the selected option to the default selected
  4119. // state when cloning options
  4120. } else if (nodeName === "option") {
  4121. dest.selected = src.defaultSelected;
  4122. // IE6-8 fails to set the defaultValue to the correct value when
  4123. // cloning other types of input fields
  4124. } else if (nodeName === "input" || nodeName === "textarea") {
  4125. dest.defaultValue = src.defaultValue;
  4126. }
  4127. // Event data gets referenced instead of copied if the expando
  4128. // gets copied too
  4129. // 自定义 data 根据参数特殊处理,expando 只是个用于引用的属性
  4130. dest.removeAttribute(DOM.__EXPANDO);
  4131. }
  4132. // 添加成员到元素中
  4133. function attachProps(elem, props) {
  4134. if (S.isPlainObject(props)) {
  4135. if (isElementNode(elem)) {
  4136. DOM.attr(elem, props, true);
  4137. }
  4138. // document fragment
  4139. else if (nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  4140. DOM.attr(elem.childNodes, props, true);
  4141. }
  4142. }
  4143. return elem;
  4144. }
  4145. // 将 nodeList 转换为 fragment
  4146. function nl2frag(nodes, ownerDoc) {
  4147. var ret = null, i, len;
  4148. if (nodes
  4149. && (nodes.push || nodes.item)
  4150. && nodes[0]) {
  4151. ownerDoc = ownerDoc || nodes[0].ownerDocument;
  4152. ret = ownerDoc.createDocumentFragment();
  4153. nodes = S.makeArray(nodes);
  4154. for (i = 0, len = nodes.length; i < len; i++) {
  4155. ret.appendChild(nodes[i]);
  4156. }
  4157. }
  4158. else {
  4159. S.log('Unable to convert ' + nodes + ' to fragment.');
  4160. }
  4161. return ret;
  4162. }
  4163. // only for gecko and ie
  4164. // 2010-10-22: 发现 chrome 也与 gecko 的处理一致了
  4165. //if (ie || UA['gecko'] || UA['webkit']) {
  4166. // 定义 creators, 处理浏览器兼容
  4167. var creators = DOM._creators,
  4168. create = DOM.create,
  4169. TABLE_OPEN = '<table>',
  4170. TABLE_CLOSE = '<' + '/table>',
  4171. RE_TBODY = /(?:\/(?:thead|tfoot|caption|col|colgroup)>)+\s*<tbody/,
  4172. creatorsMap = {
  4173. option:'select',
  4174. optgroup:'select',
  4175. area:'map',
  4176. thead:'table',
  4177. td:'tr',
  4178. th:'tr',
  4179. tr:'tbody',
  4180. tbody:'table',
  4181. tfoot:'table',
  4182. caption:'table',
  4183. colgroup:'table',
  4184. col:'colgroup',
  4185. legend:'fieldset' // ie 支持,但 gecko 不支持
  4186. };
  4187. for (var p in creatorsMap) {
  4188. (function (tag) {
  4189. creators[p] = function (html, ownerDoc) {
  4190. return create('<' + tag + '>' + html + '<' + '/' + tag + '>', null, ownerDoc);
  4191. }
  4192. })(creatorsMap[p]);
  4193. }
  4194. // IE7- adds TBODY when creating thead/tfoot/caption/col/colgroup elements
  4195. if (ie < 8) {
  4196. creators.tbody = function (html, ownerDoc) {
  4197. var frag = create(TABLE_OPEN + html + TABLE_CLOSE, null, ownerDoc),
  4198. tbody = frag.children['tags']('tbody')[0];
  4199. if (frag.children.length > 1 && tbody && !RE_TBODY.test(html)) {
  4200. tbody[PARENT_NODE].removeChild(tbody); // strip extraneous tbody
  4201. }
  4202. return frag;
  4203. };
  4204. }
  4205. // fix table elements
  4206. S.mix(creators, {
  4207. thead:creators.tbody,
  4208. tfoot:creators.tbody,
  4209. caption:creators.tbody,
  4210. colgroup:creators.tbody
  4211. });
  4212. //}
  4213. return DOM;
  4214. },
  4215. {
  4216. requires:["./base", "ua"]
  4217. });
  4218. /**
  4219. * 2011-10-13
  4220. * empty , html refactor
  4221. *
  4222. * 2011-08-22
  4223. * clone 实现,参考 jq
  4224. *
  4225. * 2011-08
  4226. * remove 需要对子孙节点以及自身清除事件以及自定义 data
  4227. * create 修改,支持 <style></style> ie 下直接创建
  4228. * TODO: jquery clone ,clean 实现
  4229. *
  4230. * TODO:
  4231. * - 研究 jQuery 的 buildFragment 和 clean
  4232. * - 增加 cache, 完善 test cases
  4233. * - 支持更多 props
  4234. * - remove 时,是否需要移除事件,以避免内存泄漏?需要详细的测试。
  4235. */
  4236. /**
  4237. * @fileOverview dom-data
  4238. * @author lifesinger@gmail.com,yiminghe@gmail.com
  4239. */
  4240. KISSY.add('dom/data', function (S, DOM, undefined) {
  4241. var win = window,
  4242. EXPANDO = '_ks_data_' + S.now(), // 让每一份 kissy 的 expando 都不同
  4243. dataCache = { }, // 存储 node 节点的 data
  4244. winDataCache = { }; // 避免污染全局
  4245. // The following elements throw uncatchable exceptions if you
  4246. // attempt to add expando properties to them.
  4247. var noData = {
  4248. };
  4249. noData['applet'] = 1;
  4250. noData['object'] = 1;
  4251. noData['embed'] = 1;
  4252. var commonOps = {
  4253. hasData:function (cache, name) {
  4254. if (cache) {
  4255. if (name !== undefined) {
  4256. if (name in cache) {
  4257. return true;
  4258. }
  4259. } else if (!S.isEmptyObject(cache)) {
  4260. return true;
  4261. }
  4262. }
  4263. return false;
  4264. }
  4265. };
  4266. var objectOps = {
  4267. hasData:function (ob, name) {
  4268. // 只判断当前窗口,iframe 窗口内数据直接放入全局变量
  4269. if (ob == win) {
  4270. return objectOps.hasData(winDataCache, name);
  4271. }
  4272. // 直接建立在对象内
  4273. var thisCache = ob[EXPANDO];
  4274. return commonOps.hasData(thisCache, name);
  4275. },
  4276. data:function (ob, name, value) {
  4277. if (ob == win) {
  4278. return objectOps.data(winDataCache, name, value);
  4279. }
  4280. var cache = ob[EXPANDO];
  4281. if (value !== undefined) {
  4282. cache = ob[EXPANDO] = ob[EXPANDO] || {};
  4283. cache[name] = value;
  4284. } else {
  4285. if (name !== undefined) {
  4286. return cache && cache[name];
  4287. } else {
  4288. cache = ob[EXPANDO] = ob[EXPANDO] || {};
  4289. return cache;
  4290. }
  4291. }
  4292. },
  4293. removeData:function (ob, name) {
  4294. if (ob == win) {
  4295. return objectOps.removeData(winDataCache, name);
  4296. }
  4297. var cache = ob[EXPANDO];
  4298. if (name !== undefined) {
  4299. delete cache[name];
  4300. if (S.isEmptyObject(cache)) {
  4301. objectOps.removeData(ob);
  4302. }
  4303. } else {
  4304. try {
  4305. // ob maybe window in iframe
  4306. // ie will throw error
  4307. delete ob[EXPANDO];
  4308. } catch (e) {
  4309. ob[EXPANDO] = undefined;
  4310. }
  4311. }
  4312. }
  4313. };
  4314. var domOps = {
  4315. hasData:function (elem, name) {
  4316. var key = elem[EXPANDO];
  4317. if (!key) {
  4318. return false;
  4319. }
  4320. var thisCache = dataCache[key];
  4321. return commonOps.hasData(thisCache, name);
  4322. },
  4323. data:function (elem, name, value) {
  4324. if (noData[elem.nodeName.toLowerCase()]) {
  4325. return undefined;
  4326. }
  4327. var key = elem[EXPANDO], cache;
  4328. if (!key) {
  4329. // 根本不用附加属性
  4330. if (name !== undefined &&
  4331. value === undefined) {
  4332. return undefined;
  4333. }
  4334. // 节点上关联键值也可以
  4335. key = elem[EXPANDO] = S.guid();
  4336. }
  4337. cache = dataCache[key];
  4338. if (value !== undefined) {
  4339. // 需要新建
  4340. cache = dataCache[key] = dataCache[key] || {};
  4341. cache[name] = value;
  4342. } else {
  4343. if (name !== undefined) {
  4344. return cache && cache[name];
  4345. } else {
  4346. // 需要新建
  4347. cache = dataCache[key] = dataCache[key] || {};
  4348. return cache;
  4349. }
  4350. }
  4351. },
  4352. removeData:function (elem, name) {
  4353. var key = elem[EXPANDO], cache;
  4354. if (!key) {
  4355. return;
  4356. }
  4357. cache = dataCache[key];
  4358. if (name !== undefined) {
  4359. delete cache[name];
  4360. if (S.isEmptyObject(cache)) {
  4361. domOps.removeData(elem);
  4362. }
  4363. } else {
  4364. delete dataCache[key];
  4365. try {
  4366. delete elem[EXPANDO];
  4367. } catch (e) {
  4368. elem[EXPANDO] = undefined;
  4369. //S.log("delete expando error : ");
  4370. //S.log(e);
  4371. }
  4372. if (elem.removeAttribute) {
  4373. elem.removeAttribute(EXPANDO);
  4374. }
  4375. }
  4376. }
  4377. };
  4378. S.mix(DOM,
  4379. /**
  4380. * @lends DOM
  4381. */
  4382. {
  4383. __EXPANDO:EXPANDO,
  4384. /**
  4385. * whether any node has data
  4386. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4387. * @param {String} [name] 数据键名
  4388. * @returns {boolean} 节点是否有关联数据键名的值
  4389. */
  4390. hasData:function (selector, name) {
  4391. var ret = false, elems = DOM.query(selector);
  4392. for (var i = 0; i < elems.length; i++) {
  4393. var elem = elems[i];
  4394. if (elem.nodeType) {
  4395. ret = domOps.hasData(elem, name);
  4396. } else {
  4397. ret = objectOps.hasData(elem, name);
  4398. }
  4399. if (ret) {
  4400. return ret;
  4401. }
  4402. }
  4403. return ret;
  4404. },
  4405. /**
  4406. * Store arbitrary data associated with the matched elements.
  4407. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4408. * @param {String} [name] 数据键名
  4409. * @param {String} [data] 数据键值
  4410. * @returns 当不设置 data,设置 name 那么返回: 节点是否有关联数据键名的值
  4411. * 当不设置 data, name 那么返回: 节点的存储空间对象
  4412. * 当设置 data, name 那么进行设置操作,返回 undefined
  4413. */
  4414. data:function (selector, name, data) {
  4415. var elems = DOM.query(selector), elem = elems[0];
  4416. // supports hash
  4417. if (S.isPlainObject(name)) {
  4418. for (var k in name) {
  4419. DOM.data(elems, k, name[k]);
  4420. }
  4421. return undefined;
  4422. }
  4423. // getter
  4424. if (data === undefined) {
  4425. if (elem) {
  4426. if (elem.nodeType) {
  4427. return domOps.data(elem, name, data);
  4428. } else {
  4429. return objectOps.data(elem, name, data);
  4430. }
  4431. }
  4432. }
  4433. // setter
  4434. else {
  4435. for (var i = elems.length - 1; i >= 0; i--) {
  4436. elem = elems[i];
  4437. if (elem.nodeType) {
  4438. domOps.data(elem, name, data);
  4439. } else {
  4440. objectOps.data(elem, name, data);
  4441. }
  4442. }
  4443. }
  4444. return undefined;
  4445. },
  4446. /**
  4447. * Remove a previously-stored piece of data.
  4448. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4449. * @param {String} [name] 数据键名,不设置时删除关联节点的所有键值对
  4450. */
  4451. removeData:function (selector, name) {
  4452. var els = DOM.query(selector), elem, i;
  4453. for (i = els.length - 1; i >= 0; i--) {
  4454. elem = els[i];
  4455. if (elem.nodeType) {
  4456. domOps.removeData(elem, name);
  4457. } else {
  4458. objectOps.removeData(elem, name);
  4459. }
  4460. }
  4461. }
  4462. });
  4463. return DOM;
  4464. }, {
  4465. requires:["./base"]
  4466. });
  4467. /**
  4468. * 承玉:2011-05-31
  4469. * - 分层 ,节点和普通对象分开处理
  4470. **//**
  4471. * @fileOverview dom
  4472. */
  4473. KISSY.add("dom", function (S, DOM) {
  4474. /**
  4475. * @namespace
  4476. * @name DOM
  4477. */
  4478. return DOM;
  4479. }, {
  4480. requires:["dom/attr",
  4481. "dom/class",
  4482. "dom/create",
  4483. "dom/data",
  4484. "dom/insertion",
  4485. "dom/offset",
  4486. "dom/style",
  4487. "dom/selector",
  4488. "dom/style-ie",
  4489. "dom/traversal"]
  4490. });/**
  4491. * @fileOverview dom-insertion
  4492. * @author yiminghe@gmail.com,lifesinger@gmail.com
  4493. */
  4494. KISSY.add('dom/insertion', function (S, UA, DOM) {
  4495. var PARENT_NODE = 'parentNode',
  4496. rformEls = /^(?:button|input|object|select|textarea)$/i,
  4497. nodeName = DOM._nodeName,
  4498. makeArray = S.makeArray,
  4499. splice = [].splice,
  4500. _isElementNode = DOM._isElementNode,
  4501. NEXT_SIBLING = 'nextSibling';
  4502. /**
  4503. ie 6,7 lose checked status when append to dom
  4504. var c=S.all("<input />");
  4505. c.attr("type","radio");
  4506. c.attr("checked",true);
  4507. S.all("#t").append(c);
  4508. alert(c[0].checked);
  4509. */
  4510. function fixChecked(ret) {
  4511. for (var i = 0; i < ret.length; i++) {
  4512. var el = ret[i];
  4513. if (el.nodeType == DOM.DOCUMENT_FRAGMENT_NODE) {
  4514. fixChecked(el.childNodes);
  4515. } else if (nodeName(el, "input")) {
  4516. fixCheckedInternal(el);
  4517. } else if (_isElementNode(el)) {
  4518. var cs = el.getElementsByTagName("input");
  4519. for (var j = 0; j < cs.length; j++) {
  4520. fixChecked(cs[j]);
  4521. }
  4522. }
  4523. }
  4524. }
  4525. function fixCheckedInternal(el) {
  4526. if (el.type === "checkbox" || el.type === "radio") {
  4527. // after insert , in ie6/7 checked is decided by defaultChecked !
  4528. el.defaultChecked = el.checked;
  4529. }
  4530. }
  4531. var rscriptType = /\/(java|ecma)script/i;
  4532. function isJs(el) {
  4533. return !el.type || rscriptType.test(el.type);
  4534. }
  4535. // extract script nodes and execute alone later
  4536. function filterScripts(nodes, scripts) {
  4537. var ret = [], i, el, nodeName;
  4538. for (i = 0; nodes[i]; i++) {
  4539. el = nodes[i];
  4540. nodeName = el.nodeName.toLowerCase();
  4541. if (el.nodeType == DOM.DOCUMENT_FRAGMENT_NODE) {
  4542. ret.push.apply(ret, filterScripts(makeArray(el.childNodes), scripts));
  4543. } else if (nodeName === "script" && isJs(el)) {
  4544. // remove script to make sure ie9 does not invoke when append
  4545. if (el.parentNode) {
  4546. el.parentNode.removeChild(el)
  4547. }
  4548. if (scripts) {
  4549. scripts.push(el);
  4550. }
  4551. } else {
  4552. if (_isElementNode(el) &&
  4553. // ie checkbox getElementsByTagName 后造成 checked 丢失
  4554. !rformEls.test(nodeName)) {
  4555. var tmp = [],
  4556. s,
  4557. j,
  4558. ss = el.getElementsByTagName("script");
  4559. for (j = 0; j < ss.length; j++) {
  4560. s = ss[j];
  4561. if (isJs(s)) {
  4562. tmp.push(s);
  4563. }
  4564. }
  4565. splice.apply(nodes, [i + 1, 0].concat(tmp));
  4566. }
  4567. ret.push(el);
  4568. }
  4569. }
  4570. return ret;
  4571. }
  4572. // execute script
  4573. function evalScript(el) {
  4574. if (el.src) {
  4575. S.getScript(el.src);
  4576. } else {
  4577. var code = S.trim(el.text || el.textContent || el.innerHTML || "");
  4578. if (code) {
  4579. S.globalEval(code);
  4580. }
  4581. }
  4582. }
  4583. // fragment is easier than nodelist
  4584. function insertion(newNodes, refNodes, fn, scripts) {
  4585. newNodes = DOM.query(newNodes);
  4586. if (scripts) {
  4587. scripts = [];
  4588. }
  4589. // filter script nodes ,process script separately if needed
  4590. newNodes = filterScripts(newNodes, scripts);
  4591. // Resets defaultChecked for any radios and checkboxes
  4592. // about to be appended to the DOM in IE 6/7
  4593. if (UA['ie'] < 8) {
  4594. fixChecked(newNodes);
  4595. }
  4596. refNodes = DOM.query(refNodes);
  4597. var newNodesLength = newNodes.length,
  4598. refNodesLength = refNodes.length;
  4599. if ((!newNodesLength &&
  4600. (!scripts || !scripts.length)) ||
  4601. !refNodesLength) {
  4602. return;
  4603. }
  4604. // fragment 插入速度快点
  4605. // 而且能够一个操作达到批量插入
  4606. // refer: http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3
  4607. var newNode = DOM._nl2frag(newNodes),
  4608. clonedNode;
  4609. //fragment 一旦插入里面就空了,先复制下
  4610. if (refNodesLength > 1) {
  4611. clonedNode = DOM.clone(newNode, true);
  4612. refNodes = S.makeArray(refNodes)
  4613. }
  4614. for (var i = 0; i < refNodesLength; i++) {
  4615. var refNode = refNodes[i];
  4616. if (newNodesLength) {
  4617. //refNodes 超过一个,clone
  4618. var node = i > 0 ? DOM.clone(clonedNode, true) : newNode;
  4619. fn(node, refNode);
  4620. }
  4621. if (scripts && scripts.length) {
  4622. S.each(scripts, evalScript);
  4623. }
  4624. }
  4625. }
  4626. // loadScripts default to false to prevent xss
  4627. S.mix(DOM,
  4628. /**
  4629. * @lends DOM
  4630. */
  4631. {
  4632. /**
  4633. * Inserts the new node as the previous sibling of the reference node.
  4634. */
  4635. insertBefore:function (newNodes, refNodes, loadScripts) {
  4636. insertion(newNodes, refNodes, function (newNode, refNode) {
  4637. if (refNode[PARENT_NODE]) {
  4638. refNode[PARENT_NODE].insertBefore(newNode, refNode);
  4639. }
  4640. }, loadScripts);
  4641. },
  4642. /**
  4643. * Inserts the new node as the next sibling of the reference node.
  4644. */
  4645. insertAfter:function (newNodes, refNodes, loadScripts) {
  4646. insertion(newNodes, refNodes, function (newNode, refNode) {
  4647. if (refNode[PARENT_NODE]) {
  4648. refNode[PARENT_NODE].insertBefore(newNode, refNode[NEXT_SIBLING]);
  4649. }
  4650. }, loadScripts);
  4651. },
  4652. /**
  4653. * Inserts the new node as the last child.
  4654. */
  4655. appendTo:function (newNodes, parents, loadScripts) {
  4656. insertion(newNodes, parents, function (newNode, parent) {
  4657. parent.appendChild(newNode);
  4658. }, loadScripts);
  4659. },
  4660. /**
  4661. * Inserts the new node as the first child.
  4662. */
  4663. prependTo:function (newNodes, parents, loadScripts) {
  4664. insertion(newNodes, parents, function (newNode, parent) {
  4665. parent.insertBefore(newNode, parent.firstChild);
  4666. }, loadScripts);
  4667. }
  4668. });
  4669. var alias = {
  4670. "prepend":"prependTo",
  4671. "append":"appendTo",
  4672. "before":"insertBefore",
  4673. "after":"insertAfter"
  4674. };
  4675. for (var a in alias) {
  4676. DOM[a] = DOM[alias[a]];
  4677. }
  4678. return DOM;
  4679. }, {
  4680. requires:["ua", "./create"]
  4681. });
  4682. /**
  4683. * 2011-05-25
  4684. * - 承玉:参考 jquery 处理多对多的情形 :http://api.jquery.com/append/
  4685. * DOM.append(".multi1",".multi2");
  4686. *
  4687. */
  4688. /**
  4689. * @fileOverview dom-offset
  4690. * @author lifesinger@gmail.com,yiminghe@gmail.com
  4691. */
  4692. KISSY.add('dom/offset', function (S, DOM, UA, undefined) {
  4693. var win = window,
  4694. doc = document,
  4695. isIE = UA['ie'],
  4696. docElem = doc.documentElement,
  4697. isElementNode = DOM._isElementNode,
  4698. nodeTypeIs = DOM._nodeTypeIs,
  4699. getWin = DOM._getWin,
  4700. CSS1Compat = "CSS1Compat",
  4701. compatMode = "compatMode",
  4702. isStrict = doc[compatMode] === CSS1Compat,
  4703. MAX = Math.max,
  4704. PARSEINT = parseInt,
  4705. POSITION = 'position',
  4706. RELATIVE = 'relative',
  4707. DOCUMENT = 'document',
  4708. BODY = 'body',
  4709. DOC_ELEMENT = 'documentElement',
  4710. OWNER_DOCUMENT = 'ownerDocument',
  4711. VIEWPORT = 'viewport',
  4712. SCROLL = 'scroll',
  4713. CLIENT = 'client',
  4714. LEFT = 'left',
  4715. TOP = 'top',
  4716. isNumber = S.isNumber,
  4717. SCROLL_LEFT = SCROLL + 'Left',
  4718. SCROLL_TOP = SCROLL + 'Top',
  4719. GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect';
  4720. S.mix(DOM, {
  4721. /**
  4722. * Gets the current coordinates of the element, relative to the document.
  4723. * @param relativeWin The window to measure relative to. If relativeWin
  4724. * is not in the ancestor frame chain of the element, we measure relative to
  4725. * the top-most window.
  4726. */
  4727. offset:function (selector, val, relativeWin) {
  4728. // getter
  4729. if (val === undefined) {
  4730. var elem = DOM.get(selector), ret;
  4731. if (elem) {
  4732. ret = getOffset(elem, relativeWin);
  4733. }
  4734. return ret;
  4735. }
  4736. // setter
  4737. var els = DOM.query(selector), i;
  4738. for (i = els.length - 1; i >= 0; i--) {
  4739. elem = els[i];
  4740. setOffset(elem, val);
  4741. }
  4742. },
  4743. /**
  4744. * Makes elem visible in the container
  4745. * @param elem
  4746. * @param container
  4747. * @param top
  4748. * @param hscroll
  4749. * @param {Boolean} auto whether adjust element automatically
  4750. * (it only scrollIntoView when element is out of view)
  4751. * @see http://www.w3.org/TR/2009/WD-html5-20090423/editing.html#scrollIntoView
  4752. * http://www.sencha.com/deploy/dev/docs/source/Element.scroll-more.html#scrollIntoView
  4753. * http://yiminghe.javaeye.com/blog/390732
  4754. */
  4755. scrollIntoView:function (elem, container, top, hscroll, auto) {
  4756. if (!(elem = DOM.get(elem))) {
  4757. return;
  4758. }
  4759. if (container) {
  4760. container = DOM.get(container);
  4761. }
  4762. if (!container) {
  4763. container = elem.ownerDocument;
  4764. }
  4765. if (auto !== true) {
  4766. hscroll = hscroll === undefined ? true : !!hscroll;
  4767. top = top === undefined ? true : !!top;
  4768. }
  4769. // document 归一化到 window
  4770. if (nodeTypeIs(container, DOM.DOCUMENT_NODE)) {
  4771. container = getWin(container);
  4772. }
  4773. var isWin = !!getWin(container),
  4774. elemOffset = DOM.offset(elem),
  4775. eh = DOM.outerHeight(elem),
  4776. ew = DOM.outerWidth(elem),
  4777. containerOffset,
  4778. ch,
  4779. cw,
  4780. containerScroll,
  4781. diffTop,
  4782. diffBottom,
  4783. win,
  4784. winScroll,
  4785. ww,
  4786. wh;
  4787. if (isWin) {
  4788. win = container;
  4789. wh = DOM.height(win);
  4790. ww = DOM.width(win);
  4791. winScroll = {
  4792. left:DOM.scrollLeft(win),
  4793. top:DOM.scrollTop(win)
  4794. };
  4795. // elem 相对 container 可视视窗的距离
  4796. diffTop = {
  4797. left:elemOffset[LEFT] - winScroll[LEFT],
  4798. top:elemOffset[TOP] - winScroll[TOP]
  4799. };
  4800. diffBottom = {
  4801. left:elemOffset[LEFT] + ew - (winScroll[LEFT] + ww),
  4802. top:elemOffset[TOP] + eh - (winScroll[TOP] + wh)
  4803. };
  4804. containerScroll = winScroll;
  4805. }
  4806. else {
  4807. containerOffset = DOM.offset(container);
  4808. ch = container.clientHeight;
  4809. cw = container.clientWidth;
  4810. containerScroll = {
  4811. left:DOM.scrollLeft(container),
  4812. top:DOM.scrollTop(container)
  4813. };
  4814. // elem 相对 container 可视视窗的距离
  4815. // 注意边框 , offset 是边框到根节点
  4816. diffTop = {
  4817. left:elemOffset[LEFT] - containerOffset[LEFT] -
  4818. (PARSEINT(DOM.css(container, 'borderLeftWidth')) || 0),
  4819. top:elemOffset[TOP] - containerOffset[TOP] -
  4820. (PARSEINT(DOM.css(container, 'borderTopWidth')) || 0)
  4821. };
  4822. diffBottom = {
  4823. left:elemOffset[LEFT] + ew -
  4824. (containerOffset[LEFT] + cw +
  4825. (PARSEINT(DOM.css(container, 'borderRightWidth')) || 0)),
  4826. top:elemOffset[TOP] + eh -
  4827. (containerOffset[TOP] + ch +
  4828. (PARSEINT(DOM.css(container, 'borderBottomWidth')) || 0))
  4829. };
  4830. }
  4831. if (diffTop.top < 0 || diffBottom.top > 0) {
  4832. // 强制向上
  4833. if (top === true) {
  4834. DOM.scrollTop(container, containerScroll.top + diffTop.top);
  4835. } else if (top === false) {
  4836. DOM.scrollTop(container, containerScroll.top + diffBottom.top);
  4837. } else {
  4838. // 自动调整
  4839. if (diffTop.top < 0) {
  4840. DOM.scrollTop(container, containerScroll.top + diffTop.top);
  4841. } else {
  4842. DOM.scrollTop(container, containerScroll.top + diffBottom.top);
  4843. }
  4844. }
  4845. }
  4846. if (hscroll) {
  4847. if (diffTop.left < 0 || diffBottom.left > 0) {
  4848. // 强制向上
  4849. if (top === true) {
  4850. DOM.scrollLeft(container, containerScroll.left + diffTop.left);
  4851. } else if (top === false) {
  4852. DOM.scrollLeft(container, containerScroll.left + diffBottom.left);
  4853. } else {
  4854. // 自动调整
  4855. if (diffTop.left < 0) {
  4856. DOM.scrollLeft(container, containerScroll.left + diffTop.left);
  4857. } else {
  4858. DOM.scrollLeft(container, containerScroll.left + diffBottom.left);
  4859. }
  4860. }
  4861. }
  4862. }
  4863. },
  4864. /**
  4865. * for idea autocomplete
  4866. */
  4867. docWidth:0,
  4868. docHeight:0,
  4869. viewportHeight:0,
  4870. viewportWidth:0
  4871. });
  4872. // http://old.jr.pl/www.quirksmode.org/viewport/compatibility.html
  4873. // http://www.quirksmode.org/dom/w3c_cssom.html
  4874. // add ScrollLeft/ScrollTop getter/setter methods
  4875. S.each(['Left', 'Top'], function (name, i) {
  4876. var method = SCROLL + name;
  4877. DOM[method] = function (elem, v) {
  4878. if (isNumber(elem)) {
  4879. return arguments.callee(win, elem);
  4880. }
  4881. elem = DOM.get(elem);
  4882. var ret,
  4883. w = getWin(elem),
  4884. d;
  4885. if (w) {
  4886. if (v !== undefined) {
  4887. v = parseFloat(v);
  4888. // 注意多 windw 情况,不能简单取 win
  4889. var left = name == "Left" ? v : DOM.scrollLeft(w),
  4890. top = name == "Top" ? v : DOM.scrollTop(w);
  4891. w['scrollTo'](left, top);
  4892. } else {
  4893. //标准
  4894. //chrome == body.scrollTop
  4895. //firefox/ie9 == documentElement.scrollTop
  4896. ret = w[ 'page' + (i ? 'Y' : 'X') + 'Offset'];
  4897. if (!isNumber(ret)) {
  4898. d = w[DOCUMENT];
  4899. //ie6,7,8 standard mode
  4900. ret = d[DOC_ELEMENT][method];
  4901. if (!isNumber(ret)) {
  4902. //quirks mode
  4903. ret = d[BODY][method];
  4904. }
  4905. }
  4906. }
  4907. } else if (isElementNode(elem)) {
  4908. if (v !== undefined) {
  4909. elem[method] = parseFloat(v)
  4910. } else {
  4911. ret = elem[method];
  4912. }
  4913. }
  4914. return ret;
  4915. }
  4916. });
  4917. // add docWidth/Height, viewportWidth/Height getter methods
  4918. S.each(['Width', 'Height'], function (name) {
  4919. DOM['doc' + name] = function (refWin) {
  4920. refWin = DOM.get(refWin);
  4921. var w = getWin(refWin),
  4922. d = w[DOCUMENT];
  4923. return MAX(
  4924. //firefox chrome documentElement.scrollHeight< body.scrollHeight
  4925. //ie standard mode : documentElement.scrollHeight> body.scrollHeight
  4926. d[DOC_ELEMENT][SCROLL + name],
  4927. //quirks : documentElement.scrollHeight 最大等于可视窗口多一点?
  4928. d[BODY][SCROLL + name],
  4929. DOM[VIEWPORT + name](d));
  4930. };
  4931. DOM[VIEWPORT + name] = function (refWin) {
  4932. refWin = DOM.get(refWin);
  4933. var prop = CLIENT + name,
  4934. win = getWin(refWin),
  4935. doc = win[DOCUMENT],
  4936. body = doc[BODY],
  4937. documentElement = doc[DOC_ELEMENT],
  4938. documentElementProp = documentElement[prop];
  4939. // 标准模式取 documentElement
  4940. // backcompat 取 body
  4941. return doc[compatMode] === CSS1Compat
  4942. && documentElementProp ||
  4943. body && body[ prop ] || documentElementProp;
  4944. // return (prop in w) ?
  4945. // // 标准 = documentElement.clientHeight
  4946. // w[prop] :
  4947. // // ie 标准 documentElement.clientHeight , 在 documentElement.clientHeight 上滚动?
  4948. // // ie quirks body.clientHeight: 在 body 上?
  4949. // (isStrict ? d[DOC_ELEMENT][CLIENT + name] : d[BODY][CLIENT + name]);
  4950. }
  4951. });
  4952. function getClientPosition(elem) {
  4953. var box, x = 0, y = 0,
  4954. body = doc.body,
  4955. w = getWin(elem[OWNER_DOCUMENT]);
  4956. // 根据 GBS 最新数据,A-Grade Browsers 都已支持 getBoundingClientRect 方法,不用再考虑传统的实现方式
  4957. if (elem[GET_BOUNDING_CLIENT_RECT]) {
  4958. box = elem[GET_BOUNDING_CLIENT_RECT]();
  4959. // 注:jQuery 还考虑减去 docElem.clientLeft/clientTop
  4960. // 但测试发现,这样反而会导致当 html 和 body 有边距/边框样式时,获取的值不正确
  4961. // 此外,ie6 会忽略 html 的 margin 值,幸运地是没有谁会去设置 html 的 margin
  4962. x = box[LEFT];
  4963. y = box[TOP];
  4964. // ie 下应该减去窗口的边框吧,毕竟默认 absolute 都是相对窗口定位的
  4965. // 窗口边框标准是设 documentElement ,quirks 时设置 body
  4966. // 最好禁止在 body 和 html 上边框 ,但 ie < 9 html 默认有 2px ,减去
  4967. // 但是非 ie 不可能设置窗口边框,body html 也不是窗口 ,ie 可以通过 html,body 设置
  4968. // 标准 ie 下 docElem.clientTop 就是 border-top
  4969. // ie7 html 即窗口边框改变不了。永远为 2
  4970. // 但标准 firefox/chrome/ie9 下 docElem.clientTop 是窗口边框,即使设了 border-top 也为 0
  4971. var clientTop = isIE && doc['documentMode'] != 9
  4972. && (isStrict ? docElem.clientTop : body.clientTop)
  4973. || 0,
  4974. clientLeft = isIE && doc['documentMode'] != 9
  4975. && (isStrict ? docElem.clientLeft : body.clientLeft)
  4976. || 0;
  4977. if (1 > 2) {
  4978. }
  4979. x -= clientLeft;
  4980. y -= clientTop;
  4981. // iphone/ipad/itouch 下的 Safari 获取 getBoundingClientRect 时,已经加入 scrollTop
  4982. if (UA.mobile == 'apple') {
  4983. x -= DOM[SCROLL_LEFT](w);
  4984. y -= DOM[SCROLL_TOP](w);
  4985. }
  4986. }
  4987. return { left:x, top:y };
  4988. }
  4989. function getPageOffset(el) {
  4990. var pos = getClientPosition(el);
  4991. var w = getWin(el[OWNER_DOCUMENT]);
  4992. pos.left += DOM[SCROLL_LEFT](w);
  4993. pos.top += DOM[SCROLL_TOP](w);
  4994. return pos;
  4995. }
  4996. // 获取 elem 相对 elem.ownerDocument 的坐标
  4997. function getOffset(el, relativeWin) {
  4998. var position = {left:0, top:0};
  4999. // Iterate up the ancestor frame chain, keeping track of the current window
  5000. // and the current element in that window.
  5001. var currentWin = getWin(el[OWNER_DOCUMENT]);
  5002. var currentEl = el;
  5003. relativeWin = relativeWin || currentWin;
  5004. do {
  5005. // if we're at the top window, we want to get the page offset.
  5006. // if we're at an inner frame, we only want to get the window position
  5007. // so that we can determine the actual page offset in the context of
  5008. // the outer window.
  5009. var offset = currentWin == relativeWin ?
  5010. getPageOffset(currentEl) :
  5011. getClientPosition(currentEl);
  5012. position.left += offset.left;
  5013. position.top += offset.top;
  5014. } while (currentWin && currentWin != relativeWin &&
  5015. (currentEl = currentWin['frameElement']) &&
  5016. (currentWin = currentWin.parent));
  5017. return position;
  5018. }
  5019. // 设置 elem 相对 elem.ownerDocument 的坐标
  5020. function setOffset(elem, offset) {
  5021. // set position first, in-case top/left are set even on static elem
  5022. if (DOM.css(elem, POSITION) === 'static') {
  5023. elem.style[POSITION] = RELATIVE;
  5024. }
  5025. var old = getOffset(elem), ret = { }, current, key;
  5026. for (key in offset) {
  5027. current = PARSEINT(DOM.css(elem, key), 10) || 0;
  5028. ret[key] = current + offset[key] - old[key];
  5029. }
  5030. DOM.css(elem, ret);
  5031. }
  5032. return DOM;
  5033. }, {
  5034. requires:["./base", "ua"]
  5035. });
  5036. /**
  5037. * 2011-05-24
  5038. * - 承玉:
  5039. * - 调整 docWidth , docHeight ,
  5040. * viewportHeight , viewportWidth ,scrollLeft,scrollTop 参数,
  5041. * 便于放置到 Node 中去,可以完全摆脱 DOM,完全使用 Node
  5042. *
  5043. *
  5044. *
  5045. * TODO:
  5046. * - 考虑是否实现 jQuery 的 position, offsetParent 等功能
  5047. * - 更详细的测试用例(比如:测试 position 为 fixed 的情况)
  5048. */
  5049. /**
  5050. * @fileOverview selector
  5051. * @author lifesinger@gmail.com , yiminghe@gmail.com
  5052. */
  5053. KISSY.add('dom/selector', function (S, DOM, undefined) {
  5054. var doc = document,
  5055. filter = S.filter,
  5056. require = function (selector) {
  5057. return S.require(selector);
  5058. },
  5059. isArray = S.isArray,
  5060. isString = S.isString,
  5061. makeArray = S.makeArray,
  5062. isNodeList = DOM._isNodeList,
  5063. nodeName = DOM._nodeName,
  5064. push = Array.prototype.push,
  5065. SPACE = ' ',
  5066. COMMA = ',',
  5067. trim = S.trim,
  5068. ANY = '*',
  5069. REG_ID = /^#[\w-]+$/,
  5070. REG_QUERY = /^(?:#([\w-]+))?\s*([\w-]+|\*)?\.?([\w-]+)?$/;
  5071. function query_each(f) {
  5072. var self = this, el, i;
  5073. for (i = 0; i < self.length; i++) {
  5074. el = self[i];
  5075. if (f(el, i) === false) {
  5076. break;
  5077. }
  5078. }
  5079. }
  5080. /**
  5081. * Retrieves an Array of HTMLElement based on the given CSS selector.
  5082. * @param {String|Array<HTMLElement>} selector
  5083. * @param {String|Array<HTMLElement>} context find elements matching selector under context
  5084. * @return {Array} The array of found HTMLElement
  5085. */
  5086. function query(selector, context) {
  5087. var ret,
  5088. i,
  5089. simpleContext,
  5090. isSelectorString = isString(selector),
  5091. // optimize common usage
  5092. contexts = (context === undefined && (simpleContext = 1)) ?
  5093. [doc] :
  5094. tuneContext(context);
  5095. // 常见的空
  5096. if (!selector) {
  5097. ret = [];
  5098. }
  5099. // 常见的选择器
  5100. // DOM.query("#x")
  5101. else if (isSelectorString) {
  5102. selector = trim(selector);
  5103. if (contexts.length == 1 && selector) {
  5104. ret = quickFindBySelectorStr(selector, contexts[0]);
  5105. }
  5106. }
  5107. // 不写 context,就是包装一下
  5108. else if (simpleContext) {
  5109. // 常见的单个元素
  5110. // DOM.query(document.getElementById("xx"))
  5111. if (selector.nodeType || selector.setTimeout || S.isFunction(selector)) {
  5112. ret = [selector];
  5113. }
  5114. // KISSY NodeList 特殊点直接返回,提高性能
  5115. else if (selector.getDOMNodes) {
  5116. return selector;
  5117. }
  5118. // 常见的数组
  5119. // var x=DOM.query(".l");
  5120. // DOM.css(x,"color","red");
  5121. else if (isArray(selector)) {
  5122. ret = selector;
  5123. }
  5124. // selector.item
  5125. // document.createElement("select").item 已经在第一步处理了
  5126. // DOM.query(document.getElementsByTagName("a"))
  5127. else if (isNodeList(selector)) {
  5128. ret = S.makeArray(selector);
  5129. } else {
  5130. ret = [ selector ];
  5131. }
  5132. }
  5133. if (!ret) {
  5134. ret = [];
  5135. if (selector) {
  5136. for (i = 0; i < contexts.length; i++) {
  5137. push.apply(ret, queryByContexts(selector, contexts[i]));
  5138. }
  5139. //必要时去重排序
  5140. if (ret.length > 1 &&
  5141. // multiple contexts
  5142. (contexts.length > 1 ||
  5143. (isSelectorString &&
  5144. // multiple selector
  5145. selector.indexOf(COMMA) > -1))) {
  5146. unique(ret);
  5147. }
  5148. }
  5149. }
  5150. // attach each method
  5151. ret.each = query_each;
  5152. return ret;
  5153. }
  5154. function queryByContexts(selector, context) {
  5155. var ret = [],
  5156. isSelectorString = isString(selector);
  5157. if (isSelectorString && selector.match(REG_QUERY) ||
  5158. !isSelectorString) {
  5159. // 简单选择器自己处理
  5160. ret = queryBySimple(selector, context);
  5161. }
  5162. // 如果选择器有 , 分开递归一部分一部分来
  5163. else if (isSelectorString && selector.indexOf(COMMA) > -1) {
  5164. ret = queryBySelectors(selector, context);
  5165. }
  5166. else {
  5167. // 复杂了,交给 sizzle
  5168. ret = queryBySizzle(selector, context);
  5169. }
  5170. return ret;
  5171. }
  5172. // 交给 sizzle 模块处理
  5173. function queryBySizzle(selector, context) {
  5174. var ret = [],
  5175. sizzle = require("sizzle");
  5176. if (sizzle) {
  5177. sizzle(selector, context, ret);
  5178. } else {
  5179. // 原生不支持
  5180. error(selector);
  5181. }
  5182. return ret;
  5183. }
  5184. // 处理 selector 的每个部分
  5185. function queryBySelectors(selector, context) {
  5186. var ret = [],
  5187. i,
  5188. selectors = selector.split(/\s*,\s*/);
  5189. for (i = 0; i < selectors.length; i++) {
  5190. push.apply(ret, queryByContexts(selectors[i], context));
  5191. }
  5192. // 多部分选择器可能得到重复结果
  5193. return ret;
  5194. }
  5195. function quickFindBySelectorStr(selector, context) {
  5196. var ret, t, match, id, tag, cls;
  5197. // selector 为 #id 是最常见的情况,特殊优化处理
  5198. if (REG_ID.test(selector)) {
  5199. t = getElementById(selector.slice(1), context);
  5200. if (t) {
  5201. // #id 无效时,返回空数组
  5202. ret = [t];
  5203. } else {
  5204. ret = [];
  5205. }
  5206. }
  5207. // selector 为支持列表中的其它 6 种
  5208. else {
  5209. match = REG_QUERY.exec(selector);
  5210. if (match) {
  5211. // 获取匹配出的信息
  5212. id = match[1];
  5213. tag = match[2];
  5214. cls = match[3];
  5215. // 空白前只能有 id ,取出来作为 context
  5216. context = (id ? getElementById(id, context) : context);
  5217. if (context) {
  5218. // #id .cls | #id tag.cls | .cls | tag.cls | #id.cls
  5219. if (cls) {
  5220. if (!id || selector.indexOf(SPACE) != -1) { // 排除 #id.cls
  5221. ret = [].concat(getElementsByClassName(cls, tag, context));
  5222. }
  5223. // 处理 #id.cls
  5224. else {
  5225. t = getElementById(id, context);
  5226. if (t && hasClass(t, cls)) {
  5227. ret = [t];
  5228. }
  5229. }
  5230. }
  5231. // #id tag | tag
  5232. else if (tag) { // 排除空白字符串
  5233. ret = getElementsByTagName(tag, context);
  5234. }
  5235. }
  5236. ret = ret || [];
  5237. }
  5238. }
  5239. return ret;
  5240. }
  5241. // 最简单情况了,单个选择器部分,单个上下文
  5242. function queryBySimple(selector, context) {
  5243. var ret,
  5244. isSelectorString = isString(selector);
  5245. if (isSelectorString) {
  5246. ret = quickFindBySelectorStr(selector, context) || [];
  5247. }
  5248. // 传入的 selector 是 NodeList 或已是 Array
  5249. else if (isArray(selector) || isNodeList(selector)) {
  5250. // 只能包含在 context 里面
  5251. // filter 会转换为 nodelist 为数组
  5252. ret = filter(selector, function (s) {
  5253. return testByContext(s, context);
  5254. });
  5255. }
  5256. // 传入的 selector 是 HTMLNode 查看约束
  5257. // 否则 window/document,原样返回
  5258. else if (testByContext(selector, context)) {
  5259. ret = [selector];
  5260. }
  5261. return ret;
  5262. }
  5263. function testByContext(element, context) {
  5264. if (!element) {
  5265. return false;
  5266. }
  5267. // 防止 element 节点还没添加到 document ,但是也可以获取到 query(element) => [element]
  5268. // document 的上下文一律放行
  5269. // context == doc 意味着没有提供第二个参数,到这里只是想单纯包装原生节点,则不检测
  5270. if (context == doc) {
  5271. return true;
  5272. }
  5273. // 节点受上下文约束
  5274. return DOM.contains(context, element);
  5275. }
  5276. var unique = S.noop;
  5277. (function () {
  5278. var sortOrder,
  5279. hasDuplicate,
  5280. baseHasDuplicate = true;
  5281. // Here we check if the JavaScript engine is using some sort of
  5282. // optimization where it does not always call our comparision
  5283. // function. If that is the case, discard the hasDuplicate value.
  5284. // Thus far that includes Google Chrome.
  5285. [0, 0].sort(function () {
  5286. baseHasDuplicate = false;
  5287. return 0;
  5288. });
  5289. // 排序去重
  5290. unique = function (elements) {
  5291. if (sortOrder) {
  5292. hasDuplicate = baseHasDuplicate;
  5293. elements.sort(sortOrder);
  5294. if (hasDuplicate) {
  5295. var i = 1, len = elements.length;
  5296. while (i < len) {
  5297. if (elements[i] === elements[ i - 1 ]) {
  5298. elements.splice(i, 1);
  5299. } else {
  5300. i++;
  5301. }
  5302. }
  5303. }
  5304. }
  5305. return elements;
  5306. };
  5307. // 貌似除了 ie 都有了...
  5308. if (doc.documentElement.compareDocumentPosition) {
  5309. sortOrder = function (a, b) {
  5310. if (a == b) {
  5311. hasDuplicate = true;
  5312. return 0;
  5313. }
  5314. if (!a.compareDocumentPosition || !b.compareDocumentPosition) {
  5315. return a.compareDocumentPosition ? -1 : 1;
  5316. }
  5317. return a.compareDocumentPosition(b) & 4 ? -1 : 1;
  5318. };
  5319. } else {
  5320. sortOrder = function (a, b) {
  5321. // The nodes are identical, we can exit early
  5322. if (a == b) {
  5323. hasDuplicate = true;
  5324. return 0;
  5325. // Fallback to using sourceIndex (in IE) if it's available on both nodes
  5326. } else if (a.sourceIndex && b.sourceIndex) {
  5327. return a.sourceIndex - b.sourceIndex;
  5328. }
  5329. };
  5330. }
  5331. })();
  5332. // 调整 context 为合理值
  5333. function tuneContext(context) {
  5334. return query(context, undefined);
  5335. }
  5336. // query #id
  5337. function getElementById(id, context) {
  5338. var doc = context,
  5339. el;
  5340. if (context.nodeType !== DOM.DOCUMENT_NODE) {
  5341. doc = context.ownerDocument;
  5342. }
  5343. el = doc.getElementById(id);
  5344. if (el && el.id === id) {
  5345. // optimize for common usage
  5346. }
  5347. else if (el && el.parentNode) {
  5348. // ie opera confuse name with id
  5349. // https://github.com/kissyteam/kissy/issues/67
  5350. // 不能直接 el.id ,否则 input shadow form attribute
  5351. if (!idEq(el, id)) {
  5352. // 直接在 context 下的所有节点找
  5353. el = DOM.filter(ANY, "#" + id, context)[0] || null;
  5354. }
  5355. // ie 特殊情况下以及指明在 context 下找了,不需要再判断
  5356. // 如果指定了 context node , 还要判断 id 是否处于 context 内
  5357. else if (!testByContext(el, context)) {
  5358. el = null;
  5359. }
  5360. } else {
  5361. el = null;
  5362. }
  5363. return el;
  5364. }
  5365. // query tag
  5366. function getElementsByTagName(tag, context) {
  5367. return context && makeArray(context.getElementsByTagName(tag)) || [];
  5368. }
  5369. (function () {
  5370. // Check to see if the browser returns only elements
  5371. // when doing getElementsByTagName('*')
  5372. // Create a fake element
  5373. var div = doc.createElement('div');
  5374. div.appendChild(doc.createComment(''));
  5375. // Make sure no comments are found
  5376. if (div.getElementsByTagName(ANY).length > 0) {
  5377. getElementsByTagName = function (tag, context) {
  5378. var ret = makeArray(context.getElementsByTagName(tag));
  5379. if (tag === ANY) {
  5380. var t = [], i = 0, node;
  5381. while ((node = ret[i++])) {
  5382. // Filter out possible comments
  5383. if (node.nodeType === 1) {
  5384. t.push(node);
  5385. }
  5386. }
  5387. ret = t;
  5388. }
  5389. return ret;
  5390. };
  5391. }
  5392. })();
  5393. // query .cls
  5394. var getElementsByClassName = doc.getElementsByClassName ? function (cls, tag, context) {
  5395. // query("#id1 xx","#id2")
  5396. // #id2 内没有 #id1 , context 为 null , 这里防御下
  5397. if (!context) {
  5398. return [];
  5399. }
  5400. var els = context.getElementsByClassName(cls),
  5401. ret,
  5402. i = 0,
  5403. len = els.length,
  5404. el;
  5405. if (tag && tag !== ANY) {
  5406. ret = [];
  5407. for (; i < len; ++i) {
  5408. el = els[i];
  5409. if (nodeName(el, tag)) {
  5410. ret.push(el);
  5411. }
  5412. }
  5413. } else {
  5414. ret = makeArray(els);
  5415. }
  5416. return ret;
  5417. } : ( doc.querySelectorAll ? function (cls, tag, context) {
  5418. // ie8 return staticNodeList 对象,[].concat 会形成 [ staticNodeList ] ,手动转化为普通数组
  5419. return context && makeArray(context.querySelectorAll((tag ? tag : '') + '.' + cls)) || [];
  5420. } : function (cls, tag, context) {
  5421. if (!context) {
  5422. return [];
  5423. }
  5424. var els = context.getElementsByTagName(tag || ANY),
  5425. ret = [],
  5426. i = 0,
  5427. len = els.length,
  5428. el;
  5429. for (; i < len; ++i) {
  5430. el = els[i];
  5431. if (hasClass(el, cls)) {
  5432. ret.push(el);
  5433. }
  5434. }
  5435. return ret;
  5436. });
  5437. function hasClass(el, cls) {
  5438. var className;
  5439. return (className = el.className) && (" " + className + " ").indexOf(" " + cls + " ") !== -1;
  5440. }
  5441. // throw exception
  5442. function error(msg) {
  5443. S.error('Unsupported selector: ' + msg);
  5444. }
  5445. S.mix(DOM, {
  5446. query:query,
  5447. get:function (selector, context) {
  5448. return query(selector, context)[0] || null;
  5449. },
  5450. unique:unique,
  5451. /**
  5452. * Filters an array of elements to only include matches of a filter.
  5453. * @param filter selector or fn
  5454. */
  5455. filter:function (selector, filter, context) {
  5456. var elems = query(selector, context),
  5457. sizzle = require("sizzle"),
  5458. match,
  5459. tag,
  5460. id,
  5461. cls,
  5462. ret = [];
  5463. // 默认仅支持最简单的 tag.cls 或 #id 形式
  5464. if (isString(filter) &&
  5465. (filter = trim(filter)) &&
  5466. (match = REG_QUERY.exec(filter))) {
  5467. id = match[1];
  5468. tag = match[2];
  5469. cls = match[3];
  5470. if (!id) {
  5471. filter = function (elem) {
  5472. var tagRe = true, clsRe = true;
  5473. // 指定 tag 才进行判断
  5474. if (tag) {
  5475. tagRe = nodeName(elem, tag);
  5476. }
  5477. // 指定 cls 才进行判断
  5478. if (cls) {
  5479. clsRe = hasClass(elem, cls);
  5480. }
  5481. return clsRe && tagRe;
  5482. }
  5483. } else if (id && !tag && !cls) {
  5484. filter = function (elem) {
  5485. return idEq(elem, id);
  5486. };
  5487. }
  5488. }
  5489. if (S.isFunction(filter)) {
  5490. ret = S.filter(elems, filter);
  5491. }
  5492. // 其它复杂 filter, 采用外部选择器
  5493. else if (filter && sizzle) {
  5494. ret = sizzle.matches(filter, elems);
  5495. }
  5496. // filter 为空或不支持的 selector
  5497. else {
  5498. error(filter);
  5499. }
  5500. return ret;
  5501. },
  5502. /**
  5503. * Returns true if the passed element(s) match the passed filter
  5504. */
  5505. test:function (selector, filter, context) {
  5506. var elements = query(selector, context);
  5507. return elements.length && (DOM.filter(elements, filter, context).length === elements.length);
  5508. }
  5509. });
  5510. function idEq(elem, id) {
  5511. // form !
  5512. var idNode = elem.getAttributeNode("id");
  5513. return idNode && idNode.nodeValue === id;
  5514. }
  5515. return DOM;
  5516. }, {
  5517. requires:["./base"]
  5518. });
  5519. /**
  5520. * NOTES:
  5521. *
  5522. * 2011.08.02
  5523. * - 利用 sizzle 重构选择器
  5524. * - 1.1.6 修正,原来 context 只支持 #id 以及 document
  5525. * 1.2 context 支持任意,和 selector 格式一致
  5526. * - 简单选择器也和 jquery 保持一致 DOM.query("xx","yy") 支持
  5527. * - context 不提供则为当前 document ,否则通过 query 递归取得
  5528. * - 保证选择出来的节点(除了 document window)都是位于 context 范围内
  5529. *
  5530. *
  5531. * 2010.01
  5532. * - 对 reg exec 的结果(id, tag, className)做 cache, 发现对性能影响很小,去掉。
  5533. * - getElementById 使用频率最高,使用直达通道优化。
  5534. * - getElementsByClassName 性能优于 querySelectorAll, 但 IE 系列不支持。
  5535. * - instanceof 对性能有影响。
  5536. * - 内部方法的参数,比如 cls, context 等的异常情况,已经在 query 方法中有保证,无需冗余“防卫”。
  5537. * - query 方法中的条件判断考虑了“频率优先”原则。最有可能出现的情况放在前面。
  5538. * - Array 的 push 方法可以用 j++ 来替代,性能有提升。
  5539. * - 返回值策略和 Sizzle 一致,正常时,返回数组;其它所有情况,返回空数组。
  5540. *
  5541. * - 从压缩角度考虑,还可以将 getElmentsByTagName 和 getElementsByClassName 定义为常量,
  5542. * 不过感觉这样做太“压缩控”,还是保留不替换的好。
  5543. *
  5544. * - 调整 getElementsByClassName 的降级写法,性能最差的放最后。
  5545. *
  5546. * 2010.02
  5547. * - 添加对分组选择器的支持(主要参考 Sizzle 的代码,代去除了对非 Grade A 级浏览器的支持)
  5548. *
  5549. * 2010.03
  5550. * - 基于原生 dom 的两个 api: S.query 返回数组; S.get 返回第一个。
  5551. * 基于 Node 的 api: S.one, 在 Node 中实现。
  5552. * 基于 NodeList 的 api: S.all, 在 NodeList 中实现。
  5553. * 通过 api 的分层,同时满足初级用户和高级用户的需求。
  5554. *
  5555. * 2010.05
  5556. * - 去掉给 S.query 返回值默认添加的 each 方法,保持纯净。
  5557. * - 对于不支持的 selector, 采用外部耦合进来的 Selector.
  5558. *
  5559. * 2010.06
  5560. * - 增加 filter 和 test 方法
  5561. *
  5562. * 2010.07
  5563. * - 取消对 , 分组的支持,group 直接用 Sizzle
  5564. *
  5565. * 2010.08
  5566. * - 给 S.query 的结果 attach each 方法
  5567. *
  5568. * 2011.05
  5569. * - 承玉:恢复对简单分组支持
  5570. *
  5571. * Ref: http://ejohn.org/blog/selectors-that-people-actually-use/
  5572. * 考虑 2/8 原则,仅支持以下选择器:
  5573. * #id
  5574. * tag
  5575. * .cls
  5576. * #id tag
  5577. * #id .cls
  5578. * tag.cls
  5579. * #id tag.cls
  5580. * 注 1:REG_QUERY 还会匹配 #id.cls
  5581. * 注 2:tag 可以为 * 字符
  5582. * 注 3: 支持 , 号分组
  5583. *
  5584. *
  5585. * Bugs:
  5586. * - S.query('#test-data *') 等带 * 号的选择器,在 IE6 下返回的值不对。jQuery 等类库也有此 bug, 诡异。
  5587. *
  5588. * References:
  5589. * - http://ejohn.org/blog/selectors-that-people-actually-use/
  5590. * - http://ejohn.org/blog/thoughts-on-queryselectorall/
  5591. * - MDC: querySelector, querySelectorAll, getElementsByClassName
  5592. * - Sizzle: http://github.com/jeresig/sizzle
  5593. * - MINI: http://james.padolsey.com/javascript/mini/
  5594. * - Peppy: http://jamesdonaghue.com/?p=40
  5595. * - Sly: http://github.com/digitarald/sly
  5596. * - XPath, TreeWalker:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html
  5597. *
  5598. * - http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
  5599. * - http://www.quirksmode.org/dom/getElementsByTagNames.html
  5600. * - http://ejohn.org/blog/comparing-document-position/
  5601. * - http://github.com/jeresig/sizzle/blob/master/sizzle.js
  5602. */
  5603. /**
  5604. * @fileOverview style for ie
  5605. * @author lifesinger@gmail.com,yiminghe@gmail.com
  5606. */
  5607. KISSY.add('dom/style-ie', function (S, DOM, UA, Style) {
  5608. var HUNDRED = 100;
  5609. // only for ie
  5610. if (!UA['ie']) {
  5611. return DOM;
  5612. }
  5613. var doc = document,
  5614. docElem = doc.documentElement,
  5615. OPACITY = 'opacity',
  5616. STYLE = 'style',
  5617. FILTER = "filter",
  5618. CURRENT_STYLE = 'currentStyle',
  5619. RUNTIME_STYLE = 'runtimeStyle',
  5620. LEFT = 'left',
  5621. PX = 'px',
  5622. CUSTOM_STYLES = Style._CUSTOM_STYLES,
  5623. RE_NUMPX = /^-?\d+(?:px)?$/i,
  5624. RE_NUM = /^-?\d/,
  5625. backgroundPosition = "backgroundPosition",
  5626. ropacity = /opacity=([^)]*)/,
  5627. ralpha = /alpha\([^)]*\)/i;
  5628. // odd backgroundPosition
  5629. CUSTOM_STYLES[backgroundPosition] = {
  5630. get:function (elem, computed) {
  5631. if (computed) {
  5632. return elem[CURRENT_STYLE][backgroundPosition + "X"] +
  5633. " " +
  5634. elem[CURRENT_STYLE][backgroundPosition + "Y"];
  5635. } else {
  5636. return elem[STYLE][backgroundPosition];
  5637. }
  5638. }
  5639. };
  5640. // use alpha filter for IE opacity
  5641. try {
  5642. if (docElem.style[OPACITY] == null) {
  5643. CUSTOM_STYLES[OPACITY] = {
  5644. get:function (elem, computed) {
  5645. // 没有设置过 opacity 时会报错,这时返回 1 即可
  5646. // 如果该节点没有添加到 dom ,取不到 filters 结构
  5647. // val = elem[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
  5648. return ropacity.test((
  5649. computed && elem[CURRENT_STYLE] ?
  5650. elem[CURRENT_STYLE][FILTER] :
  5651. elem[STYLE][FILTER]) || "") ?
  5652. ( parseFloat(RegExp.$1) / HUNDRED ) + "" :
  5653. computed ? "1" : "";
  5654. },
  5655. set:function (elem, val) {
  5656. val = parseFloat(val);
  5657. var style = elem[STYLE],
  5658. currentStyle = elem[CURRENT_STYLE],
  5659. opacity = isNaN(val) ? "" : "alpha(" + OPACITY + "=" + val * HUNDRED + ")",
  5660. filter = S.trim(currentStyle && currentStyle[FILTER] || style[FILTER] || "");
  5661. // ie has layout
  5662. style.zoom = 1;
  5663. // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute
  5664. if (val >= 1 && S.trim(filter.replace(ralpha, "")) === "") {
  5665. // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
  5666. // if "filter:" is present at all, clearType is disabled, we want to avoid this
  5667. // style.removeAttribute is IE Only, but so apparently is this code path...
  5668. style.removeAttribute(FILTER);
  5669. // if there there is no filter style applied in a css rule, we are done
  5670. if (currentStyle && !currentStyle[FILTER]) {
  5671. return;
  5672. }
  5673. }
  5674. // otherwise, set new filter values
  5675. // 如果 >=1 就不设,就不能覆盖外部样式表定义的样式,一定要设
  5676. style.filter = ralpha.test(filter) ?
  5677. filter.replace(ralpha, opacity) :
  5678. filter + (filter ? ", " : "") + opacity;
  5679. }
  5680. };
  5681. }
  5682. }
  5683. catch (ex) {
  5684. S.log('IE filters ActiveX is disabled. ex = ' + ex);
  5685. }
  5686. /*
  5687. border fix
  5688. ie 不设置数值,则 computed style 不返回数值,只返回 thick? medium ...
  5689. (default is "medium")
  5690. */
  5691. var IE8 = UA['ie'] == 8,
  5692. BORDER_MAP = {
  5693. },
  5694. BORDERS = ["", "Top", "Left", "Right", "Bottom"];
  5695. BORDER_MAP['thin'] = IE8 ? '1px' : '2px';
  5696. BORDER_MAP['medium'] = IE8 ? '3px' : '4px';
  5697. BORDER_MAP['thick'] = IE8 ? '5px' : '6px';
  5698. S.each(BORDERS, function (b) {
  5699. var name = "border" + b + "Width",
  5700. styleName = "border" + b + "Style";
  5701. /**
  5702. * @ignore
  5703. */
  5704. CUSTOM_STYLES[name] = {
  5705. get:function (elem, computed) {
  5706. // 只有需要计算样式的时候才转换,否则取原值
  5707. var currentStyle = computed ? elem[CURRENT_STYLE] : 0,
  5708. current = currentStyle && String(currentStyle[name]) || undefined;
  5709. // look up keywords if a border exists
  5710. if (current && current.indexOf("px") < 0) {
  5711. // 边框没有隐藏
  5712. if (BORDER_MAP[current] && currentStyle[styleName] !== "none") {
  5713. current = BORDER_MAP[current];
  5714. } else {
  5715. // otherwise no border
  5716. current = 0;
  5717. }
  5718. }
  5719. return current;
  5720. }
  5721. };
  5722. });
  5723. // getComputedStyle for IE
  5724. if (!(doc.defaultView || { }).getComputedStyle && docElem[CURRENT_STYLE]) {
  5725. DOM._getComputedStyle = function (elem, name) {
  5726. name = DOM._cssProps[name] || name;
  5727. var ret = elem[CURRENT_STYLE] && elem[CURRENT_STYLE][name];
  5728. // 当 width/height 设置为百分比时,通过 pixelLeft 方式转换的 width/height 值
  5729. // 一开始就处理了! CUSTOM_STYLE["height"],CUSTOM_STYLE["width"] ,cssHook 解决@2011-08-19
  5730. // 在 ie 下不对,需要直接用 offset 方式
  5731. // borderWidth 等值也有问题,但考虑到 borderWidth 设为百分比的概率很小,这里就不考虑了
  5732. // From the awesome hack by Dean Edwards
  5733. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  5734. // If we're not dealing with a regular pixel number
  5735. // but a number that has a weird ending, we need to convert it to pixels
  5736. if ((!RE_NUMPX.test(ret) && RE_NUM.test(ret))) {
  5737. // Remember the original values
  5738. var style = elem[STYLE],
  5739. left = style[LEFT],
  5740. rsLeft = elem[RUNTIME_STYLE] && elem[RUNTIME_STYLE][LEFT];
  5741. // Put in the new values to get a computed value out
  5742. if (rsLeft) {
  5743. elem[RUNTIME_STYLE][LEFT] = elem[CURRENT_STYLE][LEFT];
  5744. }
  5745. style[LEFT] = name === 'fontSize' ? '1em' : (ret || 0);
  5746. ret = style['pixelLeft'] + PX;
  5747. // Revert the changed values
  5748. style[LEFT] = left;
  5749. if (rsLeft) {
  5750. elem[RUNTIME_STYLE][LEFT] = rsLeft;
  5751. }
  5752. }
  5753. return ret === "" ? "auto" : ret;
  5754. };
  5755. }
  5756. return DOM;
  5757. }, {
  5758. requires:["./base", "ua", "./style"]
  5759. });
  5760. /**
  5761. * NOTES:
  5762. *
  5763. * yiminghe@gmail.com: 2011.12.21 backgroundPosition in ie
  5764. * - currentStyle['backgroundPosition'] undefined
  5765. * - currentStyle['backgroundPositionX'] ok
  5766. * - currentStyle['backgroundPositionY'] ok
  5767. *
  5768. *
  5769. * yiminghe@gmail.com: 2011.05.19 opacity in ie
  5770. * - 如果节点是动态创建,设置opacity,没有加到 dom 前,取不到 opacity 值
  5771. * - 兼容:border-width 值,ie 下有可能返回 medium/thin/thick 等值,其它浏览器返回 px 值。
  5772. *
  5773. * - opacity 的实现,参考自 jquery
  5774. *
  5775. */
  5776. /**
  5777. * @fileOverview dom/style
  5778. * @author yiminghe@gmail.com,lifesinger@gmail.com
  5779. */
  5780. KISSY.add('dom/style', function (S, DOM, UA, undefined) {
  5781. "use strict";
  5782. var doc = document,
  5783. docElem = doc.documentElement,
  5784. isIE = UA['ie'],
  5785. STYLE = 'style',
  5786. FLOAT = 'float',
  5787. CSS_FLOAT = 'cssFloat',
  5788. STYLE_FLOAT = 'styleFloat',
  5789. WIDTH = 'width',
  5790. HEIGHT = 'height',
  5791. AUTO = 'auto',
  5792. DISPLAY = 'display',
  5793. OLD_DISPLAY = DISPLAY + S.now(),
  5794. NONE = 'none',
  5795. PARSEINT = parseInt,
  5796. RE_NUMPX = /^-?\d+(?:px)?$/i,
  5797. cssNumber = {
  5798. "fillOpacity":1,
  5799. "fontWeight":1,
  5800. "lineHeight":1,
  5801. "opacity":1,
  5802. "orphans":1,
  5803. "widows":1,
  5804. "zIndex":1,
  5805. "zoom":1
  5806. },
  5807. RE_DASH = /-([a-z])/ig,
  5808. CAMELCASE_FN = function (all, letter) {
  5809. return letter.toUpperCase();
  5810. },
  5811. // 考虑 ie9 ...
  5812. rupper = /([A-Z]|^ms)/g,
  5813. EMPTY = '',
  5814. DEFAULT_UNIT = 'px',
  5815. CUSTOM_STYLES = {},
  5816. cssProps = {},
  5817. defaultDisplay = {};
  5818. // normalize reserved word float alternatives ("cssFloat" or "styleFloat")
  5819. if (docElem[STYLE][CSS_FLOAT] !== undefined) {
  5820. cssProps[FLOAT] = CSS_FLOAT;
  5821. }
  5822. else if (docElem[STYLE][STYLE_FLOAT] !== undefined) {
  5823. cssProps[FLOAT] = STYLE_FLOAT;
  5824. }
  5825. function camelCase(name) {
  5826. return name.replace(RE_DASH, CAMELCASE_FN);
  5827. }
  5828. var defaultDisplayDetectIframe,
  5829. defaultDisplayDetectIframeDoc;
  5830. // modified from jquery : bullet-proof method of getting default display
  5831. // fix domain problem in ie>6 , ie6 still access denied
  5832. function getDefaultDisplay(tagName) {
  5833. var body,
  5834. elem;
  5835. if (!defaultDisplay[ tagName ]) {
  5836. body = doc.body || doc.documentElement;
  5837. elem = doc.createElement(tagName);
  5838. DOM.prepend(elem, body);
  5839. var oldDisplay = DOM.css(elem, "display");
  5840. body.removeChild(elem);
  5841. // If the simple way fails,
  5842. // get element's real default display by attaching it to a temp iframe
  5843. if (oldDisplay === "none" || oldDisplay === "") {
  5844. // No iframe to use yet, so create it
  5845. if (!defaultDisplayDetectIframe) {
  5846. defaultDisplayDetectIframe = doc.createElement("iframe");
  5847. defaultDisplayDetectIframe.frameBorder =
  5848. defaultDisplayDetectIframe.width =
  5849. defaultDisplayDetectIframe.height = 0;
  5850. DOM.prepend(defaultDisplayDetectIframe, body);
  5851. var iframeSrc;
  5852. if (iframeSrc = DOM._genEmptyIframeSrc()) {
  5853. defaultDisplayDetectIframe.src = iframeSrc;
  5854. }
  5855. } else {
  5856. DOM.prepend(defaultDisplayDetectIframe, body);
  5857. }
  5858. // Create a cacheable copy of the iframe document on first call.
  5859. // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
  5860. // document to it; WebKit & Firefox won't allow reusing the iframe document.
  5861. if (!defaultDisplayDetectIframeDoc || !defaultDisplayDetectIframe.createElement) {
  5862. try {
  5863. defaultDisplayDetectIframeDoc = defaultDisplayDetectIframe.contentWindow.document;
  5864. defaultDisplayDetectIframeDoc.write(( doc.compatMode === "CSS1Compat" ? "<!doctype html>" : "" )
  5865. + "<html><head>" +
  5866. (UA['ie'] && DOM._isCustomDomain() ?
  5867. "<script>document.domain = '" +
  5868. doc.domain
  5869. + "';</script>" : "")
  5870. +
  5871. "</head><body>");
  5872. defaultDisplayDetectIframeDoc.close();
  5873. } catch (e) {
  5874. // ie6 need a breath , such as alert(8) or setTimeout;
  5875. // 同时需要同步,所以无解,勉强返回
  5876. return "block";
  5877. }
  5878. }
  5879. elem = defaultDisplayDetectIframeDoc.createElement(tagName);
  5880. defaultDisplayDetectIframeDoc.body.appendChild(elem);
  5881. oldDisplay = DOM.css(elem, "display");
  5882. body.removeChild(defaultDisplayDetectIframe);
  5883. }
  5884. // Store the correct default display
  5885. defaultDisplay[ tagName ] = oldDisplay;
  5886. }
  5887. return defaultDisplay[ tagName ];
  5888. }
  5889. S.mix(DOM, {
  5890. _camelCase:camelCase,
  5891. // _cssNumber:cssNumber,
  5892. _CUSTOM_STYLES:CUSTOM_STYLES,
  5893. _cssProps:cssProps,
  5894. _getComputedStyle:function (elem, name) {
  5895. var val = "",
  5896. computedStyle,
  5897. d = elem.ownerDocument;
  5898. name = name.replace(rupper, "-$1").toLowerCase();
  5899. // https://github.com/kissyteam/kissy/issues/61
  5900. if (computedStyle = d.defaultView.getComputedStyle(elem, null)) {
  5901. val = computedStyle.getPropertyValue(name) || computedStyle[name];
  5902. }
  5903. // 还没有加入到 document,就取行内
  5904. if (val == "" && !DOM.contains(d.documentElement, elem)) {
  5905. name = cssProps[name] || name;
  5906. val = elem[STYLE][name];
  5907. }
  5908. return val;
  5909. },
  5910. /**
  5911. * Get and set the style property on a DOM Node
  5912. */
  5913. style:function (selector, name, val) {
  5914. var els = DOM.query(selector), elem = els[0], i;
  5915. // supports hash
  5916. if (S.isPlainObject(name)) {
  5917. for (var k in name) {
  5918. for (i = els.length - 1; i >= 0; i--) {
  5919. style(els[i], k, name[k]);
  5920. }
  5921. }
  5922. return;
  5923. }
  5924. if (val === undefined) {
  5925. var ret = '';
  5926. if (elem) {
  5927. ret = style(elem, name, val);
  5928. }
  5929. return ret;
  5930. } else {
  5931. for (i = els.length - 1; i >= 0; i--) {
  5932. style(els[i], name, val);
  5933. }
  5934. }
  5935. },
  5936. /**
  5937. * (Gets computed style) or (sets styles) on the matches elements.
  5938. */
  5939. css:function (selector, name, val) {
  5940. var els = DOM.query(selector), elem = els[0], i;
  5941. // supports hash
  5942. if (S.isPlainObject(name)) {
  5943. for (var k in name) {
  5944. for (i = els.length - 1; i >= 0; i--) {
  5945. style(els[i], k, name[k]);
  5946. }
  5947. }
  5948. return;
  5949. }
  5950. name = camelCase(name);
  5951. var hook = CUSTOM_STYLES[name];
  5952. // getter
  5953. if (val === undefined) {
  5954. // supports css selector/Node/NodeList
  5955. var ret = '';
  5956. if (elem) {
  5957. // If a hook was provided get the computed value from there
  5958. if (hook && "get" in hook && (ret = hook.get(elem, true)) !== undefined) {
  5959. } else {
  5960. ret = DOM._getComputedStyle(elem, name);
  5961. }
  5962. }
  5963. return ret === undefined ? '' : ret;
  5964. }
  5965. // setter
  5966. else {
  5967. for (i = els.length - 1; i >= 0; i--) {
  5968. style(els[i], name, val);
  5969. }
  5970. }
  5971. },
  5972. /**
  5973. * Show the matched elements.
  5974. */
  5975. show:function (selector) {
  5976. var els = DOM.query(selector), elem, i;
  5977. for (i = els.length - 1; i >= 0; i--) {
  5978. elem = els[i];
  5979. elem[STYLE][DISPLAY] = DOM.data(elem, OLD_DISPLAY) || EMPTY;
  5980. // 可能元素还处于隐藏状态,比如 css 里设置了 display: none
  5981. if (DOM.css(elem, DISPLAY) === NONE) {
  5982. var tagName = elem.tagName.toLowerCase(),
  5983. old = getDefaultDisplay(tagName);
  5984. DOM.data(elem, OLD_DISPLAY, old);
  5985. elem[STYLE][DISPLAY] = old;
  5986. }
  5987. }
  5988. },
  5989. /**
  5990. * Hide the matched elements.
  5991. */
  5992. hide:function (selector) {
  5993. var els = DOM.query(selector), elem, i;
  5994. for (i = els.length - 1; i >= 0; i--) {
  5995. elem = els[i];
  5996. var style = elem[STYLE], old = style[DISPLAY];
  5997. if (old !== NONE) {
  5998. if (old) {
  5999. DOM.data(elem, OLD_DISPLAY, old);
  6000. }
  6001. style[DISPLAY] = NONE;
  6002. }
  6003. }
  6004. },
  6005. /**
  6006. * Display or hide the matched elements.
  6007. */
  6008. toggle:function (selector) {
  6009. var els = DOM.query(selector), elem, i;
  6010. for (i = els.length - 1; i >= 0; i--) {
  6011. elem = els[i];
  6012. if (DOM.css(elem, DISPLAY) === NONE) {
  6013. DOM.show(elem);
  6014. } else {
  6015. DOM.hide(elem);
  6016. }
  6017. }
  6018. },
  6019. /**
  6020. * Creates a stylesheet from a text blob of rules.
  6021. * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
  6022. * @param {String} cssText The text containing the css rules
  6023. * @param {String} id An id to add to the stylesheet for later removal
  6024. */
  6025. addStyleSheet:function (refWin, cssText, id) {
  6026. if (S.isString(refWin)) {
  6027. id = cssText;
  6028. cssText = refWin;
  6029. refWin = window;
  6030. }
  6031. refWin = DOM.get(refWin);
  6032. var win = DOM._getWin(refWin), doc = win.document;
  6033. var elem;
  6034. if (id && (id = id.replace('#', EMPTY))) {
  6035. elem = DOM.get('#' + id, doc);
  6036. }
  6037. // 仅添加一次,不重复添加
  6038. if (elem) {
  6039. return;
  6040. }
  6041. elem = DOM.create('<style>', { id:id }, doc);
  6042. // 先添加到 DOM 树中,再给 cssText 赋值,否则 css hack 会失效
  6043. DOM.get('head', doc).appendChild(elem);
  6044. if (elem.styleSheet) { // IE
  6045. elem.styleSheet.cssText = cssText;
  6046. } else { // W3C
  6047. elem.appendChild(doc.createTextNode(cssText));
  6048. }
  6049. },
  6050. unselectable:function (selector) {
  6051. var _els = DOM.query(selector), elem, j;
  6052. for (j = _els.length - 1; j >= 0; j--) {
  6053. elem = _els[j];
  6054. if (UA['gecko']) {
  6055. elem[STYLE]['MozUserSelect'] = 'none';
  6056. }
  6057. else if (UA['webkit']) {
  6058. elem[STYLE]['KhtmlUserSelect'] = 'none';
  6059. } else {
  6060. if (UA['ie'] || UA['opera']) {
  6061. var e, i = 0,
  6062. els = elem.getElementsByTagName("*");
  6063. elem.setAttribute("unselectable", 'on');
  6064. while (( e = els[ i++ ] )) {
  6065. switch (e.tagName.toLowerCase()) {
  6066. case 'iframe' :
  6067. case 'textarea' :
  6068. case 'input' :
  6069. case 'select' :
  6070. /* Ignore the above tags */
  6071. break;
  6072. default :
  6073. e.setAttribute("unselectable", 'on');
  6074. }
  6075. }
  6076. }
  6077. }
  6078. }
  6079. },
  6080. innerWidth:0,
  6081. innerHeight:0,
  6082. outerWidth:0,
  6083. outerHeight:0,
  6084. width:0,
  6085. height:0
  6086. });
  6087. function capital(str) {
  6088. return str.charAt(0).toUpperCase() + str.substring(1);
  6089. }
  6090. S.each([WIDTH, HEIGHT], function (name) {
  6091. DOM["inner" + capital(name)] = function (selector) {
  6092. var el = DOM.get(selector);
  6093. if (el) {
  6094. return getWH(el, name, "padding");
  6095. } else {
  6096. return null;
  6097. }
  6098. };
  6099. DOM["outer" + capital(name)] = function (selector, includeMargin) {
  6100. var el = DOM.get(selector);
  6101. if (el) {
  6102. return getWH(el, name, includeMargin ? "margin" : "border");
  6103. } else {
  6104. return null;
  6105. }
  6106. };
  6107. DOM[name] = function (selector, val) {
  6108. var ret = DOM.css(selector, name, val);
  6109. if (ret) {
  6110. ret = parseFloat(ret);
  6111. }
  6112. return ret;
  6113. };
  6114. });
  6115. var cssShow = { position:"absolute", visibility:"hidden", display:"block" };
  6116. /*
  6117. css height,width 永远都是计算值
  6118. */
  6119. S.each(["height", "width"], function (name) {
  6120. /**
  6121. * @ignore
  6122. */
  6123. CUSTOM_STYLES[ name ] = {
  6124. /**
  6125. * @ignore
  6126. */
  6127. get:function (elem, computed) {
  6128. var val;
  6129. if (computed) {
  6130. if (elem.offsetWidth !== 0) {
  6131. val = getWH(elem, name);
  6132. } else {
  6133. swap(elem, cssShow, function () {
  6134. val = getWH(elem, name);
  6135. });
  6136. }
  6137. return val + "px";
  6138. }
  6139. },
  6140. set:function (elem, value) {
  6141. if (RE_NUMPX.test(value)) {
  6142. value = parseFloat(value);
  6143. if (value >= 0) {
  6144. return value + "px";
  6145. }
  6146. } else {
  6147. return value;
  6148. }
  6149. }
  6150. };
  6151. });
  6152. S.each(["left", "top"], function (name) {
  6153. /**
  6154. * @ignore
  6155. */
  6156. CUSTOM_STYLES[ name ] = {
  6157. get:function (elem, computed) {
  6158. if (computed) {
  6159. var val = DOM._getComputedStyle(elem, name), offset;
  6160. // 1. 当没有设置 style.left 时,getComputedStyle 在不同浏览器下,返回值不同
  6161. // 比如:firefox 返回 0, webkit/ie 返回 auto
  6162. // 2. style.left 设置为百分比时,返回值为百分比
  6163. // 对于第一种情况,如果是 relative 元素,值为 0. 如果是 absolute 元素,值为 offsetLeft - marginLeft
  6164. // 对于第二种情况,大部分类库都未做处理,属于“明之而不 fix”的保留 bug
  6165. if (val === AUTO) {
  6166. val = 0;
  6167. if (S.inArray(DOM.css(elem, 'position'), ['absolute', 'fixed'])) {
  6168. offset = elem[name === 'left' ? 'offsetLeft' : 'offsetTop'];
  6169. // old-ie 下,elem.offsetLeft 包含 offsetParent 的 border 宽度,需要减掉
  6170. if (isIE && document['documentMode'] != 9 || UA['opera']) {
  6171. // 类似 offset ie 下的边框处理
  6172. // 如果 offsetParent 为 html ,需要减去默认 2 px == documentElement.clientTop
  6173. // 否则减去 borderTop 其实也是 clientTop
  6174. // http://msdn.microsoft.com/en-us/library/aa752288%28v=vs.85%29.aspx
  6175. // ie<9 注意有时候 elem.offsetParent 为 null ...
  6176. // 比如 DOM.append(DOM.create("<div class='position:absolute'></div>"),document.body)
  6177. offset -= elem.offsetParent && elem.offsetParent['client' + (name == 'left' ? 'Left' : 'Top')]
  6178. || 0;
  6179. }
  6180. val = offset - (PARSEINT(DOM.css(elem, 'margin-' + name)) || 0);
  6181. }
  6182. val += "px";
  6183. }
  6184. return val;
  6185. }
  6186. }
  6187. };
  6188. });
  6189. function swap(elem, options, callback) {
  6190. var old = {};
  6191. // Remember the old values, and insert the new ones
  6192. for (var name in options) {
  6193. old[ name ] = elem[STYLE][ name ];
  6194. elem[STYLE][ name ] = options[ name ];
  6195. }
  6196. callback.call(elem);
  6197. // Revert the old values
  6198. for (name in options) {
  6199. elem[STYLE][ name ] = old[ name ];
  6200. }
  6201. }
  6202. function style(elem, name, val) {
  6203. var style;
  6204. if (elem.nodeType === 3 || elem.nodeType === 8 || !(style = elem[STYLE])) {
  6205. return undefined;
  6206. }
  6207. name = camelCase(name);
  6208. var ret, hook = CUSTOM_STYLES[name];
  6209. name = cssProps[name] || name;
  6210. // setter
  6211. if (val !== undefined) {
  6212. // normalize unsetting
  6213. if (val === null || val === EMPTY) {
  6214. val = EMPTY;
  6215. }
  6216. // number values may need a unit
  6217. else if (!isNaN(Number(val)) && !cssNumber[name]) {
  6218. val += DEFAULT_UNIT;
  6219. }
  6220. if (hook && hook.set) {
  6221. val = hook.set(elem, val);
  6222. }
  6223. if (val !== undefined) {
  6224. // ie 无效值报错
  6225. try {
  6226. style[name] = val;
  6227. } catch (e) {
  6228. S.log("css set error :" + e);
  6229. }
  6230. // #80 fix,font-family
  6231. if (val == EMPTY && style.removeAttribute) {
  6232. style.removeAttribute(name);
  6233. }
  6234. }
  6235. if (!style.cssText) {
  6236. elem.removeAttribute('style');
  6237. }
  6238. return undefined;
  6239. }
  6240. //getter
  6241. else {
  6242. // If a hook was provided get the non-computed value from there
  6243. if (hook && "get" in hook && (ret = hook.get(elem, false)) !== undefined) {
  6244. } else {
  6245. // Otherwise just get the value from the style object
  6246. ret = style[ name ];
  6247. }
  6248. return ret === undefined ? "" : ret;
  6249. }
  6250. }
  6251. /**
  6252. * 得到元素的大小信息
  6253. * @param elem
  6254. * @param name
  6255. * @param {String} [extra] "padding" : (css width) + padding
  6256. * "border" : (css width) + padding + border
  6257. * "margin" : (css width) + padding + border + margin
  6258. */
  6259. function getWH(elem, name, extra) {
  6260. if (S.isWindow(elem)) {
  6261. return name == WIDTH ? DOM.viewportWidth(elem) : DOM.viewportHeight(elem);
  6262. } else if (elem.nodeType == 9) {
  6263. return name == WIDTH ? DOM.docWidth(elem) : DOM.docHeight(elem);
  6264. }
  6265. var which = name === WIDTH ? ['Left', 'Right'] : ['Top', 'Bottom'],
  6266. val = name === WIDTH ? elem.offsetWidth : elem.offsetHeight;
  6267. if (val > 0) {
  6268. if (extra !== "border") {
  6269. S.each(which, function (w) {
  6270. if (!extra) {
  6271. val -= parseFloat(DOM.css(elem, "padding" + w)) || 0;
  6272. }
  6273. if (extra === "margin") {
  6274. val += parseFloat(DOM.css(elem, extra + w)) || 0;
  6275. } else {
  6276. val -= parseFloat(DOM.css(elem, "border" + w + "Width")) || 0;
  6277. }
  6278. });
  6279. }
  6280. return val
  6281. }
  6282. // Fall back to computed then uncomputed css if necessary
  6283. val = DOM._getComputedStyle(elem, name);
  6284. if (val == null || (Number(val)) < 0) {
  6285. val = elem.style[ name ] || 0;
  6286. }
  6287. // Normalize "", auto, and prepare for extra
  6288. val = parseFloat(val) || 0;
  6289. // Add padding, border, margin
  6290. if (extra) {
  6291. S.each(which, function (w) {
  6292. val += parseFloat(DOM.css(elem, "padding" + w)) || 0;
  6293. if (extra !== "padding") {
  6294. val += parseFloat(DOM.css(elem, "border" + w + "Width")) || 0;
  6295. }
  6296. if (extra === "margin") {
  6297. val += parseFloat(DOM.css(elem, extra + w)) || 0;
  6298. }
  6299. });
  6300. }
  6301. return val;
  6302. }
  6303. return DOM;
  6304. }, {
  6305. requires:["dom/base", "ua"]
  6306. });
  6307. /**
  6308. * 2011-12-21
  6309. * - backgroundPositionX, backgroundPositionY firefox/w3c 不支持
  6310. * - w3c 为准,这里不 fix 了
  6311. *
  6312. *
  6313. * 2011-08-19
  6314. * - 调整结构,减少耦合
  6315. * - fix css("height") == auto
  6316. *
  6317. * NOTES:
  6318. * - Opera 下,color 默认返回 #XXYYZZ, 非 rgb(). 目前 jQuery 等类库均忽略此差异,KISSY 也忽略。
  6319. * - Safari 低版本,transparent 会返回为 rgba(0, 0, 0, 0), 考虑低版本才有此 bug, 亦忽略。
  6320. *
  6321. *
  6322. * - getComputedStyle 在 webkit 下,会舍弃小数部分,ie 下会四舍五入,gecko 下直接输出 float 值。
  6323. *
  6324. * - color: blue 继承值,getComputedStyle, 在 ie 下返回 blue, opera 返回 #0000ff, 其它浏览器
  6325. * 返回 rgb(0, 0, 255)
  6326. *
  6327. * - 总之:要使得返回值完全一致是不大可能的,jQuery/ExtJS/KISSY 未“追求完美”。YUI3 做了部分完美处理,但
  6328. * 依旧存在浏览器差异。
  6329. */
  6330. /**
  6331. * @fileOverview dom-traversal
  6332. * @author lifesinger@gmail.com,yiminghe@gmail.com
  6333. */
  6334. KISSY.add('dom/traversal', function (S, DOM, undefined) {
  6335. var isElementNode = DOM._isElementNode,
  6336. CONTAIN_MASK = 16,
  6337. __contains = document.documentElement.contains ?
  6338. function (a, b) {
  6339. if (a.nodeType == DOM.TEXT_NODE) {
  6340. return false;
  6341. }
  6342. var precondition;
  6343. if (b.nodeType == DOM.TEXT_NODE) {
  6344. b = b.parentNode;
  6345. // a 和 b父亲相等也就是返回 true
  6346. precondition = true;
  6347. } else if (b.nodeType == DOM.DOCUMENT_NODE) {
  6348. // b === document
  6349. // 没有任何元素能包含 document
  6350. return false;
  6351. } else {
  6352. // a 和 b 相等返回 false
  6353. precondition = a !== b;
  6354. }
  6355. // !a.contains => a===document
  6356. // 注意原生 contains 判断时 a===b 也返回 true
  6357. return precondition && (a.contains ? a.contains(b) : true);
  6358. } : (
  6359. document.documentElement.compareDocumentPosition ?
  6360. function (a, b) {
  6361. return !!(a.compareDocumentPosition(b) & CONTAIN_MASK);
  6362. } :
  6363. // it can not be true , pathetic browser
  6364. 0
  6365. );
  6366. S.mix(DOM, {
  6367. closest:function (selector, filter, context) {
  6368. return nth(selector, filter, 'parentNode', function (elem) {
  6369. return elem.nodeType != DOM.DOCUMENT_FRAGMENT_NODE;
  6370. }, context, true);
  6371. },
  6372. /**
  6373. * Gets the parent node of the first matched element.
  6374. */
  6375. parent:function (selector, filter, context) {
  6376. return nth(selector, filter, 'parentNode', function (elem) {
  6377. return elem.nodeType != DOM.DOCUMENT_FRAGMENT_NODE;
  6378. }, context);
  6379. },
  6380. first:function (selector, filter) {
  6381. var elem = DOM.get(selector);
  6382. return nth(elem && elem.firstChild, filter, 'nextSibling',
  6383. undefined, undefined, true);
  6384. },
  6385. last:function (selector, filter) {
  6386. var elem = DOM.get(selector);
  6387. return nth(elem && elem.lastChild, filter, 'previousSibling',
  6388. undefined, undefined, true);
  6389. },
  6390. /**
  6391. * Gets the following sibling of the first matched element.
  6392. */
  6393. next:function (selector, filter) {
  6394. return nth(selector, filter, 'nextSibling', undefined);
  6395. },
  6396. /**
  6397. * Gets the preceding sibling of the first matched element.
  6398. */
  6399. prev:function (selector, filter) {
  6400. return nth(selector, filter, 'previousSibling', undefined);
  6401. },
  6402. /**
  6403. * Gets the siblings of the first matched element.
  6404. */
  6405. siblings:function (selector, filter) {
  6406. return getSiblings(selector, filter, true);
  6407. },
  6408. /**
  6409. * Gets the children of the first matched element.
  6410. */
  6411. children:function (selector, filter) {
  6412. return getSiblings(selector, filter, undefined);
  6413. },
  6414. /**
  6415. * Check to see if a DOM node is within another DOM node.
  6416. */
  6417. contains:function (a, b) {
  6418. a = DOM.get(a);
  6419. b = DOM.get(b);
  6420. if (a && b) {
  6421. return __contains(a, b);
  6422. }
  6423. },
  6424. equals:function (n1, n2) {
  6425. n1 = DOM.query(n1);
  6426. n2 = DOM.query(n2);
  6427. if (n1.length != n2.length) {
  6428. return false;
  6429. }
  6430. for (var i = n1.length; i >= 0; i--) {
  6431. if (n1[i] != n2[i]) {
  6432. return false;
  6433. }
  6434. }
  6435. return true;
  6436. }
  6437. });
  6438. // 获取元素 elem 在 direction 方向上满足 filter 的第一个元素
  6439. // filter 可为 number, selector, fn array ,为数组时返回多个
  6440. // direction 可为 parentNode, nextSibling, previousSibling
  6441. // context : 到某个阶段不再查找直接返回
  6442. function nth(elem, filter, direction, extraFilter, context, includeSef) {
  6443. if (!(elem = DOM.get(elem))) {
  6444. return null;
  6445. }
  6446. if (filter === 0) {
  6447. return elem;
  6448. }
  6449. if (!includeSef) {
  6450. elem = elem[direction];
  6451. }
  6452. if (!elem) {
  6453. return null;
  6454. }
  6455. context = (context && DOM.get(context)) || null;
  6456. if (filter === undefined) {
  6457. // 默认取 1
  6458. filter = 1;
  6459. }
  6460. var ret = [],
  6461. isArray = S.isArray(filter),
  6462. fi,
  6463. flen;
  6464. if (S.isNumber(filter)) {
  6465. fi = 0;
  6466. flen = filter;
  6467. filter = function () {
  6468. return ++fi === flen;
  6469. };
  6470. }
  6471. // 概念统一,都是 context 上下文,只过滤子孙节点,自己不管
  6472. while (elem && elem != context) {
  6473. if (isElementNode(elem)
  6474. && testFilter(elem, filter)
  6475. && (!extraFilter || extraFilter(elem))) {
  6476. ret.push(elem);
  6477. if (!isArray) {
  6478. break;
  6479. }
  6480. }
  6481. elem = elem[direction];
  6482. }
  6483. return isArray ? ret : ret[0] || null;
  6484. }
  6485. function testFilter(elem, filter) {
  6486. if (!filter) {
  6487. return true;
  6488. }
  6489. if (S.isArray(filter)) {
  6490. for (var i = 0; i < filter.length; i++) {
  6491. if (DOM.test(elem, filter[i])) {
  6492. return true;
  6493. }
  6494. }
  6495. } else if (DOM.test(elem, filter)) {
  6496. return true;
  6497. }
  6498. return false;
  6499. }
  6500. // 获取元素 elem 的 siblings, 不包括自身
  6501. function getSiblings(selector, filter, parent) {
  6502. var ret = [],
  6503. elem = DOM.get(selector),
  6504. j,
  6505. parentNode = elem,
  6506. next;
  6507. if (elem && parent) {
  6508. parentNode = elem.parentNode;
  6509. }
  6510. if (parentNode) {
  6511. for (j = 0, next = parentNode.firstChild;
  6512. next;
  6513. next = next.nextSibling) {
  6514. if (isElementNode(next)
  6515. && next !== elem
  6516. && (!filter || DOM.test(next, filter))) {
  6517. ret[j++] = next;
  6518. }
  6519. }
  6520. }
  6521. return ret;
  6522. }
  6523. return DOM;
  6524. }, {
  6525. requires:["./base"]
  6526. });
  6527. /**
  6528. * 2011-08
  6529. * - 添加 closest , first ,last 完全摆脱原生属性
  6530. *
  6531. * NOTES:
  6532. * - jquery does not return null ,it only returns empty array , but kissy does.
  6533. *
  6534. * - api 的设计上,没有跟随 jQuery. 一是为了和其他 api 一致,保持 first-all 原则。二是
  6535. * 遵循 8/2 原则,用尽可能少的代码满足用户最常用的功能。
  6536. *
  6537. */
  6538. /*
  6539. Copyright 2012, KISSY UI Library v1.30dev
  6540. MIT Licensed
  6541. build time: Jan 5 21:11
  6542. */
  6543. /**
  6544. * @fileOverview responsible for registering event
  6545. * @author yiminghe@gmail.com
  6546. */
  6547. KISSY.add("event/add", function (S, Event, DOM, Utils, EventObject, handle, _data, specials) {
  6548. var simpleAdd = Utils.simpleAdd,
  6549. isValidTarget = Utils.isValidTarget,
  6550. isIdenticalHandler = Utils.isIdenticalHandler;
  6551. /**
  6552. * dom node need eventHandler attached to dom node
  6553. */
  6554. function addDomEvent(target, type, eventHandler, handlers, handleObj) {
  6555. var special = specials[type] || {};
  6556. // 第一次注册该事件,dom 节点才需要注册 dom 事件
  6557. if (!handlers.length &&
  6558. (!special.setup || special.setup.call(target) === false)) {
  6559. simpleAdd(target, type, eventHandler)
  6560. }
  6561. if (special.add) {
  6562. special.add.call(target, handleObj);
  6563. }
  6564. }
  6565. /**
  6566. * @exports Event as Event
  6567. */
  6568. S.mix(Event,
  6569. /**
  6570. * @lends Event
  6571. */
  6572. {
  6573. // single type , single target , fixed native
  6574. __add:function (isNativeTarget, target, type, fn, scope) {
  6575. var typedGroups = Utils.getTypedGroups(type);
  6576. type = typedGroups[0];
  6577. var groups = typedGroups[1],
  6578. eventDesc,
  6579. data,
  6580. s = specials[type],
  6581. // in case overwrite by delegateFix/onFix in specials events
  6582. // (mouseenter/leave,focusin/out)
  6583. originalType,
  6584. last,
  6585. selector;
  6586. if (S.isObject(fn)) {
  6587. last = fn.last;
  6588. scope = fn.scope;
  6589. data = fn.data;
  6590. selector = fn.selector;
  6591. fn = fn.fn;
  6592. if (selector) {
  6593. if (s && s['delegateFix']) {
  6594. originalType = type;
  6595. type = s['delegateFix'];
  6596. }
  6597. }
  6598. }
  6599. if (!selector) {
  6600. // when on mouseenter , it's actually on mouseover , and handlers is saved with mouseover!
  6601. // TODO need evaluate!
  6602. if (s && s['onFix']) {
  6603. originalType = type;
  6604. type = s['onFix'];
  6605. }
  6606. }
  6607. // 不是有效的 target 或 参数不对
  6608. if (!type ||
  6609. !target ||
  6610. !S.isFunction(fn) ||
  6611. (isNativeTarget && !isValidTarget(target))) {
  6612. return;
  6613. }
  6614. // 获取事件描述
  6615. eventDesc = Event._data(target);
  6616. if (!eventDesc) {
  6617. _data._data(target, eventDesc = {});
  6618. }
  6619. //事件 listeners , similar to eventListeners in DOM3 Events
  6620. var events = eventDesc.events = eventDesc.events || {},
  6621. handlers = events[type] = events[type] || [],
  6622. handleObj = {
  6623. fn:fn,
  6624. scope:scope,
  6625. selector:selector,
  6626. last:last,
  6627. data:data,
  6628. groups:groups,
  6629. originalType:originalType
  6630. },
  6631. eventHandler = eventDesc.handler;
  6632. // 该元素没有 handler ,并且该元素是 dom 节点时才需要注册 dom 事件
  6633. if (!eventHandler) {
  6634. eventHandler = eventDesc.handler = function (event, data) {
  6635. // 是经过 fire 手动调用而浏览器同步触发导致的,就不要再次触发了,
  6636. // 已经在 fire 中 bubble 过一次了
  6637. // incase after page has unloaded
  6638. if (typeof KISSY == "undefined" ||
  6639. event && event.type == Utils.Event_Triggered) {
  6640. return;
  6641. }
  6642. var currentTarget = eventHandler.target, type;
  6643. if (!event || !event.fixed) {
  6644. event = new EventObject(currentTarget, event);
  6645. }
  6646. type = event.type;
  6647. if (S.isPlainObject(data)) {
  6648. S.mix(event, data);
  6649. }
  6650. // protect type
  6651. if (type) {
  6652. event.type = type;
  6653. }
  6654. return handle(currentTarget, event);
  6655. };
  6656. // as for native dom event , this represents currentTarget !
  6657. eventHandler.target = target;
  6658. }
  6659. for (var i = handlers.length - 1; i >= 0; --i) {
  6660. /**
  6661. * If multiple identical EventListeners are registered on the same EventTarget
  6662. * with the same parameters the duplicate instances are discarded.
  6663. * They do not cause the EventListener to be called twice
  6664. * and since they are discarded
  6665. * they do not need to be removed with the removeEventListener method.
  6666. */
  6667. if (isIdenticalHandler(handlers[i], handleObj, target)) {
  6668. return;
  6669. }
  6670. }
  6671. if (isNativeTarget) {
  6672. addDomEvent(target, type, eventHandler, handlers, handleObj);
  6673. //nullify to prevent memory leak in ie ?
  6674. target = null;
  6675. }
  6676. // 增加 listener
  6677. if (selector) {
  6678. var delegateIndex = handlers.delegateCount
  6679. = handlers.delegateCount || 0;
  6680. handlers.splice(delegateIndex, 0, handleObj);
  6681. handlers.delegateCount++;
  6682. } else {
  6683. handlers.lastCount = handlers.lastCount || 0;
  6684. if (last) {
  6685. handlers.push(handleObj);
  6686. handlers.lastCount++;
  6687. } else {
  6688. handlers.splice(handlers.length - handlers.lastCount,
  6689. 0, handleObj);
  6690. }
  6691. }
  6692. },
  6693. /**
  6694. * Adds an event listener.similar to addEventListener in DOM3 Events
  6695. * @param targets KISSY selector
  6696. * @param type {String} The type of event to append.
  6697. * @param fn {Function|Object} The event handler/listener.
  6698. * @param fn.scope
  6699. * @param fn.selector
  6700. * @param fn.fn
  6701. * @param {Object} [scope] The scope (this reference) in which the handler function is executed.
  6702. */
  6703. add:function (targets, type, fn, scope) {
  6704. type = S.trim(type);
  6705. // data : 附加在回调后面的数据,delegate 检查使用
  6706. // remove 时 data 相等(指向同一对象或者定义了 equals 比较函数)
  6707. if (Utils.batchForType(Event.add, targets, type, fn, scope)) {
  6708. return targets;
  6709. }
  6710. targets=DOM.query(targets);
  6711. for(var i=targets.length-1;i>=0;i--){
  6712. Event.__add(true, targets[i], type, fn, scope);
  6713. }
  6714. return targets;
  6715. }
  6716. });
  6717. }, {
  6718. requires:['./base', 'dom', './utils', './object', './handle', './data', './special']
  6719. });/**
  6720. * @fileOverview scalable event framework for kissy (refer DOM3 Events)
  6721. * how to fire event just like browser?
  6722. * @author yiminghe@gmail.com,lifesinger@gmail.com
  6723. */
  6724. KISSY.add('event/base', function (S, DOM, EventObject, Utils, handle, _data, special) {
  6725. var isValidTarget = Utils.isValidTarget,
  6726. splitAndRun = Utils.splitAndRun,
  6727. nodeName = DOM._nodeName,
  6728. trim = S.trim,
  6729. TRIGGERED_NONE = Utils.TRIGGERED_NONE;
  6730. /**
  6731. * @namespace
  6732. * @name Event
  6733. */
  6734. var Event =
  6735. /**
  6736. * @lends Event
  6737. */
  6738. {
  6739. _clone:function (src, dest) {
  6740. if (dest.nodeType !== DOM.ELEMENT_NODE ||
  6741. !_data._hasData(src)) {
  6742. return;
  6743. }
  6744. var eventDesc = _data._data(src),
  6745. events = eventDesc.events;
  6746. S.each(events, function (handlers, type) {
  6747. S.each(handlers, function (handler) {
  6748. // scope undefined 时不能写死在 handlers 中,否则不能保证 clone 时的 this
  6749. Event.on(dest, type, {
  6750. fn:handler.fn,
  6751. scope:handler.scope,
  6752. data:handler.data,
  6753. originalType:handler.originalType,
  6754. selector:handler.selector
  6755. });
  6756. });
  6757. });
  6758. },
  6759. /**
  6760. * fire event,simulate bubble in browser. similar to dispatchEvent in DOM3 Events
  6761. * @memberOf Event
  6762. * @param targets html nodes
  6763. * @param {String|Event.Object} eventType event type
  6764. * @param [eventData] additional event data
  6765. * @param {boolean} [onlyHandlers] only fire handlers
  6766. * @returns {boolean} The return value of fire/dispatchEvent indicates
  6767. * whether any of the listeners which handled the event called preventDefault.
  6768. * If preventDefault was called the value is false, else the value is true.
  6769. */
  6770. fire:function (targets, eventType, eventData, onlyHandlers/*internal usage*/) {
  6771. var ret = true, r;
  6772. // custom event firing moved to target.js
  6773. eventData = eventData || {};
  6774. if (S.isString(eventType)) {
  6775. eventType = trim(eventType);
  6776. if (eventType.indexOf(" ") > -1) {
  6777. splitAndRun(eventType, function (t) {
  6778. r = Event.fire(targets, t, eventData, onlyHandlers);
  6779. if (ret !== false) {
  6780. ret = r;
  6781. }
  6782. });
  6783. return ret;
  6784. }
  6785. // protect event type
  6786. eventData.type = eventType;
  6787. } else if (eventType instanceof EventObject) {
  6788. eventData = eventType;
  6789. eventType = eventData.type;
  6790. }
  6791. var typedGroups = Utils.getTypedGroups(eventType),
  6792. _ks_groups = typedGroups[1];
  6793. if (_ks_groups) {
  6794. _ks_groups = Utils.getGroupsRe(_ks_groups);
  6795. }
  6796. eventType = typedGroups[0];
  6797. S.mix(eventData, {
  6798. type:eventType,
  6799. _ks_groups:_ks_groups
  6800. });
  6801. targets = DOM.query(targets);
  6802. for (var i = targets.length - 1; i >= 0; i--) {
  6803. r = fireDOMEvent(targets[i], eventType, eventData, onlyHandlers);
  6804. if (ret !== false) {
  6805. ret = r;
  6806. }
  6807. }
  6808. return ret;
  6809. },
  6810. /**
  6811. * does not cause default behavior to occur
  6812. * does not bubble up the DOM hierarchy
  6813. * @param targets
  6814. * @param {Event.Object | String} eventType
  6815. * @param [eventData]
  6816. */
  6817. fireHandler:function (targets, eventType, eventData) {
  6818. return Event.fire(targets, eventType, eventData, 1);
  6819. }
  6820. };
  6821. /**
  6822. * fire dom event from bottom to up , emulate dispatchEvent in DOM3 Events
  6823. * @return boolean The return value of dispatchEvent indicates
  6824. * whether any of the listeners which handled the event called preventDefault.
  6825. * If preventDefault was called the value is false, else the value is true.
  6826. */
  6827. function fireDOMEvent(target, eventType, eventData, onlyHandlers) {
  6828. if (!isValidTarget(target)) {
  6829. return false;
  6830. }
  6831. var s = special[eventType];
  6832. // TODO bug : when fire mouseenter , it also fire mouseover in firefox/chrome
  6833. if (s && s['onFix']) {
  6834. eventType = s['onFix'];
  6835. }
  6836. var event,
  6837. ret = true;
  6838. if (eventData instanceof EventObject) {
  6839. event = eventData;
  6840. } else {
  6841. event = new EventObject(target, undefined, eventType);
  6842. S.mix(event, eventData);
  6843. }
  6844. /**
  6845. * identify event as fired manually
  6846. */
  6847. event._ks_fired = 1;
  6848. /*
  6849. The target of the event is the EventTarget on which dispatchEvent is called.
  6850. */
  6851. // TODO: protect target , but incompatible
  6852. // event.target=target;
  6853. // protect type
  6854. event.type = eventType;
  6855. // onlyHandlers is equal to event.halt()
  6856. // but we can not call event.halt()
  6857. // because handle will check event.isPropagationStopped
  6858. var cur = target,
  6859. t,
  6860. ontype = "on" + eventType;
  6861. //bubble up dom tree
  6862. do {
  6863. event.currentTarget = cur;
  6864. t = handle(cur, event);
  6865. if (ret !== false) {
  6866. ret = t;
  6867. }
  6868. // Trigger an inline bound script
  6869. if (cur[ ontype ] &&
  6870. cur[ ontype ].call(cur) === false) {
  6871. event.preventDefault();
  6872. }
  6873. // Bubble up to document, then to window
  6874. cur = cur.parentNode ||
  6875. cur.ownerDocument ||
  6876. cur === target.ownerDocument && window;
  6877. } while (!onlyHandlers && cur && !event.isPropagationStopped);
  6878. if (!onlyHandlers && !event.isDefaultPrevented) {
  6879. if (!(eventType === "click" &&
  6880. nodeName(target, "a"))) {
  6881. var old;
  6882. try {
  6883. // execute default action on dom node
  6884. // so exclude window
  6885. // exclude focus/blue on hidden element
  6886. if (ontype &&
  6887. target[ eventType ] &&
  6888. (
  6889. (eventType !== "focus" && eventType !== "blur") ||
  6890. target.offsetWidth !== 0
  6891. ) &&
  6892. !S.isWindow(target)) {
  6893. // Don't re-trigger an onFOO event when we call its FOO() method
  6894. old = target[ ontype ];
  6895. if (old) {
  6896. target[ ontype ] = null;
  6897. }
  6898. // 记录当前 trigger 触发
  6899. Utils.Event_Triggered = eventType;
  6900. // 只触发默认事件,而不要执行绑定的用户回调
  6901. // 同步触发
  6902. target[ eventType ]();
  6903. }
  6904. } catch (ieError) {
  6905. S.log("trigger action error : ");
  6906. S.log(ieError);
  6907. }
  6908. if (old) {
  6909. target[ ontype ] = old;
  6910. }
  6911. Utils.Event_Triggered = TRIGGERED_NONE;
  6912. }
  6913. }
  6914. return ret;
  6915. }
  6916. return Event;
  6917. }, {
  6918. requires:["dom", "./object", "./utils", './handle', './data', './special']
  6919. });
  6920. /**
  6921. * yiminghe@gmail.com : 2011-12-15
  6922. * - 重构,粒度更细,新的架构
  6923. *
  6924. * 2011-11-24
  6925. * - 自定义事件和 dom 事件操作彻底分离
  6926. * - TODO: group event from DOM3 Event
  6927. *
  6928. * 2011-06-07
  6929. * - refer : http://www.w3.org/TR/2001/WD-DOM-Level-3-Events-20010823/events.html
  6930. * - 重构
  6931. * - eventHandler 一个元素一个而不是一个元素一个事件一个,节省内存
  6932. * - 减少闭包使用,prevent ie 内存泄露?
  6933. * - 增加 fire ,模拟冒泡处理 dom 事件
  6934. */
  6935. /**
  6936. * @fileOverview change bubble and checkbox/radio fix patch for ie<9
  6937. * @author yiminghe@gmail.com
  6938. */
  6939. KISSY.add("event/change", function (S, UA, Event, DOM, special) {
  6940. var mode = document['documentMode'];
  6941. if (UA['ie'] && (UA['ie'] < 9 || (mode && mode < 9))) {
  6942. var rformElems = /^(?:textarea|input|select)$/i;
  6943. function isFormElement(n) {
  6944. return rformElems.test(n.nodeName);
  6945. }
  6946. function isCheckBoxOrRadio(el) {
  6947. var type = el.type;
  6948. return type == "checkbox" || type == "radio";
  6949. }
  6950. special['change'] = {
  6951. setup:function () {
  6952. var el = this;
  6953. if (isFormElement(el)) {
  6954. // checkbox/radio only fires change when blur in ie<9
  6955. // so use another technique from jquery
  6956. if (isCheckBoxOrRadio(el)) {
  6957. // change in ie<9
  6958. // change = propertychange -> click
  6959. Event.on(el, "propertychange", propertyChange);
  6960. Event.on(el, "click", onClick);
  6961. } else {
  6962. // other form elements use native , do not bubble
  6963. return false;
  6964. }
  6965. } else {
  6966. // if bind on parentNode ,lazy bind change event to its form elements
  6967. // note event order : beforeactivate -> change
  6968. // note 2: checkbox/radio is exceptional
  6969. Event.on(el, "beforeactivate", beforeActivate);
  6970. }
  6971. },
  6972. tearDown:function () {
  6973. var el = this;
  6974. if (isFormElement(el)) {
  6975. if (isCheckBoxOrRadio(el)) {
  6976. Event.remove(el, "propertychange", propertyChange);
  6977. Event.remove(el, "click", onClick);
  6978. } else {
  6979. return false;
  6980. }
  6981. } else {
  6982. Event.remove(el, "beforeactivate", beforeActivate);
  6983. S.each(DOM.query("textarea,input,select", el),function (fel) {
  6984. if (fel.__changeHandler) {
  6985. fel.__changeHandler = 0;
  6986. Event.remove(fel, "change", {fn:changeHandler, last:1});
  6987. }
  6988. });
  6989. }
  6990. }
  6991. };
  6992. function propertyChange(e) {
  6993. if (e.originalEvent.propertyName == "checked") {
  6994. this.__changed = 1;
  6995. }
  6996. }
  6997. function onClick(e) {
  6998. if (this.__changed) {
  6999. this.__changed = 0;
  7000. // fire from itself
  7001. Event.fire(this, "change", e);
  7002. }
  7003. }
  7004. function beforeActivate(e) {
  7005. var t = e.target;
  7006. if (isFormElement(t) && !t.__changeHandler) {
  7007. t.__changeHandler = 1;
  7008. // lazy bind change , always as last handler among user's handlers
  7009. Event.on(t, "change", {fn:changeHandler, last:1});
  7010. }
  7011. }
  7012. function changeHandler(e) {
  7013. var fel = this;
  7014. if (
  7015. // in case stopped by user's callback,same with submit
  7016. // http://bugs.jquery.com/ticket/11049
  7017. // see : test/change/bubble.html
  7018. e.isPropagationStopped ||
  7019. // checkbox/radio already bubble using another technique
  7020. isCheckBoxOrRadio(fel)) {
  7021. return;
  7022. }
  7023. var p;
  7024. if (p = fel.parentNode) {
  7025. // fire from parent , itself is handled natively
  7026. Event.fire(p, "change", e);
  7027. }
  7028. }
  7029. }
  7030. }, {
  7031. requires:["ua", "./base", "dom", './special']
  7032. });/**
  7033. * @fileOverview for other kissy core usage
  7034. * @author yiminghe@gmail.com
  7035. */
  7036. KISSY.add("event/data", function (S, DOM, Utils) {
  7037. var EVENT_GUID = Utils.EVENT_GUID,
  7038. data,
  7039. makeArray = S.makeArray;
  7040. data = {
  7041. _hasData:function (elem) {
  7042. return DOM.hasData(elem, EVENT_GUID);
  7043. },
  7044. _data:function (elem) {
  7045. var args = makeArray(arguments);
  7046. args.splice(1, 0, EVENT_GUID);
  7047. return DOM.data.apply(DOM, args);
  7048. },
  7049. _removeData:function (elem) {
  7050. var args = makeArray(arguments);
  7051. args.splice(1, 0, EVENT_GUID);
  7052. return DOM.removeData.apply(DOM, args);
  7053. }
  7054. };
  7055. return data;
  7056. }, {
  7057. requires:['dom', './utils']
  7058. });/**
  7059. * @fileOverview KISSY Scalable Event Framework
  7060. */
  7061. KISSY.add("event", function (S, _data, KeyCodes, Event, Target, Object) {
  7062. S.mix(Event, {
  7063. KeyCodes:KeyCodes,
  7064. Target:Target,
  7065. Object:Object,
  7066. on:Event.add,
  7067. detach:Event.remove,
  7068. /**
  7069. *
  7070. * @param targets
  7071. * @param {String} eventType
  7072. * @param {String|Function} selector
  7073. * @param {Object|Function} fn
  7074. * @param [scope]
  7075. */
  7076. delegate:function (targets, eventType, selector, fn, scope) {
  7077. return Event.add(targets, eventType, {
  7078. fn:fn,
  7079. scope:scope,
  7080. selector:selector
  7081. });
  7082. },
  7083. /**
  7084. *
  7085. * @param targets
  7086. * @param {String} [eventType]
  7087. * @param {String|Function} [selector]
  7088. * @param {Object|Function} [fn]
  7089. * @param [scope]
  7090. */
  7091. undelegate:function (targets, eventType, selector, fn, scope) {
  7092. return Event.remove(targets, eventType, {
  7093. fn:fn,
  7094. scope:scope,
  7095. selector:selector
  7096. });
  7097. }
  7098. });
  7099. S.mix(Event, _data);
  7100. return Event;
  7101. }, {
  7102. requires:[
  7103. "event/data",
  7104. "event/keycodes",
  7105. "event/base",
  7106. "event/target",
  7107. "event/object",
  7108. "event/focusin",
  7109. "event/hashchange",
  7110. "event/valuechange",
  7111. "event/mouseenter",
  7112. "event/submit",
  7113. "event/change",
  7114. "event/mousewheel",
  7115. "event/add",
  7116. "event/remove"
  7117. ]
  7118. });/**
  7119. * @fileOverview event-focusin
  7120. * @author yiminghe@gmail.com
  7121. */
  7122. KISSY.add('event/focusin', function (S, UA, Event, special) {
  7123. // 让非 IE 浏览器支持 focusin/focusout
  7124. if (!UA['ie']) {
  7125. S.each([
  7126. { name:'focusin', fix:'focus' },
  7127. { name:'focusout', fix:'blur' }
  7128. ], function (o) {
  7129. var attaches = 0;
  7130. special[o.name] = {
  7131. // 统一在 document 上 capture focus/blur 事件,然后模拟冒泡 fire 出来
  7132. // 达到和 focusin 一样的效果 focusin -> focus
  7133. // refer: http://yiminghe.iteye.com/blog/813255
  7134. setup:function () {
  7135. if (attaches++ === 0) {
  7136. document.addEventListener(o.fix, handler, true);
  7137. }
  7138. },
  7139. tearDown:function () {
  7140. if (--attaches === 0) {
  7141. document.removeEventListener(o.fix, handler, true);
  7142. }
  7143. }
  7144. };
  7145. function handler(event) {
  7146. var target = event.target;
  7147. return Event.fire(target, o.name);
  7148. }
  7149. });
  7150. }
  7151. special["focus"] = {
  7152. delegateFix:"focusin"
  7153. };
  7154. special["blur"] = {
  7155. delegateFix:"focusout"
  7156. };
  7157. return Event;
  7158. }, {
  7159. requires:["ua", "./base", './special']
  7160. });
  7161. /**
  7162. * 承玉:2011-06-07
  7163. * - refactor to jquery , 更加合理的模拟冒泡顺序,子元素先出触发,父元素后触发
  7164. *
  7165. * NOTES:
  7166. * - webkit 和 opera 已支持 DOMFocusIn/DOMFocusOut 事件,但上面的写法已经能达到预期效果,暂时不考虑原生支持。
  7167. */
  7168. /**
  7169. * @fileOverview responsible for handling event from browser to KISSY Event
  7170. * @author yiminghe@gmail.com
  7171. */
  7172. KISSY.add("event/handle", function (S, DOM, _data, special) {
  7173. function getEvents(target) {
  7174. // 获取事件描述
  7175. var eventDesc = _data._data(target);
  7176. return eventDesc && eventDesc.events;
  7177. }
  7178. function getHandlers(target, type) {
  7179. var events = getEvents(target) || {};
  7180. return events[type] || [];
  7181. }
  7182. return function (currentTarget, event) {
  7183. /*
  7184. As some listeners may remove themselves from the
  7185. event, the original array length is dynamic. So,
  7186. let's make a copy of all listeners, so we are
  7187. sure we'll call all of them.
  7188. */
  7189. /**
  7190. * DOM3 Events: EventListenerList objects in the DOM are live. ??
  7191. */
  7192. var handlers = getHandlers(currentTarget, event.type),
  7193. target = event.target,
  7194. currentTarget0,
  7195. allHandlers = [],
  7196. ret,
  7197. gRet,
  7198. handlerObj,
  7199. i,
  7200. j,
  7201. delegateCount = handlers.delegateCount || 0,
  7202. len,
  7203. currentTargetHandlers,
  7204. currentTargetHandler,
  7205. handler;
  7206. // collect delegated handlers and corresponding element
  7207. if (delegateCount &&
  7208. // by jq
  7209. // Avoid disabled elements in IE (#6911)
  7210. // non-left-click bubbling in Firefox (#3861),firefox 8 fix it
  7211. !target.disabled) {
  7212. while (target != currentTarget) {
  7213. currentTargetHandlers = [];
  7214. for (i = 0; i < delegateCount; i++) {
  7215. handler = handlers[i];
  7216. if (DOM.test(target, handler.selector)) {
  7217. currentTargetHandlers.push(handler);
  7218. }
  7219. }
  7220. if (currentTargetHandlers.length) {
  7221. allHandlers.push({
  7222. currentTarget:target,
  7223. "currentTargetHandlers":currentTargetHandlers
  7224. });
  7225. }
  7226. target = target.parentNode || currentTarget;
  7227. }
  7228. }
  7229. // root node's handlers is placed at end position of add handlers
  7230. // in case child node stopPropagation of root node's handlers
  7231. allHandlers.push({
  7232. currentTarget:currentTarget,
  7233. currentTargetHandlers:handlers.slice(delegateCount)
  7234. });
  7235. // backup eventType
  7236. var eventType = event.type,
  7237. s,
  7238. t,
  7239. _ks_groups = event._ks_groups;
  7240. for (i = 0, len = allHandlers.length;
  7241. !event.isPropagationStopped && i < len;
  7242. ++i) {
  7243. handlerObj = allHandlers[i];
  7244. currentTargetHandlers = handlerObj.currentTargetHandlers;
  7245. currentTarget0 = handlerObj.currentTarget;
  7246. event.currentTarget = currentTarget0;
  7247. for (j = 0; !event.isImmediatePropagationStopped &&
  7248. j < currentTargetHandlers.length;
  7249. j++) {
  7250. currentTargetHandler = currentTargetHandlers[j];
  7251. // handler's group does not match specified groups (at fire step)
  7252. if (_ks_groups &&
  7253. (!currentTargetHandler.groups ||
  7254. !(currentTargetHandler.groups.match(_ks_groups)))) {
  7255. continue;
  7256. }
  7257. var data = currentTargetHandler.data;
  7258. // restore originalType if involving delegate/onFix handlers
  7259. event.type = currentTargetHandler.originalType || eventType;
  7260. // scope undefined 时不能写死在 listener 中,否则不能保证 clone 时的 this
  7261. if ((s = special[event.type]) && s.handle) {
  7262. t = s.handle(event, currentTargetHandler, data);
  7263. // can handle
  7264. if (t.length > 0) {
  7265. ret = t[0];
  7266. }
  7267. } else {
  7268. ret = currentTargetHandler.fn.call(
  7269. currentTargetHandler.scope || currentTarget,
  7270. event, data
  7271. );
  7272. }
  7273. // 和 jQuery 逻辑保持一致
  7274. // 有一个 false,最终结果就是 false
  7275. // 否则等于最后一个返回值
  7276. if (gRet !== false) {
  7277. gRet = ret;
  7278. }
  7279. // return false 等价 preventDefault + stopProgation
  7280. if (ret === false) {
  7281. event.halt();
  7282. }
  7283. }
  7284. }
  7285. // fire 时判断如果 preventDefault,则返回 false 否则返回 true
  7286. // 这里返回值意义不同
  7287. return gRet;
  7288. }
  7289. }, {
  7290. requires:['dom', './data', './special']
  7291. });/**
  7292. * @fileOverview event-hashchange
  7293. * @author yiminghe@gmail.com , xiaomacji@gmail.com
  7294. */
  7295. KISSY.add('event/hashchange', function (S, Event, DOM, UA, special) {
  7296. var doc = document,
  7297. docMode = doc['documentMode'],
  7298. ie = docMode || UA['ie'],
  7299. HASH_CHANGE = 'hashchange';
  7300. // ie8 支持 hashchange
  7301. // 但IE8以上切换浏览器模式到IE7(兼容模式),会导致 'onhashchange' in window === true,但是不触发事件
  7302. // 1. 不支持 hashchange 事件,支持 hash 导航(opera??):定时器监控
  7303. // 2. 不支持 hashchange 事件,不支持 hash 导航(ie67) : iframe + 定时器
  7304. if ((!( 'on' + HASH_CHANGE in window)) || ie && ie < 8) {
  7305. function getIframeDoc(iframe) {
  7306. return iframe.contentWindow.document;
  7307. }
  7308. var POLL_INTERVAL = 50,
  7309. win = window,
  7310. IFRAME_TEMPLATE = "<html><head><title>" + (doc.title || "") +
  7311. " - {hash}</title>{head}</head><body>{hash}</body></html>",
  7312. getHash = function () {
  7313. // 不能 location.hash
  7314. // http://xx.com/#yy?z=1
  7315. // ie6 => location.hash = #yy
  7316. // 其他浏览器 => location.hash = #yy?z=1
  7317. var url = location.href;
  7318. return '#' + url.replace(/^[^#]*#?(.*)$/, '$1');
  7319. },
  7320. timer,
  7321. // 用于定时器检测,上次定时器记录的 hash 值
  7322. lastHash,
  7323. poll = function () {
  7324. var hash = getHash();
  7325. if (hash !== lastHash) {
  7326. // S.log("poll success :" + hash + " :" + lastHash);
  7327. // 通知完调用者 hashchange 事件前设置 lastHash
  7328. lastHash = hash;
  7329. // ie<8 同步 : hashChange -> onIframeLoad
  7330. hashChange(hash);
  7331. }
  7332. timer = setTimeout(poll, POLL_INTERVAL);
  7333. },
  7334. hashChange = ie && ie < 8 ? function (hash) {
  7335. // S.log("set iframe html :" + hash);
  7336. var html = S.substitute(IFRAME_TEMPLATE, {
  7337. hash:hash,
  7338. // 一定要加哦
  7339. head:DOM._isCustomDomain() ? "<script>document.domain = '" +
  7340. doc.domain
  7341. + "';</script>" : ""
  7342. }),
  7343. iframeDoc = getIframeDoc(iframe);
  7344. try {
  7345. // 写入历史 hash
  7346. iframeDoc.open();
  7347. // 取时要用 innerText !!
  7348. // 否则取 innerHtml 会因为 escapeHtml 导置 body.innerHTMl != hash
  7349. iframeDoc.write(html);
  7350. iframeDoc.close();
  7351. // 立刻同步调用 onIframeLoad !!!!
  7352. } catch (e) {
  7353. // S.log('doc write error : ', 'error');
  7354. // S.log(e, 'error');
  7355. }
  7356. } : function () {
  7357. notifyHashChange();
  7358. },
  7359. notifyHashChange = function () {
  7360. // S.log("hash changed : " + getHash());
  7361. Event.fire(win, HASH_CHANGE);
  7362. },
  7363. setup = function () {
  7364. if (!timer) {
  7365. poll();
  7366. }
  7367. },
  7368. tearDown = function () {
  7369. timer && clearTimeout(timer);
  7370. timer = 0;
  7371. },
  7372. iframe;
  7373. // ie6, 7, 覆盖一些function
  7374. if (ie < 8) {
  7375. /*
  7376. 前进后退 : start -> notifyHashChange
  7377. 直接输入 : poll -> hashChange -> start
  7378. iframe 内容和 url 同步
  7379. */
  7380. setup = function () {
  7381. if (!iframe) {
  7382. var iframeSrc = DOM._genEmptyIframeSrc();
  7383. //http://www.paciellogroup.com/blog/?p=604
  7384. iframe = DOM.create('<iframe ' +
  7385. (iframeSrc ? 'src="' + iframeSrc + '"' : '') +
  7386. ' style="display: none" ' +
  7387. 'height="0" ' +
  7388. 'width="0" ' +
  7389. 'tabindex="-1" ' +
  7390. 'title="empty"/>');
  7391. // Append the iframe to the documentElement rather than the body.
  7392. // Keeping it outside the body prevents scrolling on the initial
  7393. // page load
  7394. DOM.prepend(iframe, doc.documentElement);
  7395. // init,第一次触发,以后都是 onIframeLoad
  7396. Event.add(iframe, "load", function () {
  7397. Event.remove(iframe, "load");
  7398. // Update the iframe with the initial location hash, if any. This
  7399. // will create an initial history entry that the user can return to
  7400. // after the state has changed.
  7401. hashChange(getHash());
  7402. Event.add(iframe, "load", onIframeLoad);
  7403. poll();
  7404. });
  7405. // Whenever `document.title` changes, update the Iframe's title to
  7406. // prettify the back/next history menu entries. Since IE sometimes
  7407. // errors with "Unspecified error" the very first time this is set
  7408. // (yes, very useful) wrap this with a try/catch block.
  7409. doc.onpropertychange = function () {
  7410. try {
  7411. if (event.propertyName === 'title') {
  7412. getIframeDoc(iframe).title =
  7413. doc.title + " - " + getHash();
  7414. }
  7415. } catch (e) {
  7416. }
  7417. };
  7418. /*
  7419. 前进后退 : onIframeLoad -> 触发
  7420. 直接输入 : timer -> hashChange -> onIframeLoad -> 触发
  7421. 触发统一在 start(load)
  7422. iframe 内容和 url 同步
  7423. */
  7424. function onIframeLoad() {
  7425. // S.log('iframe start load..');
  7426. // 2011.11.02 note: 不能用 innerHtml 会自动转义!!
  7427. // #/x?z=1&y=2 => #/x?z=1&amp;y=2
  7428. var c = S.trim(getIframeDoc(iframe).body.innerText),
  7429. ch = getHash();
  7430. // 后退时不等
  7431. // 定时器调用 hashChange() 修改 iframe 同步调用过来的(手动改变 location)则相等
  7432. if (c != ch) {
  7433. S.log("set loc hash :" + c);
  7434. location.hash = c;
  7435. // 使lasthash为 iframe 历史, 不然重新写iframe,
  7436. // 会导致最新状态(丢失前进状态)
  7437. // 后退则立即触发 hashchange,
  7438. // 并更新定时器记录的上个 hash 值
  7439. lastHash = c;
  7440. }
  7441. notifyHashChange();
  7442. }
  7443. }
  7444. };
  7445. tearDown = function () {
  7446. timer && clearTimeout(timer);
  7447. timer = 0;
  7448. Event.detach(iframe);
  7449. DOM.remove(iframe);
  7450. iframe = 0;
  7451. };
  7452. }
  7453. special[HASH_CHANGE] = {
  7454. setup:function () {
  7455. if (this !== win) {
  7456. return;
  7457. }
  7458. // 第一次启动 hashchange 时取一下,不能类库载入后立即取
  7459. // 防止类库嵌入后,手动修改过 hash,
  7460. lastHash = getHash();
  7461. // 不用注册 dom 事件
  7462. setup();
  7463. },
  7464. tearDown:function () {
  7465. if (this !== win) {
  7466. return;
  7467. }
  7468. tearDown();
  7469. }
  7470. };
  7471. }
  7472. }, {
  7473. requires:["./base", "dom", "ua", "./special"]
  7474. });
  7475. /**
  7476. * 已知 bug :
  7477. * - ie67 有时后退后取得的 location.hash 不和地址栏一致,导致必须后退两次才能触发 hashchange
  7478. *
  7479. * v1 : 2010-12-29
  7480. * v1.1: 支持非IE,但不支持onhashchange事件的浏览器(例如低版本的firefox、safari)
  7481. * refer : http://yiminghe.javaeye.com/blog/377867
  7482. * https://github.com/cowboy/jquery-hashchange
  7483. *//**
  7484. * @fileOverview some keycodes definition and utils from closure-library
  7485. * @author yiminghe@gmail.com
  7486. */
  7487. KISSY.add("event/keycodes", function() {
  7488. var KeyCodes = {
  7489. MAC_ENTER: 3,
  7490. BACKSPACE: 8,
  7491. TAB: 9,
  7492. NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac
  7493. ENTER: 13,
  7494. SHIFT: 16,
  7495. CTRL: 17,
  7496. ALT: 18,
  7497. PAUSE: 19,
  7498. CAPS_LOCK: 20,
  7499. ESC: 27,
  7500. SPACE: 32,
  7501. PAGE_UP: 33, // also NUM_NORTH_EAST
  7502. PAGE_DOWN: 34, // also NUM_SOUTH_EAST
  7503. END: 35, // also NUM_SOUTH_WEST
  7504. HOME: 36, // also NUM_NORTH_WEST
  7505. LEFT: 37, // also NUM_WEST
  7506. UP: 38, // also NUM_NORTH
  7507. RIGHT: 39, // also NUM_EAST
  7508. DOWN: 40, // also NUM_SOUTH
  7509. PRINT_SCREEN: 44,
  7510. INSERT: 45, // also NUM_INSERT
  7511. DELETE: 46, // also NUM_DELETE
  7512. ZERO: 48,
  7513. ONE: 49,
  7514. TWO: 50,
  7515. THREE: 51,
  7516. FOUR: 52,
  7517. FIVE: 53,
  7518. SIX: 54,
  7519. SEVEN: 55,
  7520. EIGHT: 56,
  7521. NINE: 57,
  7522. QUESTION_MARK: 63, // needs localization
  7523. A: 65,
  7524. B: 66,
  7525. C: 67,
  7526. D: 68,
  7527. E: 69,
  7528. F: 70,
  7529. G: 71,
  7530. H: 72,
  7531. I: 73,
  7532. J: 74,
  7533. K: 75,
  7534. L: 76,
  7535. M: 77,
  7536. N: 78,
  7537. O: 79,
  7538. P: 80,
  7539. Q: 81,
  7540. R: 82,
  7541. S: 83,
  7542. T: 84,
  7543. U: 85,
  7544. V: 86,
  7545. W: 87,
  7546. X: 88,
  7547. Y: 89,
  7548. Z: 90,
  7549. META: 91, // WIN_KEY_LEFT
  7550. WIN_KEY_RIGHT: 92,
  7551. CONTEXT_MENU: 93,
  7552. NUM_ZERO: 96,
  7553. NUM_ONE: 97,
  7554. NUM_TWO: 98,
  7555. NUM_THREE: 99,
  7556. NUM_FOUR: 100,
  7557. NUM_FIVE: 101,
  7558. NUM_SIX: 102,
  7559. NUM_SEVEN: 103,
  7560. NUM_EIGHT: 104,
  7561. NUM_NINE: 105,
  7562. NUM_MULTIPLY: 106,
  7563. NUM_PLUS: 107,
  7564. NUM_MINUS: 109,
  7565. NUM_PERIOD: 110,
  7566. NUM_DIVISION: 111,
  7567. F1: 112,
  7568. F2: 113,
  7569. F3: 114,
  7570. F4: 115,
  7571. F5: 116,
  7572. F6: 117,
  7573. F7: 118,
  7574. F8: 119,
  7575. F9: 120,
  7576. F10: 121,
  7577. F11: 122,
  7578. F12: 123,
  7579. NUMLOCK: 144,
  7580. SEMICOLON: 186, // needs localization
  7581. DASH: 189, // needs localization
  7582. EQUALS: 187, // needs localization
  7583. COMMA: 188, // needs localization
  7584. PERIOD: 190, // needs localization
  7585. SLASH: 191, // needs localization
  7586. APOSTROPHE: 192, // needs localization
  7587. SINGLE_QUOTE: 222, // needs localization
  7588. OPEN_SQUARE_BRACKET: 219, // needs localization
  7589. BACKSLASH: 220, // needs localization
  7590. CLOSE_SQUARE_BRACKET: 221, // needs localization
  7591. WIN_KEY: 224,
  7592. MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
  7593. WIN_IME: 229
  7594. };
  7595. KeyCodes.isTextModifyingKeyEvent = function(e) {
  7596. if (e.altKey && !e.ctrlKey ||
  7597. e.metaKey ||
  7598. // Function keys don't generate text
  7599. e.keyCode >= KeyCodes.F1 &&
  7600. e.keyCode <= KeyCodes.F12) {
  7601. return false;
  7602. }
  7603. // The following keys are quite harmless, even in combination with
  7604. // CTRL, ALT or SHIFT.
  7605. switch (e.keyCode) {
  7606. case KeyCodes.ALT:
  7607. case KeyCodes.CAPS_LOCK:
  7608. case KeyCodes.CONTEXT_MENU:
  7609. case KeyCodes.CTRL:
  7610. case KeyCodes.DOWN:
  7611. case KeyCodes.END:
  7612. case KeyCodes.ESC:
  7613. case KeyCodes.HOME:
  7614. case KeyCodes.INSERT:
  7615. case KeyCodes.LEFT:
  7616. case KeyCodes.MAC_FF_META:
  7617. case KeyCodes.META:
  7618. case KeyCodes.NUMLOCK:
  7619. case KeyCodes.NUM_CENTER:
  7620. case KeyCodes.PAGE_DOWN:
  7621. case KeyCodes.PAGE_UP:
  7622. case KeyCodes.PAUSE:
  7623. case KeyCodes.PHANTOM:
  7624. case KeyCodes.PRINT_SCREEN:
  7625. case KeyCodes.RIGHT:
  7626. case KeyCodes.SHIFT:
  7627. case KeyCodes.UP:
  7628. case KeyCodes.WIN_KEY:
  7629. case KeyCodes.WIN_KEY_RIGHT:
  7630. return false;
  7631. default:
  7632. return true;
  7633. }
  7634. };
  7635. KeyCodes.isCharacterKey = function(keyCode) {
  7636. if (keyCode >= KeyCodes.ZERO &&
  7637. keyCode <= KeyCodes.NINE) {
  7638. return true;
  7639. }
  7640. if (keyCode >= KeyCodes.NUM_ZERO &&
  7641. keyCode <= KeyCodes.NUM_MULTIPLY) {
  7642. return true;
  7643. }
  7644. if (keyCode >= KeyCodes.A &&
  7645. keyCode <= KeyCodes.Z) {
  7646. return true;
  7647. }
  7648. // Safari sends zero key code for non-latin characters.
  7649. if (goog.userAgent.WEBKIT && keyCode == 0) {
  7650. return true;
  7651. }
  7652. switch (keyCode) {
  7653. case KeyCodes.SPACE:
  7654. case KeyCodes.QUESTION_MARK:
  7655. case KeyCodes.NUM_PLUS:
  7656. case KeyCodes.NUM_MINUS:
  7657. case KeyCodes.NUM_PERIOD:
  7658. case KeyCodes.NUM_DIVISION:
  7659. case KeyCodes.SEMICOLON:
  7660. case KeyCodes.DASH:
  7661. case KeyCodes.EQUALS:
  7662. case KeyCodes.COMMA:
  7663. case KeyCodes.PERIOD:
  7664. case KeyCodes.SLASH:
  7665. case KeyCodes.APOSTROPHE:
  7666. case KeyCodes.SINGLE_QUOTE:
  7667. case KeyCodes.OPEN_SQUARE_BRACKET:
  7668. case KeyCodes.BACKSLASH:
  7669. case KeyCodes.CLOSE_SQUARE_BRACKET:
  7670. return true;
  7671. default:
  7672. return false;
  7673. }
  7674. };
  7675. return KeyCodes;
  7676. });/**
  7677. * @fileOverview event-mouseenter
  7678. * @author yiminghe@gmail.com
  7679. */
  7680. KISSY.add('event/mouseenter', function (S, Event, DOM, UA, special) {
  7681. S.each([
  7682. { name:'mouseenter', fix:'mouseover' },
  7683. { name:'mouseleave', fix:'mouseout' }
  7684. ], function (o) {
  7685. special[o.name] = {
  7686. // fix #75
  7687. onFix:o.fix,
  7688. // all browser need
  7689. delegateFix:o.fix,
  7690. handle:function (event, handler, data) {
  7691. var currentTarget = event.currentTarget,
  7692. relatedTarget = event.relatedTarget;
  7693. // 在自身外边就触发
  7694. // self === document,parent === null
  7695. // relatedTarget 与 currentTarget 之间就是 mouseenter/leave
  7696. if (!relatedTarget ||
  7697. (relatedTarget !== currentTarget &&
  7698. !DOM.contains(currentTarget, relatedTarget))) {
  7699. // http://msdn.microsoft.com/en-us/library/ms536945(v=vs.85).aspx
  7700. // does not bubble
  7701. event.stopPropagation();
  7702. return [handler.fn.call(handler.scope || currentTarget, event, data)];
  7703. }
  7704. return [];
  7705. }
  7706. };
  7707. });
  7708. return Event;
  7709. }, {
  7710. requires:["./base", "dom", "ua", "./special"]
  7711. });
  7712. /**
  7713. * yiminghe@gmail.com:2011-12-15
  7714. * - 借鉴 jq 1.7 新的架构
  7715. *
  7716. * 承玉:2011-06-07
  7717. * - 根据新结构,调整 mouseenter 兼容处理
  7718. * - fire('mouseenter') 可以的,直接执行 mouseenter 的 handlers 用户回调数组
  7719. */
  7720. /**
  7721. * @fileOverview normalize mousewheel in gecko
  7722. * @author yiminghe@gmail.com
  7723. */
  7724. KISSY.add("event/mousewheel", function (S, Event, UA, Utils, EventObject, handle, _data, special) {
  7725. var MOUSE_WHEEL = UA.gecko ? 'DOMMouseScroll' : 'mousewheel',
  7726. simpleRemove = Utils.simpleRemove,
  7727. simpleAdd = Utils.simpleAdd,
  7728. MOUSE_WHEEL_HANDLER = "mousewheelHandler";
  7729. function handler(e) {
  7730. var deltaX,
  7731. currentTarget = this,
  7732. deltaY,
  7733. delta,
  7734. detail = e.detail;
  7735. if (e.wheelDelta) {
  7736. delta = e.wheelDelta / 120;
  7737. }
  7738. if (e.detail) {
  7739. // press control e.detail == 1 else e.detail == 3
  7740. delta = -(detail % 3 == 0 ? detail / 3 : detail);
  7741. }
  7742. // Gecko
  7743. if (e.axis !== undefined) {
  7744. if (e.axis === e['HORIZONTAL_AXIS']) {
  7745. deltaY = 0;
  7746. deltaX = -1 * delta;
  7747. } else if (e.axis === e['VERTICAL_AXIS']) {
  7748. deltaX = 0;
  7749. deltaY = delta;
  7750. }
  7751. }
  7752. // Webkit
  7753. if (e['wheelDeltaY'] !== undefined) {
  7754. deltaY = e['wheelDeltaY'] / 120;
  7755. }
  7756. if (e['wheelDeltaX'] !== undefined) {
  7757. deltaX = -1 * e['wheelDeltaX'] / 120;
  7758. }
  7759. // 默认 deltaY ( ie )
  7760. if (!deltaX && !deltaY) {
  7761. deltaY = delta;
  7762. }
  7763. // can not invoke eventDesc.handler , it will protect type
  7764. // but here in firefox , we want to change type really
  7765. e = new EventObject(currentTarget, e);
  7766. S.mix(e, {
  7767. deltaY:deltaY,
  7768. delta:delta,
  7769. deltaX:deltaX,
  7770. type:'mousewheel'
  7771. });
  7772. return handle(currentTarget, e);
  7773. }
  7774. special['mousewheel'] = {
  7775. setup:function () {
  7776. var el = this,
  7777. mousewheelHandler,
  7778. eventDesc = _data._data(el);
  7779. // solve this in ie
  7780. mousewheelHandler = eventDesc[MOUSE_WHEEL_HANDLER] = S.bind(handler, el);
  7781. simpleAdd(this, MOUSE_WHEEL, mousewheelHandler);
  7782. },
  7783. tearDown:function () {
  7784. var el = this,
  7785. mousewheelHandler,
  7786. eventDesc = _data._data(el);
  7787. mousewheelHandler = eventDesc[MOUSE_WHEEL_HANDLER];
  7788. simpleRemove(this, MOUSE_WHEEL, mousewheelHandler);
  7789. delete eventDesc[mousewheelHandler];
  7790. }
  7791. };
  7792. }, {
  7793. requires:['./base', 'ua', './utils',
  7794. './object', './handle',
  7795. './data', "./special"]
  7796. });
  7797. /**
  7798. note:
  7799. not perfect in osx : accelerated scroll
  7800. refer:
  7801. https://github.com/brandonaaron/jquery-mousewheel/blob/master/jquery.mousewheel.js
  7802. http://www.planabc.net/2010/08/12/mousewheel_event_in_javascript/
  7803. http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel
  7804. http://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers/5542105#5542105
  7805. http://www.javascriptkit.com/javatutors/onmousewheel.shtml
  7806. http://www.adomas.org/javascript-mouse-wheel/
  7807. http://plugins.jquery.com/project/mousewheel
  7808. http://www.cnblogs.com/aiyuchen/archive/2011/04/19/2020843.html
  7809. http://www.w3.org/TR/DOM-Level-3-Events/#events-mousewheelevents
  7810. **//**
  7811. * @fileOverview EventObject
  7812. * @author lifesinger@gmail.com,yiminghe@gmail.com
  7813. */
  7814. KISSY.add('event/object', function (S, undefined) {
  7815. var doc = document,
  7816. TRUE = true,
  7817. FALSE = false,
  7818. props = ('altKey attrChange attrName bubbles button cancelable ' +
  7819. 'charCode clientX clientY ctrlKey currentTarget data detail ' +
  7820. 'eventPhase fromElement handler keyCode metaKey ' +
  7821. 'newValue offsetX offsetY originalTarget pageX pageY prevValue ' +
  7822. 'relatedNode relatedTarget screenX screenY shiftKey srcElement ' +
  7823. 'target toElement view wheelDelta which axis').split(' ');
  7824. /**
  7825. * KISSY's event system normalizes the event object according to
  7826. * W3C standards. The event object is guaranteed to be passed to
  7827. * the event handler. Most properties from the original event are
  7828. * copied over and normalized to the new event object.
  7829. * @name Object
  7830. * @constructor
  7831. * @memberOf Event
  7832. */
  7833. function EventObject(currentTarget, domEvent, type) {
  7834. var self = this;
  7835. self.originalEvent = domEvent || { };
  7836. self.currentTarget = currentTarget;
  7837. if (domEvent) { // html element
  7838. self.type = domEvent.type;
  7839. // incase dom event has been mark as default prevented by lower dom node
  7840. self.isDefaultPrevented = ( domEvent['defaultPrevented'] || domEvent.returnValue === FALSE ||
  7841. domEvent['getPreventDefault'] && domEvent['getPreventDefault']() ) ? TRUE : FALSE;
  7842. self._fix();
  7843. }
  7844. else { // custom
  7845. self.type = type;
  7846. self.target = currentTarget;
  7847. }
  7848. // bug fix: in _fix() method, ie maybe reset currentTarget to undefined.
  7849. self.currentTarget = currentTarget;
  7850. self.fixed = TRUE;
  7851. }
  7852. S.augment(EventObject, {
  7853. isDefaultPrevented:FALSE,
  7854. isPropagationStopped:FALSE,
  7855. isImmediatePropagationStopped:FALSE,
  7856. _fix:function () {
  7857. var self = this,
  7858. originalEvent = self.originalEvent,
  7859. l = props.length, prop,
  7860. ct = self.currentTarget,
  7861. ownerDoc = (ct.nodeType === 9) ? ct : (ct.ownerDocument || doc); // support iframe
  7862. // clone properties of the original event object
  7863. while (l) {
  7864. prop = props[--l];
  7865. self[prop] = originalEvent[prop];
  7866. }
  7867. // fix target property, if necessary
  7868. if (!self.target) {
  7869. self.target = self.srcElement || doc; // srcElement might not be defined either
  7870. }
  7871. // check if target is a textnode (safari)
  7872. if (self.target.nodeType === 3) {
  7873. self.target = self.target.parentNode;
  7874. }
  7875. // add relatedTarget, if necessary
  7876. if (!self.relatedTarget && self.fromElement) {
  7877. self.relatedTarget = (self.fromElement === self.target) ? self.toElement : self.fromElement;
  7878. }
  7879. // calculate pageX/Y if missing and clientX/Y available
  7880. if (self.pageX === undefined && self.clientX !== undefined) {
  7881. var docEl = ownerDoc.documentElement, bd = ownerDoc.body;
  7882. self.pageX = self.clientX + (docEl && docEl.scrollLeft || bd && bd.scrollLeft || 0) - (docEl && docEl.clientLeft || bd && bd.clientLeft || 0);
  7883. self.pageY = self.clientY + (docEl && docEl.scrollTop || bd && bd.scrollTop || 0) - (docEl && docEl.clientTop || bd && bd.clientTop || 0);
  7884. }
  7885. // add which for key events
  7886. if (self.which === undefined) {
  7887. self.which = (self.charCode === undefined) ? self.keyCode : self.charCode;
  7888. }
  7889. // add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
  7890. if (self.metaKey === undefined) {
  7891. self.metaKey = self.ctrlKey;
  7892. }
  7893. // add which for click: 1 === left; 2 === middle; 3 === right
  7894. // Note: button is not normalized, so don't use it
  7895. if (!self.which && self.button !== undefined) {
  7896. self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : ( self.button & 4 ? 2 : 0)));
  7897. }
  7898. },
  7899. /**
  7900. * Prevents the event's default behavior
  7901. */
  7902. preventDefault:function () {
  7903. var e = this.originalEvent;
  7904. // if preventDefault exists run it on the original event
  7905. if (e.preventDefault) {
  7906. e.preventDefault();
  7907. }
  7908. // otherwise set the returnValue property of the original event to FALSE (IE)
  7909. else {
  7910. e.returnValue = FALSE;
  7911. }
  7912. this.isDefaultPrevented = TRUE;
  7913. },
  7914. /**
  7915. * Stops the propagation to the next bubble target
  7916. */
  7917. stopPropagation:function () {
  7918. var e = this.originalEvent;
  7919. // if stopPropagation exists run it on the original event
  7920. if (e.stopPropagation) {
  7921. e.stopPropagation();
  7922. }
  7923. // otherwise set the cancelBubble property of the original event to TRUE (IE)
  7924. else {
  7925. e.cancelBubble = TRUE;
  7926. }
  7927. this.isPropagationStopped = TRUE;
  7928. },
  7929. /**
  7930. * Stops the propagation to the next bubble target and
  7931. * prevents any additional listeners from being exectued
  7932. * on the current target.
  7933. */
  7934. stopImmediatePropagation:function () {
  7935. var self = this;
  7936. self.isImmediatePropagationStopped = TRUE;
  7937. // fixed 1.2
  7938. // call stopPropagation implicitly
  7939. self.stopPropagation();
  7940. },
  7941. /**
  7942. * Stops the event propagation and prevents the default
  7943. * event behavior.
  7944. * @param immediate {boolean} if TRUE additional listeners
  7945. * on the current target will not be executed
  7946. */
  7947. halt:function (immediate) {
  7948. var self = this;
  7949. if (immediate) {
  7950. self.stopImmediatePropagation();
  7951. } else {
  7952. self.stopPropagation();
  7953. }
  7954. self.preventDefault();
  7955. }
  7956. });
  7957. return EventObject;
  7958. });
  7959. /**
  7960. * NOTES:
  7961. *
  7962. * 2010.04
  7963. * - http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  7964. *
  7965. * TODO:
  7966. * - pageX, clientX, scrollLeft, clientLeft 的详细测试
  7967. */
  7968. /**
  7969. * @fileOverview responsible for un-registering event
  7970. * @author yiminghe@gmail.com
  7971. */
  7972. KISSY.add("event/remove", function (S, Event, DOM, Utils, _data, EVENT_SPECIAL) {
  7973. var isValidTarget = Utils.isValidTarget,
  7974. simpleRemove = Utils.simpleRemove;
  7975. S.mix(Event, {
  7976. // single target, single type, fixed native
  7977. __remove:function (isNativeTarget, target, type, fn, scope) {
  7978. if (!target || (isNativeTarget && !isValidTarget(target))) {
  7979. return;
  7980. }
  7981. var typedGroups = Utils.getTypedGroups(type);
  7982. type = typedGroups[0];
  7983. var groups = typedGroups[1],
  7984. selector,
  7985. // in case type is undefined
  7986. originalFn = fn,
  7987. originalScope = scope,
  7988. hasSelector, s = EVENT_SPECIAL[type];
  7989. if (S.isObject(fn)) {
  7990. scope = fn.scope;
  7991. hasSelector = ("selector" in fn);
  7992. selector = fn.selector;
  7993. fn = fn.fn;
  7994. if (selector) {
  7995. if (s && s['delegateFix']) {
  7996. type = s['delegateFix'];
  7997. }
  7998. }
  7999. }
  8000. if (!selector) {
  8001. if (s && s['onFix']) {
  8002. type = s['onFix'];
  8003. }
  8004. }
  8005. var eventDesc = _data._data(target),
  8006. events = eventDesc && eventDesc.events,
  8007. handlers,
  8008. handler,
  8009. len,
  8010. i,
  8011. j,
  8012. t,
  8013. special = (isNativeTarget && EVENT_SPECIAL[type]) || { };
  8014. if (!events) {
  8015. return;
  8016. }
  8017. // remove all types of event
  8018. if (!type) {
  8019. for (type in events) {
  8020. if (events.hasOwnProperty(type)) {
  8021. Event.__remove(isNativeTarget,
  8022. target, type + groups, originalFn,
  8023. originalScope);
  8024. }
  8025. }
  8026. return;
  8027. }
  8028. var groupsRe;
  8029. if (groups) {
  8030. groupsRe = Utils.getGroupsRe(groups);
  8031. }
  8032. if ((handlers = events[type])) {
  8033. len = handlers.length;
  8034. // 移除 fn
  8035. if ((fn || hasSelector || groupsRe ) && len) {
  8036. scope = scope || target;
  8037. for (i = 0, j = 0, t = []; i < len; ++i) {
  8038. handler = handlers[i];
  8039. var handlerScope = handler.scope || target;
  8040. if (
  8041. (scope != handlerScope) ||
  8042. // 指定了函数,函数不相等,保留
  8043. (fn && fn != handler.fn) ||
  8044. // 1.没指定函数
  8045. // 1.1 没有指定选择器,删掉 else2
  8046. // 1.2 指定选择器,字符串为空
  8047. // 1.2.1 指定选择器,字符串为空,待比较 handler 有选择器,删掉 else
  8048. // 1.2.2 指定选择器,字符串为空,待比较 handler 没有选择器,保留
  8049. // 1.3 指定选择器,字符串不为空,字符串相等,删掉 else
  8050. // 1.4 指定选择器,字符串不为空,字符串不相等,保留
  8051. // 2.指定了函数且函数相等
  8052. // 2.1 没有指定选择器,删掉 else
  8053. // 2.2 指定选择器,字符串为空
  8054. // 2.2.1 指定选择器,字符串为空,待比较 handler 有选择器,删掉 else
  8055. // 2.2.2 指定选择器,字符串为空,待比较 handler 没有选择器,保留
  8056. // 2.3 指定选择器,字符串不为空,字符串相等,删掉 else
  8057. // 2.4 指定选择器,字符串不为空,字符串不相等,保留
  8058. (
  8059. hasSelector &&
  8060. (
  8061. (selector && selector != handler.selector) ||
  8062. (!selector && !handler.selector)
  8063. )
  8064. ) ||
  8065. // 指定了删除的某些组,而该 handler 不属于这些组,保留,否则删除
  8066. (groupsRe && !handler.groups.match(groupsRe))
  8067. ) {
  8068. t[j++] = handler;
  8069. }
  8070. else {
  8071. if (handler.selector && handlers.delegateCount) {
  8072. handlers.delegateCount--;
  8073. }
  8074. if (handler.last && handlers.lastCount) {
  8075. handlers.lastCount--;
  8076. }
  8077. if (special.remove) {
  8078. special.remove.call(target, handler);
  8079. }
  8080. }
  8081. }
  8082. t.delegateCount = handlers.delegateCount;
  8083. t.lastCount = handlers.lastCount;
  8084. events[type] = t;
  8085. len = t.length;
  8086. } else {
  8087. // 全部删除
  8088. len = 0;
  8089. }
  8090. if (!len) {
  8091. // remove(el, type) or fn 已移除光
  8092. // dom node need to detach handler from dom node
  8093. if (isNativeTarget &&
  8094. (!special['tearDown'] ||
  8095. special['tearDown'].call(target) === false)) {
  8096. simpleRemove(target, type, eventDesc.handler);
  8097. }
  8098. // remove target's single event description
  8099. delete events[type];
  8100. }
  8101. }
  8102. // remove target's all events description
  8103. if (S.isEmptyObject(events)) {
  8104. eventDesc.handler.target = null;
  8105. delete eventDesc.handler;
  8106. delete eventDesc.events;
  8107. Event._removeData(target);
  8108. }
  8109. },
  8110. /**
  8111. * Detach an event or set of events from an element. similar to removeEventListener in DOM3 Events
  8112. * @param targets KISSY selector
  8113. * @param {String} [type] The type of event to append.
  8114. * @param {Object|Function} [fn] The event handler/listener.
  8115. * @param {Object} [scope] The scope (this reference) in which the handler function is executed.
  8116. */
  8117. remove:function (targets, type, fn, scope) {
  8118. type = S.trim(type);
  8119. if (Utils.batchForType(Event.remove, targets, type, fn, scope)) {
  8120. return targets;
  8121. }
  8122. targets = DOM.query(targets);
  8123. for (var i = targets.length - 1; i >= 0; i--) {
  8124. Event.__remove(true, targets[i], type, fn, scope);
  8125. }
  8126. return targets;
  8127. }
  8128. });
  8129. }, {
  8130. requires:['./base', 'dom', './utils', './data', './special']
  8131. });/**
  8132. * @fileOverview special house for special events
  8133. * @author yiminghe@gmail.com
  8134. */
  8135. KISSY.add("event/special", function () {
  8136. return {};
  8137. });/**
  8138. * @fileOverview patch for ie<9 submit : does not bubble !
  8139. * @author yiminghe@gmail.com
  8140. */
  8141. KISSY.add("event/submit", function (S, UA, Event, DOM, special) {
  8142. var mode = document['documentMode'];
  8143. if (UA['ie'] && (UA['ie'] < 9 || (mode && mode < 9))) {
  8144. var nodeName = DOM._nodeName;
  8145. special['submit'] = {
  8146. setup:function () {
  8147. var el = this;
  8148. // form use native
  8149. if (nodeName(el, "form")) {
  8150. return false;
  8151. }
  8152. // lazy add submit for inside forms
  8153. // note event order : click/keypress -> submit
  8154. // keypoint : find the forms
  8155. Event.on(el, "click keypress", detector);
  8156. },
  8157. tearDown:function () {
  8158. var el = this;
  8159. // form use native
  8160. if (nodeName(el, "form")) {
  8161. return false;
  8162. }
  8163. Event.remove(el, "click keypress", detector);
  8164. S.each(DOM.query("form", el),function (form) {
  8165. if (form.__submit__fix) {
  8166. form.__submit__fix = 0;
  8167. Event.remove(form, "submit", {
  8168. fn:submitBubble,
  8169. last:1
  8170. });
  8171. }
  8172. });
  8173. }
  8174. };
  8175. function detector(e) {
  8176. var t = e.target,
  8177. form = nodeName(t, "input") || nodeName(t, "button") ? t.form : null;
  8178. if (form && !form.__submit__fix) {
  8179. form.__submit__fix = 1;
  8180. Event.on(form, "submit", {
  8181. fn:submitBubble,
  8182. last:1
  8183. });
  8184. }
  8185. }
  8186. function submitBubble(e) {
  8187. var form = this;
  8188. if (form.parentNode &&
  8189. // it is stopped by user callback
  8190. !e.isPropagationStopped &&
  8191. // it is not fired manually
  8192. !e._ks_fired) {
  8193. // simulated bubble for submit
  8194. // fire from parentNode. if form.on("submit") , this logic is never run!
  8195. Event.fire(form.parentNode, "submit", e);
  8196. }
  8197. }
  8198. }
  8199. }, {
  8200. requires:["ua", "./base", "dom", "./special"]
  8201. });
  8202. /**
  8203. * modified from jq ,fix submit in ie<9
  8204. * - http://bugs.jquery.com/ticket/11049
  8205. **//**
  8206. * @fileOverview 提供事件发布和订阅机制
  8207. * @author yiminghe@gmail.com
  8208. */
  8209. KISSY.add('event/target', function (S, Event, EventObject, Utils, handle, undefined) {
  8210. var KS_PUBLISH = "__~ks_publish",
  8211. trim = S.trim,
  8212. splitAndRun = Utils.splitAndRun,
  8213. KS_BUBBLE_TARGETS = "__~ks_bubble_targets",
  8214. ALL_EVENT = "*";
  8215. function getCustomEvent(self, type, eventData) {
  8216. if (eventData instanceof EventObject) {
  8217. // set currentTarget in the process of bubbling
  8218. eventData.currentTarget = self;
  8219. return eventData;
  8220. }
  8221. var customEvent = new EventObject(self, undefined, type);
  8222. S.mix(customEvent, eventData);
  8223. return customEvent
  8224. }
  8225. function getEventPublishObj(self) {
  8226. self[KS_PUBLISH] = self[KS_PUBLISH] || {};
  8227. return self[KS_PUBLISH];
  8228. }
  8229. function getBubbleTargetsObj(self) {
  8230. self[KS_BUBBLE_TARGETS] = self[KS_BUBBLE_TARGETS] || {};
  8231. return self[KS_BUBBLE_TARGETS];
  8232. }
  8233. function isBubblable(self, eventType) {
  8234. var publish = getEventPublishObj(self);
  8235. return publish[eventType] && publish[eventType].bubbles || publish[ALL_EVENT] && publish[ALL_EVENT].bubbles
  8236. }
  8237. function attach(method) {
  8238. return function (type, fn, scope) {
  8239. var self = this;
  8240. type = trim(type);
  8241. splitAndRun(type, function (t) {
  8242. Event["__" + method](false, self, t, fn, scope);
  8243. });
  8244. return self; // chain
  8245. };
  8246. }
  8247. /**
  8248. * 提供事件发布和订阅机制
  8249. * @name Target
  8250. * @namespace
  8251. * @memberOf Event
  8252. */
  8253. var Target =
  8254. /**
  8255. * @lends Event.Target
  8256. */
  8257. {
  8258. /**
  8259. * 触发事件
  8260. * @param {String} type 事件名
  8261. * @param {Object} [eventData] 事件附加信息对象
  8262. * @returns 如果一个 listener 返回false,则返回 false ,否则返回最后一个 listener 的值.
  8263. */
  8264. fire:function (type, eventData) {
  8265. var self = this,
  8266. ret = undefined,
  8267. r2,
  8268. customEvent;
  8269. eventData = eventData || {};
  8270. type = trim(type);
  8271. if (type.indexOf(" ") > 0) {
  8272. splitAndRun(type, function (t) {
  8273. r2 = self.fire(t, eventData);
  8274. if (ret !== false) {
  8275. ret = r2;
  8276. }
  8277. });
  8278. return ret;
  8279. }
  8280. var typedGroups = Utils.getTypedGroups(type), _ks_groups = typedGroups[1];
  8281. type = typedGroups[0];
  8282. if (_ks_groups) {
  8283. _ks_groups = Utils.getGroupsRe(_ks_groups);
  8284. }
  8285. S.mix(eventData, {
  8286. // protect type
  8287. type:type,
  8288. _ks_groups:_ks_groups
  8289. });
  8290. customEvent = getCustomEvent(self, type, eventData);
  8291. ret = handle(self, customEvent);
  8292. if (!customEvent.isPropagationStopped &&
  8293. isBubblable(self, type)) {
  8294. r2 = self.bubble(type, customEvent);
  8295. // false 优先返回
  8296. if (ret !== false) {
  8297. ret = r2;
  8298. }
  8299. }
  8300. return ret
  8301. },
  8302. /**
  8303. * defined event config
  8304. * @param type
  8305. * @param cfg
  8306. * example { bubbles: true}
  8307. * default bubbles: false
  8308. */
  8309. publish:function (type, cfg) {
  8310. var self = this,
  8311. publish = getEventPublishObj(self);
  8312. type = trim(type);
  8313. if (type) {
  8314. publish[type] = cfg;
  8315. }
  8316. },
  8317. /**
  8318. * bubble event to its targets
  8319. * @param type
  8320. * @param eventData
  8321. */
  8322. bubble:function (type, eventData) {
  8323. var self = this,
  8324. ret = undefined,
  8325. targets = getBubbleTargetsObj(self);
  8326. S.each(targets, function (t) {
  8327. var r2 = t.fire(type, eventData);
  8328. if (ret !== false) {
  8329. ret = r2;
  8330. }
  8331. });
  8332. return ret;
  8333. },
  8334. /**
  8335. * add target which bubblable event bubbles towards
  8336. * @param target another EventTarget instance
  8337. */
  8338. addTarget:function (target) {
  8339. var self = this,
  8340. targets = getBubbleTargetsObj(self);
  8341. targets[S.stamp(target)] = target;
  8342. },
  8343. removeTarget:function (target) {
  8344. var self = this,
  8345. targets = getBubbleTargetsObj(self);
  8346. delete targets[S.stamp(target)];
  8347. },
  8348. /**
  8349. * 监听事件
  8350. * @function
  8351. * @param {String} type 事件名
  8352. * @param {Function} fn 事件处理器
  8353. * @param {Object} scope 事件处理器内的 this 值,默认当前实例
  8354. * @returns 当前实例
  8355. */
  8356. on:attach("add"),
  8357. /**
  8358. * 取消监听事件
  8359. * @function
  8360. * @param {String} type 事件名
  8361. * @param {Function} fn 事件处理器
  8362. * @param {Object} scope 事件处理器内的 this 值,默认当前实例
  8363. * @returns 当前实例
  8364. */
  8365. detach:attach("remove")
  8366. };
  8367. return Target;
  8368. }, {
  8369. /*
  8370. 实际上只需要 dom/data ,但是不要跨模块引用另一模块的子模块,
  8371. 否则会导致build打包文件 dom 和 dom-data 重复载入
  8372. */
  8373. requires:["./base", './object', './utils', './handle']
  8374. });
  8375. /**
  8376. * yiminghe:2011-10-17
  8377. * - implement bubble for custom event
  8378. **//**
  8379. * @fileOverview utils for event
  8380. * @author yiminghe@gmail.com
  8381. */
  8382. KISSY.add("event/utils", function (S, DOM) {
  8383. /**
  8384. * whether two event listens are the same
  8385. * @param h1 已有的 handler 描述
  8386. * @param h2 用户提供的 handler 描述
  8387. */
  8388. function isIdenticalHandler(h1, h2, el) {
  8389. var scope1 = h1.scope || el,
  8390. ret = 1,
  8391. scope2 = h2.scope || el;
  8392. if (
  8393. h1.fn !== h2.fn ||
  8394. h1.selector !== h2.selector ||
  8395. h1.data !== h2.data ||
  8396. scope1 !== scope2 ||
  8397. h1.originalType !== h2.originalType ||
  8398. h1.groups !== h2.groups ||
  8399. h1.last !== h2.last
  8400. ) {
  8401. ret = 0;
  8402. }
  8403. return ret;
  8404. }
  8405. function isValidTarget(target) {
  8406. // 3 - is text node
  8407. // 8 - is comment node
  8408. return target &&
  8409. target.nodeType !== DOM.TEXT_NODE &&
  8410. target.nodeType !== DOM.COMMENT_NODE;
  8411. }
  8412. function batchForType(fn, targets, types) {
  8413. // on(target, 'click focus', fn)
  8414. if (types && types.indexOf(" ") > 0) {
  8415. var args = S.makeArray(arguments);
  8416. S.each(types.split(/\s+/), function (type) {
  8417. var args2 = [].concat(args);
  8418. args2.splice(0, 3, targets, type);
  8419. fn.apply(null, args2);
  8420. });
  8421. return true;
  8422. }
  8423. return 0;
  8424. }
  8425. function splitAndRun(type, fn) {
  8426. S.each(type.split(/\s+/), fn);
  8427. }
  8428. var doc = document,
  8429. simpleAdd = doc.addEventListener ?
  8430. function (el, type, fn, capture) {
  8431. if (el.addEventListener) {
  8432. el.addEventListener(type, fn, !!capture);
  8433. }
  8434. } :
  8435. function (el, type, fn) {
  8436. if (el.attachEvent) {
  8437. el.attachEvent('on' + type, fn);
  8438. }
  8439. },
  8440. simpleRemove = doc.removeEventListener ?
  8441. function (el, type, fn, capture) {
  8442. if (el.removeEventListener) {
  8443. el.removeEventListener(type, fn, !!capture);
  8444. }
  8445. } :
  8446. function (el, type, fn) {
  8447. if (el.detachEvent) {
  8448. el.detachEvent('on' + type, fn);
  8449. }
  8450. };
  8451. return {
  8452. // 记录手工 fire(domElement,type) 时的 type
  8453. // 再在浏览器通知的系统 eventHandler 中检查
  8454. // 如果相同,那么证明已经 fire 过了,不要再次触发了
  8455. Event_Triggered:"",
  8456. TRIGGERED_NONE:"trigger-none-" + S.now(),
  8457. EVENT_GUID:'ksEventTargetId' + S.now(),
  8458. splitAndRun:splitAndRun,
  8459. batchForType:batchForType,
  8460. isValidTarget:isValidTarget,
  8461. isIdenticalHandler:isIdenticalHandler,
  8462. simpleAdd:simpleAdd,
  8463. simpleRemove:simpleRemove,
  8464. getTypedGroups:function (type) {
  8465. if (type.indexOf(".") < 0) {
  8466. return [type, ""];
  8467. }
  8468. var m = type.match(/([^.]+)?(\..+)?$/),
  8469. t = m[1],
  8470. ret = [t],
  8471. gs = m[2];
  8472. if (gs) {
  8473. gs = gs.split(".").sort();
  8474. ret.push(gs.join("."));
  8475. } else {
  8476. ret.push("");
  8477. }
  8478. return ret;
  8479. },
  8480. getGroupsRe:function (groups) {
  8481. return new RegExp(groups.split(".").join(".*\\.") + "(?:\\.|$)");
  8482. }
  8483. };
  8484. }, {
  8485. requires:['dom']
  8486. });/**
  8487. * @fileOverview inspired by yui3 :
  8488. *
  8489. * Synthetic event that fires when the <code>value</code> property of an input
  8490. * field or textarea changes as a result of a keystroke, mouse operation, or
  8491. * input method editor (IME) input event.
  8492. *
  8493. * Unlike the <code>onchange</code> event, this event fires when the value
  8494. * actually changes and not when the element loses focus. This event also
  8495. * reports IME and multi-stroke input more reliably than <code>oninput</code> or
  8496. * the various key events across browsers.
  8497. *
  8498. * @author yiminghe@gmail.com
  8499. */
  8500. KISSY.add('event/valuechange', function (S, Event, DOM, special) {
  8501. var VALUE_CHANGE = "valuechange",
  8502. nodeName = DOM._nodeName,
  8503. KEY = "event/valuechange",
  8504. HISTORY_KEY = KEY + "/history",
  8505. POLL_KEY = KEY + "/poll",
  8506. interval = 50;
  8507. function stopPoll(target) {
  8508. DOM.removeData(target, HISTORY_KEY);
  8509. if (DOM.hasData(target, POLL_KEY)) {
  8510. var poll = DOM.data(target, POLL_KEY);
  8511. clearTimeout(poll);
  8512. DOM.removeData(target, POLL_KEY);
  8513. }
  8514. }
  8515. function stopPollHandler(ev) {
  8516. var target = ev.target;
  8517. stopPoll(target);
  8518. }
  8519. function startPoll(target) {
  8520. if (DOM.hasData(target, POLL_KEY)) return;
  8521. DOM.data(target, POLL_KEY, setTimeout(function () {
  8522. var v = target.value, h = DOM.data(target, HISTORY_KEY);
  8523. if (v !== h) {
  8524. // 只触发自己绑定的 handler
  8525. Event.fire(target, VALUE_CHANGE, {
  8526. prevVal:h,
  8527. newVal:v
  8528. }, true);
  8529. DOM.data(target, HISTORY_KEY, v);
  8530. }
  8531. DOM.data(target, POLL_KEY, setTimeout(arguments.callee, interval));
  8532. }, interval));
  8533. }
  8534. function startPollHandler(ev) {
  8535. var target = ev.target;
  8536. // when focus ,record its current value immediately
  8537. if (ev.type == "focus") {
  8538. DOM.data(target, HISTORY_KEY, target.value);
  8539. }
  8540. startPoll(target);
  8541. }
  8542. function monitor(target) {
  8543. unmonitored(target);
  8544. Event.on(target, "blur", stopPollHandler);
  8545. Event.on(target, "mousedown keyup keydown focus", startPollHandler);
  8546. }
  8547. function unmonitored(target) {
  8548. stopPoll(target);
  8549. Event.remove(target, "blur", stopPollHandler);
  8550. Event.remove(target, "mousedown keyup keydown focus", startPollHandler);
  8551. }
  8552. special[VALUE_CHANGE] = {
  8553. setup:function () {
  8554. var target = this;
  8555. if (nodeName(target, "input")
  8556. || nodeName(target, "textarea")) {
  8557. monitor(target);
  8558. }
  8559. },
  8560. tearDown:function () {
  8561. var target = this;
  8562. unmonitored(target);
  8563. }
  8564. };
  8565. return Event;
  8566. }, {
  8567. requires:["./base", "dom", "./special"]
  8568. });
  8569. /*
  8570. Copyright 2011, KISSY UI Library v1.30dev
  8571. MIT Licensed
  8572. build time: Dec 31 15:26
  8573. */
  8574. /**
  8575. * @fileOverview adapt json2 to kissy
  8576. */
  8577. KISSY.add('json', function (S, JSON) {
  8578. return {
  8579. parse:function (text) {
  8580. // 当输入为 undefined / null / '' 时,返回 null
  8581. if (text == null || text === '') {
  8582. return null;
  8583. }
  8584. return JSON.parse(text);
  8585. },
  8586. stringify:JSON.stringify
  8587. };
  8588. }, {
  8589. requires:["json/json2"]
  8590. });
  8591. /*
  8592. http://www.JSON.org/json2.js
  8593. 2010-08-25
  8594. Public Domain.
  8595. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  8596. See http://www.JSON.org/js.html
  8597. This code should be minified before deployment.
  8598. See http://javascript.crockford.com/jsmin.html
  8599. USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
  8600. NOT CONTROL.
  8601. This file creates a global JSON object containing two methods: stringify
  8602. and parse.
  8603. JSON.stringify(value, replacer, space)
  8604. value any JavaScript value, usually an object or array.
  8605. replacer an optional parameter that determines how object
  8606. values are stringified for objects. It can be a
  8607. function or an array of strings.
  8608. space an optional parameter that specifies the indentation
  8609. of nested structures. If it is omitted, the text will
  8610. be packed without extra whitespace. If it is a number,
  8611. it will specify the number of spaces to indent at each
  8612. level. If it is a string (such as '\t' or '&nbsp;'),
  8613. it contains the characters used to indent at each level.
  8614. This method produces a JSON text from a JavaScript value.
  8615. When an object value is found, if the object contains a toJSON
  8616. method, its toJSON method will be called and the result will be
  8617. stringified. A toJSON method does not serialize: it returns the
  8618. value represented by the name/value pair that should be serialized,
  8619. or undefined if nothing should be serialized. The toJSON method
  8620. will be passed the key associated with the value, and this will be
  8621. bound to the value
  8622. For example, this would serialize Dates as ISO strings.
  8623. Date.prototype.toJSON = function (key) {
  8624. function f(n) {
  8625. // Format integers to have at least two digits.
  8626. return n < 10 ? '0' + n : n;
  8627. }
  8628. return this.getUTCFullYear() + '-' +
  8629. f(this.getUTCMonth() + 1) + '-' +
  8630. f(this.getUTCDate()) + 'T' +
  8631. f(this.getUTCHours()) + ':' +
  8632. f(this.getUTCMinutes()) + ':' +
  8633. f(this.getUTCSeconds()) + 'Z';
  8634. };
  8635. You can provide an optional replacer method. It will be passed the
  8636. key and value of each member, with this bound to the containing
  8637. object. The value that is returned from your method will be
  8638. serialized. If your method returns undefined, then the member will
  8639. be excluded from the serialization.
  8640. If the replacer parameter is an array of strings, then it will be
  8641. used to select the members to be serialized. It filters the results
  8642. such that only members with keys listed in the replacer array are
  8643. stringified.
  8644. Values that do not have JSON representations, such as undefined or
  8645. functions, will not be serialized. Such values in objects will be
  8646. dropped; in arrays they will be replaced with null. You can use
  8647. a replacer function to replace those with JSON values.
  8648. JSON.stringify(undefined) returns undefined.
  8649. The optional space parameter produces a stringification of the
  8650. value that is filled with line breaks and indentation to make it
  8651. easier to read.
  8652. If the space parameter is a non-empty string, then that string will
  8653. be used for indentation. If the space parameter is a number, then
  8654. the indentation will be that many spaces.
  8655. Example:
  8656. text = JSON.stringify(['e', {pluribus: 'unum'}]);
  8657. // text is '["e",{"pluribus":"unum"}]'
  8658. text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
  8659. // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
  8660. text = JSON.stringify([new Date()], function (key, value) {
  8661. return this[key] instanceof Date ?
  8662. 'Date(' + this[key] + ')' : value;
  8663. });
  8664. // text is '["Date(---current time---)"]'
  8665. JSON.parse(text, reviver)
  8666. This method parses a JSON text to produce an object or array.
  8667. It can throw a SyntaxError exception.
  8668. The optional reviver parameter is a function that can filter and
  8669. transform the results. It receives each of the keys and values,
  8670. and its return value is used instead of the original value.
  8671. If it returns what it received, then the structure is not modified.
  8672. If it returns undefined then the member is deleted.
  8673. Example:
  8674. // Parse the text. Values that look like ISO date strings will
  8675. // be converted to Date objects.
  8676. myData = JSON.parse(text, function (key, value) {
  8677. var a;
  8678. if (typeof value === 'string') {
  8679. a =
  8680. /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
  8681. if (a) {
  8682. return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
  8683. +a[5], +a[6]));
  8684. }
  8685. }
  8686. return value;
  8687. });
  8688. myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
  8689. var d;
  8690. if (typeof value === 'string' &&
  8691. value.slice(0, 5) === 'Date(' &&
  8692. value.slice(-1) === ')') {
  8693. d = new Date(value.slice(5, -1));
  8694. if (d) {
  8695. return d;
  8696. }
  8697. }
  8698. return value;
  8699. });
  8700. This is a reference implementation. You are free to copy, modify, or
  8701. redistribute.
  8702. */
  8703. /*jslint evil: true, strict: false */
  8704. /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
  8705. call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
  8706. getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
  8707. lastIndex, length, parse, prototype, push, replace, slice, stringify,
  8708. test, toJSON, toString, valueOf
  8709. */
  8710. // Create a JSON object only if one does not already exist. We create the
  8711. // methods in a closure to avoid creating global variables.
  8712. KISSY.add("json/json2", function(S, UA) {
  8713. var win = window,JSON = win.JSON;
  8714. // ie 8.0.7600.16315@win7 json 有问题
  8715. if (!JSON || UA['ie'] < 9) {
  8716. JSON = win.JSON = {};
  8717. }
  8718. function f(n) {
  8719. // Format integers to have at least two digits.
  8720. return n < 10 ? '0' + n : n;
  8721. }
  8722. if (typeof Date.prototype.toJSON !== 'function') {
  8723. Date.prototype.toJSON = function (key) {
  8724. return isFinite(this.valueOf()) ?
  8725. this.getUTCFullYear() + '-' +
  8726. f(this.getUTCMonth() + 1) + '-' +
  8727. f(this.getUTCDate()) + 'T' +
  8728. f(this.getUTCHours()) + ':' +
  8729. f(this.getUTCMinutes()) + ':' +
  8730. f(this.getUTCSeconds()) + 'Z' : null;
  8731. };
  8732. String.prototype.toJSON =
  8733. Number.prototype.toJSON =
  8734. Boolean.prototype.toJSON = function (key) {
  8735. return this.valueOf();
  8736. };
  8737. }
  8738. var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  8739. escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  8740. gap,
  8741. indent,
  8742. meta = { // table of character substitutions
  8743. '\b': '\\b',
  8744. '\t': '\\t',
  8745. '\n': '\\n',
  8746. '\f': '\\f',
  8747. '\r': '\\r',
  8748. '"' : '\\"',
  8749. '\\': '\\\\'
  8750. },
  8751. rep;
  8752. function quote(string) {
  8753. // If the string contains no control characters, no quote characters, and no
  8754. // backslash characters, then we can safely slap some quotes around it.
  8755. // Otherwise we must also replace the offending characters with safe escape
  8756. // sequences.
  8757. escapable['lastIndex'] = 0;
  8758. return escapable.test(string) ?
  8759. '"' + string.replace(escapable, function (a) {
  8760. var c = meta[a];
  8761. return typeof c === 'string' ? c :
  8762. '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  8763. }) + '"' :
  8764. '"' + string + '"';
  8765. }
  8766. function str(key, holder) {
  8767. // Produce a string from holder[key].
  8768. var i, // The loop counter.
  8769. k, // The member key.
  8770. v, // The member value.
  8771. length,
  8772. mind = gap,
  8773. partial,
  8774. value = holder[key];
  8775. // If the value has a toJSON method, call it to obtain a replacement value.
  8776. if (value && typeof value === 'object' &&
  8777. typeof value.toJSON === 'function') {
  8778. value = value.toJSON(key);
  8779. }
  8780. // If we were called with a replacer function, then call the replacer to
  8781. // obtain a replacement value.
  8782. if (typeof rep === 'function') {
  8783. value = rep.call(holder, key, value);
  8784. }
  8785. // What happens next depends on the value's type.
  8786. switch (typeof value) {
  8787. case 'string':
  8788. return quote(value);
  8789. case 'number':
  8790. // JSON numbers must be finite. Encode non-finite numbers as null.
  8791. return isFinite(value) ? String(value) : 'null';
  8792. case 'boolean':
  8793. case 'null':
  8794. // If the value is a boolean or null, convert it to a string. Note:
  8795. // typeof null does not produce 'null'. The case is included here in
  8796. // the remote chance that this gets fixed someday.
  8797. return String(value);
  8798. // If the type is 'object', we might be dealing with an object or an array or
  8799. // null.
  8800. case 'object':
  8801. // Due to a specification blunder in ECMAScript, typeof null is 'object',
  8802. // so watch out for that case.
  8803. if (!value) {
  8804. return 'null';
  8805. }
  8806. // Make an array to hold the partial results of stringifying this object value.
  8807. gap += indent;
  8808. partial = [];
  8809. // Is the value an array?
  8810. if (Object.prototype.toString.apply(value) === '[object Array]') {
  8811. // The value is an array. Stringify every element. Use null as a placeholder
  8812. // for non-JSON values.
  8813. length = value.length;
  8814. for (i = 0; i < length; i += 1) {
  8815. partial[i] = str(i, value) || 'null';
  8816. }
  8817. // Join all of the elements together, separated with commas, and wrap them in
  8818. // brackets.
  8819. v = partial.length === 0 ? '[]' :
  8820. gap ? '[\n' + gap +
  8821. partial.join(',\n' + gap) + '\n' +
  8822. mind + ']' :
  8823. '[' + partial.join(',') + ']';
  8824. gap = mind;
  8825. return v;
  8826. }
  8827. // If the replacer is an array, use it to select the members to be stringified.
  8828. if (rep && typeof rep === 'object') {
  8829. length = rep.length;
  8830. for (i = 0; i < length; i += 1) {
  8831. k = rep[i];
  8832. if (typeof k === 'string') {
  8833. v = str(k, value);
  8834. if (v) {
  8835. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  8836. }
  8837. }
  8838. }
  8839. } else {
  8840. // Otherwise, iterate through all of the keys in the object.
  8841. for (k in value) {
  8842. if (Object.hasOwnProperty.call(value, k)) {
  8843. v = str(k, value);
  8844. if (v) {
  8845. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  8846. }
  8847. }
  8848. }
  8849. }
  8850. // Join all of the member texts together, separated with commas,
  8851. // and wrap them in braces.
  8852. v = partial.length === 0 ? '{}' :
  8853. gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
  8854. mind + '}' : '{' + partial.join(',') + '}';
  8855. gap = mind;
  8856. return v;
  8857. }
  8858. }
  8859. // If the JSON object does not yet have a stringify method, give it one.
  8860. if (typeof JSON.stringify !== 'function') {
  8861. JSON.stringify = function (value, replacer, space) {
  8862. // The stringify method takes a value and an optional replacer, and an optional
  8863. // space parameter, and returns a JSON text. The replacer can be a function
  8864. // that can replace values, or an array of strings that will select the keys.
  8865. // A default replacer method can be provided. Use of the space parameter can
  8866. // produce text that is more easily readable.
  8867. var i;
  8868. gap = '';
  8869. indent = '';
  8870. // If the space parameter is a number, make an indent string containing that
  8871. // many spaces.
  8872. if (typeof space === 'number') {
  8873. for (i = 0; i < space; i += 1) {
  8874. indent += ' ';
  8875. }
  8876. // If the space parameter is a string, it will be used as the indent string.
  8877. } else if (typeof space === 'string') {
  8878. indent = space;
  8879. }
  8880. // If there is a replacer, it must be a function or an array.
  8881. // Otherwise, throw an error.
  8882. rep = replacer;
  8883. if (replacer && typeof replacer !== 'function' &&
  8884. (typeof replacer !== 'object' ||
  8885. typeof replacer.length !== 'number')) {
  8886. throw new Error('JSON.stringify');
  8887. }
  8888. // Make a fake root object containing our value under the key of ''.
  8889. // Return the result of stringifying the value.
  8890. return str('', {'': value});
  8891. };
  8892. }
  8893. // If the JSON object does not yet have a parse method, give it one.
  8894. if (typeof JSON.parse !== 'function') {
  8895. JSON.parse = function (text, reviver) {
  8896. // The parse method takes a text and an optional reviver function, and returns
  8897. // a JavaScript value if the text is a valid JSON text.
  8898. var j;
  8899. function walk(holder, key) {
  8900. // The walk method is used to recursively walk the resulting structure so
  8901. // that modifications can be made.
  8902. var k, v, value = holder[key];
  8903. if (value && typeof value === 'object') {
  8904. for (k in value) {
  8905. if (Object.hasOwnProperty.call(value, k)) {
  8906. v = walk(value, k);
  8907. if (v !== undefined) {
  8908. value[k] = v;
  8909. } else {
  8910. delete value[k];
  8911. }
  8912. }
  8913. }
  8914. }
  8915. return reviver.call(holder, key, value);
  8916. }
  8917. // Parsing happens in four stages. In the first stage, we replace certain
  8918. // Unicode characters with escape sequences. JavaScript handles many characters
  8919. // incorrectly, either silently deleting them, or treating them as line endings.
  8920. text = String(text);
  8921. cx['lastIndex'] = 0;
  8922. if (cx.test(text)) {
  8923. text = text.replace(cx, function (a) {
  8924. return '\\u' +
  8925. ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  8926. });
  8927. }
  8928. // In the second stage, we run the text against regular expressions that look
  8929. // for non-JSON patterns. We are especially concerned with '()' and 'new'
  8930. // because they can cause invocation, and '=' because it can cause mutation.
  8931. // But just to be safe, we want to reject all unexpected forms.
  8932. // We split the second stage into 4 regexp operations in order to work around
  8933. // crippling inefficiencies in IE's and Safari's regexp engines. First we
  8934. // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  8935. // replace all simple value tokens with ']' characters. Third, we delete all
  8936. // open brackets that follow a colon or comma or that begin the text. Finally,
  8937. // we look to see that the remaining characters are only whitespace or ']' or
  8938. // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  8939. if (/^[\],:{}\s]*$/
  8940. .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  8941. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  8942. .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  8943. // In the third stage we use the eval function to compile the text into a
  8944. // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  8945. // in JavaScript: it can begin a block or an object literal. We wrap the text
  8946. // in parens to eliminate the ambiguity.
  8947. j = eval('(' + text + ')');
  8948. // In the optional fourth stage, we recursively walk the new structure, passing
  8949. // each name/value pair to a reviver function for possible transformation.
  8950. return typeof reviver === 'function' ?
  8951. walk({'': j}, '') : j;
  8952. }
  8953. // If the text is not JSON parseable, then a SyntaxError is thrown.
  8954. throw new SyntaxError('JSON.parse');
  8955. };
  8956. }
  8957. return JSON;
  8958. }, {requires:['ua']});
  8959. /*
  8960. Copyright 2011, KISSY UI Library v1.30dev
  8961. MIT Licensed
  8962. build time: Dec 31 15:25
  8963. */
  8964. /**
  8965. * @fileOverview io shortcut
  8966. * @author yiminghe@gmail.com
  8967. */
  8968. KISSY.add("ajax", function (S, serializer, io, XhrObject) {
  8969. var undef = undefined;
  8970. // some shortcut
  8971. S.mix(io,
  8972. /**
  8973. * @lends io
  8974. */
  8975. {
  8976. XhrObject:XhrObject,
  8977. /**
  8978. * form 序列化
  8979. * @param formElement {HTMLFormElement} 将要序列化的 form 元素
  8980. */
  8981. serialize:serializer.serialize,
  8982. /**
  8983. * get 请求
  8984. * @param url
  8985. * @param data
  8986. * @param callback
  8987. * @param [dataType]
  8988. * @param [_t]
  8989. */
  8990. get:function (url, data, callback, dataType, _t) {
  8991. // data 参数可省略
  8992. if (S.isFunction(data)) {
  8993. dataType = callback;
  8994. callback = data;
  8995. data = undef;
  8996. }
  8997. return io({
  8998. type:_t || "get",
  8999. url:url,
  9000. data:data,
  9001. success:callback,
  9002. dataType:dataType
  9003. });
  9004. },
  9005. /**
  9006. * post 请求
  9007. * @param url
  9008. * @param data
  9009. * @param callback
  9010. * @param [dataType]
  9011. */
  9012. post:function (url, data, callback, dataType) {
  9013. if (S.isFunction(data)) {
  9014. dataType = callback;
  9015. callback = data;
  9016. data = undef;
  9017. }
  9018. return io.get(url, data, callback, dataType, "post");
  9019. },
  9020. /**
  9021. * jsonp 请求
  9022. * @param url
  9023. * @param data
  9024. * @param callback
  9025. */
  9026. jsonp:function (url, data, callback) {
  9027. if (S.isFunction(data)) {
  9028. callback = data;
  9029. data = undef;
  9030. }
  9031. return io.get(url, data, callback, "jsonp");
  9032. },
  9033. // 和 S.getScript 保持一致
  9034. // 更好的 getScript 可以用
  9035. /*
  9036. io({
  9037. dataType:'script'
  9038. });
  9039. */
  9040. getScript:S.getScript,
  9041. /**
  9042. * 获取 json 数据
  9043. * @param url
  9044. * @param data
  9045. * @param callback
  9046. */
  9047. getJSON:function (url, data, callback) {
  9048. if (S.isFunction(data)) {
  9049. callback = data;
  9050. data = undef;
  9051. }
  9052. return io.get(url, data, callback, "json");
  9053. },
  9054. /**
  9055. * 无刷新上传文件
  9056. * @param url
  9057. * @param form
  9058. * @param data
  9059. * @param callback
  9060. * @param [dataType]
  9061. */
  9062. upload:function (url, form, data, callback, dataType) {
  9063. if (S.isFunction(data)) {
  9064. dataType = callback;
  9065. callback = data;
  9066. data = undef;
  9067. }
  9068. return io({
  9069. url:url,
  9070. type:'post',
  9071. dataType:dataType,
  9072. form:form,
  9073. data:data,
  9074. success:callback
  9075. });
  9076. }
  9077. });
  9078. return io;
  9079. }, {
  9080. requires:[
  9081. "ajax/form-serializer",
  9082. "ajax/base",
  9083. "ajax/xhrobject",
  9084. "ajax/xhr",
  9085. "ajax/script",
  9086. "ajax/jsonp",
  9087. "ajax/form",
  9088. "ajax/iframe-upload"]
  9089. });/**
  9090. * @fileOverview a scalable client io framework
  9091. * @author yiminghe@gmail.com
  9092. */
  9093. KISSY.add("ajax/base", function (S, JSON, Event, XhrObject) {
  9094. var rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
  9095. rspace = /\s+/,
  9096. rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  9097. mirror = function (s) {
  9098. return s;
  9099. },
  9100. HTTP_PORT = 80,
  9101. HTTPS_PORT = 443,
  9102. rnoContent = /^(?:GET|HEAD)$/,
  9103. curLocation,
  9104. curLocationParts;
  9105. try {
  9106. curLocation = location.href;
  9107. } catch (e) {
  9108. S.log("ajax/base get curLocation error : ");
  9109. S.log(e);
  9110. // Use the href attribute of an A element
  9111. // since IE will modify it given document.location
  9112. curLocation = document.createElement("a");
  9113. curLocation.href = "";
  9114. curLocation = curLocation.href;
  9115. }
  9116. curLocationParts = rurl.exec(curLocation);
  9117. var isLocal = rlocalProtocol.test(curLocationParts[1]),
  9118. transports = {},
  9119. defaultConfig = {
  9120. // isLocal:isLocal,
  9121. type:"GET",
  9122. // only support utf-8 when post, encoding can not be changed actually
  9123. contentType:"application/x-www-form-urlencoded; charset=UTF-8",
  9124. async:true,
  9125. // whether add []
  9126. serializeArray:true,
  9127. // whether param data
  9128. processData:true,
  9129. /*
  9130. url:"",
  9131. context:null,
  9132. // 单位秒!!
  9133. timeout: 0,
  9134. data: null,
  9135. // 可取json | jsonp | script | xml | html | text | null | undefined
  9136. dataType: null,
  9137. username: null,
  9138. password: null,
  9139. cache: null,
  9140. mimeType:null,
  9141. xdr:{
  9142. subDomain:{
  9143. proxy:'http://xx.t.com/proxy.html'
  9144. },
  9145. src:''
  9146. },
  9147. headers: {},
  9148. xhrFields:{},
  9149. // jsonp script charset
  9150. scriptCharset:null,
  9151. crossdomain:false,
  9152. forceScript:false,
  9153. */
  9154. accepts:{
  9155. xml:"application/xml, text/xml",
  9156. html:"text/html",
  9157. text:"text/plain",
  9158. json:"application/json, text/javascript",
  9159. "*":"*/*"
  9160. },
  9161. converters:{
  9162. text:{
  9163. json:JSON.parse,
  9164. html:mirror,
  9165. text:mirror,
  9166. xml:S.parseXML
  9167. }
  9168. },
  9169. contents:{
  9170. xml:/xml/,
  9171. html:/html/,
  9172. json:/json/
  9173. }
  9174. };
  9175. defaultConfig.converters.html = defaultConfig.converters.text;
  9176. function setUpConfig(c) {
  9177. // deep mix
  9178. c = S.mix(S.clone(defaultConfig), c || {}, undefined, undefined, true);
  9179. if (!S.isBoolean(c.crossDomain)) {
  9180. var parts = rurl.exec(c.url.toLowerCase());
  9181. c.crossDomain = !!( parts &&
  9182. ( parts[ 1 ] != curLocationParts[ 1 ] || parts[ 2 ] != curLocationParts[ 2 ] ||
  9183. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? HTTP_PORT : HTTPS_PORT ) )
  9184. !=
  9185. ( curLocationParts[ 3 ] || ( curLocationParts[ 1 ] === "http:" ? HTTP_PORT : HTTPS_PORT ) ) )
  9186. );
  9187. }
  9188. if (c.processData && c.data && !S.isString(c.data)) {
  9189. // 必须 encodeURIComponent 编码 utf-8
  9190. c.data = S.param(c.data, undefined, undefined, c.serializeArray);
  9191. }
  9192. c.type = c.type.toUpperCase();
  9193. c.hasContent = !rnoContent.test(c.type);
  9194. if (!c.hasContent) {
  9195. if (c.data) {
  9196. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + c.data;
  9197. }
  9198. if (c.cache === false) {
  9199. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + "_ksTS=" + (S.now() + "_" + S.guid());
  9200. }
  9201. }
  9202. // 数据类型处理链,一步步将前面的数据类型转化成最后一个
  9203. c.dataType = S.trim(c.dataType || "*").split(rspace);
  9204. c.context = c.context || c;
  9205. return c;
  9206. }
  9207. function fire(eventType, xhr) {
  9208. /**
  9209. * @name io#complete
  9210. * @description 请求完成(成功或失败)后触发
  9211. * @event
  9212. * @param {Event.Object} e
  9213. * @param {Object} e.ajaxConfig 当前请求的配置
  9214. * @param {io.XhrObject} e.xhr 当前请求对象
  9215. */
  9216. /**
  9217. * @name io#success
  9218. * @description 请求成功后触发
  9219. * @event
  9220. * @param {Event.Object} e
  9221. * @param {Object} e.ajaxConfig 当前请求的配置
  9222. * @param {io.XhrObject} e.xhr 当前请求对象
  9223. */
  9224. /**
  9225. * @name io#error
  9226. * @description 请求失败后触发
  9227. * @event
  9228. * @param {Event.Object} e
  9229. * @param {Object} e.ajaxConfig 当前请求的配置
  9230. * @param {io.XhrObject} e.xhr 当前请求对象
  9231. */
  9232. io.fire(eventType, { ajaxConfig:xhr.config, xhr:xhr});
  9233. }
  9234. function handleXhrEvent(e) {
  9235. var xhr = this,
  9236. c = xhr.config,
  9237. type = e.type;
  9238. if (this.timeoutTimer) {
  9239. clearTimeout(this.timeoutTimer);
  9240. }
  9241. if (c[type]) {
  9242. c[type].call(c.context, xhr.responseData, xhr.statusText, xhr);
  9243. }
  9244. fire(type, xhr);
  9245. }
  9246. /**
  9247. * @name io
  9248. * @description kissy io framework
  9249. * @namespace io framework
  9250. * @function
  9251. * @param {Object} c 发送请求配置选项
  9252. * @param {String} c.url 请求地址
  9253. */
  9254. function io(c) {
  9255. if (!c.url) {
  9256. return undefined;
  9257. }
  9258. c = setUpConfig(c);
  9259. var xhr = new XhrObject(c);
  9260. /**
  9261. * @name io#start
  9262. * @description 生成请求对象前触发
  9263. * @event
  9264. * @param {Event.Object} e
  9265. * @param {Object} e.ajaxConfig 当前请求的配置
  9266. * @param {io.XhrObject} e.xhr 当前请求对象
  9267. */
  9268. fire("start", xhr);
  9269. var transportContructor = transports[c.dataType[0]] || transports["*"],
  9270. transport = new transportContructor(xhr);
  9271. xhr.transport = transport;
  9272. if (c.contentType) {
  9273. xhr.setRequestHeader("Content-Type", c.contentType);
  9274. }
  9275. var dataType = c.dataType[0],
  9276. accepts = c.accepts;
  9277. // Set the Accepts header for the server, depending on the dataType
  9278. xhr.setRequestHeader(
  9279. "Accept",
  9280. dataType && accepts[dataType] ?
  9281. accepts[ dataType ] + (dataType === "*" ? "" : ", */*; q=0.01" ) :
  9282. accepts[ "*" ]
  9283. );
  9284. // Check for headers option
  9285. for (var i in c.headers) {
  9286. xhr.setRequestHeader(i, c.headers[ i ]);
  9287. }
  9288. xhr.on("complete success error", handleXhrEvent);
  9289. xhr.readyState = 1;
  9290. /**
  9291. * @name io#send
  9292. * @description 发送请求前触发
  9293. * @event
  9294. * @param {Event.Object} e
  9295. * @param {Object} e.ajaxConfig 当前请求的配置
  9296. * @param {io.XhrObject} xhr 当前请求对象
  9297. */
  9298. fire("send", xhr);
  9299. // Timeout
  9300. if (c.async && c.timeout > 0) {
  9301. xhr.timeoutTimer = setTimeout(function () {
  9302. xhr.abort("timeout");
  9303. }, c.timeout * 1000);
  9304. }
  9305. try {
  9306. // flag as sending
  9307. xhr.state = 1;
  9308. transport.send();
  9309. } catch (e) {
  9310. // Propagate exception as error if not done
  9311. if (xhr.status < 2) {
  9312. xhr.callback(-1, e);
  9313. // Simply rethrow otherwise
  9314. } else {
  9315. S.error(e);
  9316. }
  9317. }
  9318. return xhr;
  9319. }
  9320. S.mix(io, Event.Target);
  9321. S.mix(io, {
  9322. isLocal:isLocal,
  9323. setupConfig:function (setting) {
  9324. S.mix(defaultConfig, setting, undefined, undefined, true);
  9325. },
  9326. setupTransport:function (name, fn) {
  9327. transports[name] = fn;
  9328. },
  9329. getTransport:function (name) {
  9330. return transports[name];
  9331. },
  9332. getConfig:function () {
  9333. return defaultConfig;
  9334. }
  9335. });
  9336. return io;
  9337. },
  9338. {
  9339. requires:["json", "event", "./xhrobject"]
  9340. });
  9341. /**
  9342. * 借鉴 jquery,优化减少闭包使用
  9343. *
  9344. * TODO:
  9345. * ifModified mode 是否需要?
  9346. * 优点:
  9347. * 不依赖浏览器处理,ajax 请求浏览不会自动加 If-Modified-Since If-None-Match ??
  9348. * 缺点:
  9349. * 内存占用
  9350. **//**
  9351. * @fileOverview form data serialization util
  9352. * @author yiminghe@gmail.com
  9353. */
  9354. KISSY.add("ajax/form-serializer", function(S, DOM) {
  9355. var rselectTextarea = /^(?:select|textarea)/i,
  9356. rCRLF = /\r?\n/g,
  9357. rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i;
  9358. return {
  9359. /**
  9360. * 序列化表单元素
  9361. * @param {String|HTMLElement[]|HTMLElement|Node} forms
  9362. */
  9363. serialize:function(forms) {
  9364. var elements = [],data = {};
  9365. DOM.query(forms).each(function(el) {
  9366. // form 取其表单元素集合
  9367. // 其他直接取自身
  9368. var subs = el.elements ? S.makeArray(el.elements) : [el];
  9369. elements.push.apply(elements, subs);
  9370. });
  9371. // 对表单元素进行过滤,具备有效值的才保留
  9372. elements = S.filter(elements, function(el) {
  9373. // 有名字
  9374. return el.name &&
  9375. // 不被禁用
  9376. !el.disabled &&
  9377. (
  9378. // radio,checkbox 被选择了
  9379. el.checked ||
  9380. // select 或者 textarea
  9381. rselectTextarea.test(el.nodeName) ||
  9382. // input 类型
  9383. rinput.test(el.type)
  9384. );
  9385. // 这样子才取值
  9386. });
  9387. S.each(elements, function(el) {
  9388. var val = DOM.val(el),vs;
  9389. // 字符串换行平台归一化
  9390. val = S.map(S.makeArray(val), function(v) {
  9391. return v.replace(rCRLF, "\r\n");
  9392. });
  9393. // 全部搞成数组,防止同名
  9394. vs = data[el.name] = data[el.name] || [];
  9395. vs.push.apply(vs, val);
  9396. });
  9397. // 名值键值对序列化,数组元素名字前不加 []
  9398. return S.param(data, undefined, undefined, false);
  9399. }
  9400. };
  9401. }, {
  9402. requires:['dom']
  9403. });/**
  9404. * @fileOverview process form config
  9405. * @author yiminghe@gmail.com
  9406. */
  9407. KISSY.add("ajax/form", function(S, io, DOM, FormSerializer) {
  9408. io.on("start", function(e) {
  9409. var xhr = e.xhr,
  9410. c = xhr.config;
  9411. // serialize form if needed
  9412. if (c.form) {
  9413. var form = DOM.get(c.form),
  9414. enctype = form['encoding'] || form.enctype;
  9415. // 上传有其他方法
  9416. if (enctype.toLowerCase() != "multipart/form-data") {
  9417. // when get need encode
  9418. var formParam = FormSerializer.serialize(form);
  9419. if (formParam) {
  9420. if (c.hasContent) {
  9421. // post 加到 data 中
  9422. c.data = c.data || "";
  9423. if (c.data) {
  9424. c.data += "&";
  9425. }
  9426. c.data += formParam;
  9427. } else {
  9428. // get 直接加到 url
  9429. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + formParam;
  9430. }
  9431. }
  9432. } else {
  9433. var d = c.dataType[0];
  9434. if (d == "*") {
  9435. d = "text";
  9436. }
  9437. c.dataType.length = 2;
  9438. c.dataType[0] = "iframe";
  9439. c.dataType[1] = d;
  9440. }
  9441. }
  9442. });
  9443. return io;
  9444. }, {
  9445. requires:['./base',"dom","./form-serializer"]
  9446. });/**
  9447. * @fileOverview non-refresh upload file with form by iframe
  9448. * @author yiminghe@gmail.com
  9449. */
  9450. KISSY.add("ajax/iframe-upload", function(S, DOM, Event, io) {
  9451. var doc = document;
  9452. var OK_CODE = 200,ERROR_CODE = 500,BREATH_INTERVAL = 30;
  9453. // iframe 内的内容就是 body.innerText
  9454. io.setupConfig({
  9455. converters:{
  9456. // iframe 到其他类型的转化和 text 一样
  9457. iframe:io.getConfig().converters.text,
  9458. text:{
  9459. iframe:function(text) {
  9460. return text;
  9461. }
  9462. }}});
  9463. function createIframe(xhr) {
  9464. var id = S.guid("ajax-iframe");
  9465. xhr.iframe = DOM.create("<iframe " +
  9466. " id='" + id + "'" +
  9467. // need name for target of form
  9468. " name='" + id + "'" +
  9469. " style='position:absolute;left:-9999px;top:-9999px;'/>");
  9470. xhr.iframeId = id;
  9471. DOM.prepend(xhr.iframe, doc.body || doc.documentElement);
  9472. }
  9473. function addDataToForm(data, form, serializeArray) {
  9474. data = S.unparam(data);
  9475. var ret = [];
  9476. for (var d in data) {
  9477. var isArray = S.isArray(data[d]),
  9478. vs = S.makeArray(data[d]);
  9479. // 数组和原生一样对待,创建多个同名输入域
  9480. for (var i = 0; i < vs.length; i++) {
  9481. var e = doc.createElement("input");
  9482. e.type = 'hidden';
  9483. e.name = d + (isArray && serializeArray ? "[]" : "");
  9484. e.value = vs[i];
  9485. DOM.append(e, form);
  9486. ret.push(e);
  9487. }
  9488. }
  9489. return ret;
  9490. }
  9491. function removeFieldsFromData(fields) {
  9492. DOM.remove(fields);
  9493. }
  9494. function IframeTransport(xhr) {
  9495. this.xhr = xhr;
  9496. }
  9497. S.augment(IframeTransport, {
  9498. send:function() {
  9499. //debugger
  9500. var xhr = this.xhr,
  9501. c = xhr.config,
  9502. fields,
  9503. form = DOM.get(c.form);
  9504. this.attrs = {
  9505. target:DOM.attr(form, "target") || "",
  9506. action:DOM.attr(form, "action") || ""
  9507. };
  9508. this.form = form;
  9509. createIframe(xhr);
  9510. // set target to iframe to avoid main page refresh
  9511. DOM.attr(form, {"target": xhr.iframeId,"action": c.url});
  9512. if (c.data) {
  9513. fields = addDataToForm(c.data, form, c.serializeArray);
  9514. }
  9515. this.fields = fields;
  9516. var iframe = xhr.iframe;
  9517. Event.on(iframe, "load error", this._callback, this);
  9518. form.submit();
  9519. },
  9520. _callback:function(event
  9521. //, abort
  9522. ) {
  9523. //debugger
  9524. var form = this.form,
  9525. xhr = this.xhr,
  9526. eventType = event.type,
  9527. iframe = xhr.iframe;
  9528. // 防止重复调用 , 成功后 abort
  9529. if (!iframe) {
  9530. return;
  9531. }
  9532. DOM.attr(form, this.attrs);
  9533. if (eventType == "load") {
  9534. var iframeDoc = iframe.contentWindow.document;
  9535. xhr.responseXML = iframeDoc;
  9536. xhr.responseText = DOM.text(iframeDoc.body);
  9537. xhr.callback(OK_CODE, "success");
  9538. } else if (eventType == 'error') {
  9539. xhr.callback(ERROR_CODE, "error");
  9540. }
  9541. removeFieldsFromData(this.fields);
  9542. Event.detach(iframe);
  9543. setTimeout(function() {
  9544. // firefox will keep loading if not settimeout
  9545. DOM.remove(iframe);
  9546. }, BREATH_INTERVAL);
  9547. // nullify to prevent memory leak?
  9548. xhr.iframe = null;
  9549. },
  9550. abort:function() {
  9551. this._callback(0, 1);
  9552. }
  9553. });
  9554. io.setupTransport("iframe", IframeTransport);
  9555. return io;
  9556. }, {
  9557. requires:["dom","event","./base"]
  9558. });/**
  9559. * @fileOverview jsonp transport based on script transport
  9560. * @author yiminghe@gmail.com
  9561. */
  9562. KISSY.add("ajax/jsonp", function (S, io) {
  9563. io.setupConfig({
  9564. jsonp:"callback",
  9565. jsonpCallback:function () {
  9566. //不使用 now() ,极端情况下可能重复
  9567. return S.guid("jsonp");
  9568. }
  9569. });
  9570. io.on("start", function (e) {
  9571. var xhr = e.xhr, c = xhr.config;
  9572. if (c.dataType[0] == "jsonp") {
  9573. var response,
  9574. cJsonpCallback = c.jsonpCallback,
  9575. jsonpCallback = S.isFunction(cJsonpCallback) ?
  9576. cJsonpCallback() :
  9577. cJsonpCallback,
  9578. previous = window[ jsonpCallback ];
  9579. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + c.jsonp + "=" + jsonpCallback;
  9580. // build temporary JSONP function
  9581. window[jsonpCallback] = function (r) {
  9582. // 使用数组,区别:故意调用了 jsonpCallback(undefined) 与 根本没有调用
  9583. // jsonp 返回了数组
  9584. if (arguments.length > 1) {
  9585. r = S.makeArray(arguments);
  9586. }
  9587. response = [r];
  9588. };
  9589. // cleanup whether success or failure
  9590. xhr.on("complete", function () {
  9591. window[ jsonpCallback ] = previous;
  9592. if (previous === undefined) {
  9593. try {
  9594. delete window[ jsonpCallback ];
  9595. } catch (e) {
  9596. //S.log("delete window variable error : ");
  9597. //S.log(e);
  9598. }
  9599. } else if (response) {
  9600. // after io success handler called
  9601. // then call original existed jsonpcallback
  9602. previous(response[0]);
  9603. }
  9604. });
  9605. xhr.converters = xhr.converters || {};
  9606. xhr.converters.script = xhr.converters.script || {};
  9607. // script -> jsonp ,jsonp need to see json not as script
  9608. // if ie onload a 404 file or all browsers onload an invalid script
  9609. // 404/invalid will be caught here
  9610. // because response is undefined( jsonp callback is never called)
  9611. // error throwed will be caught in conversion step
  9612. // and KISSY will notify user by error callback
  9613. xhr.converters.script.json = function () {
  9614. if (!response) {
  9615. S.error(" not call jsonpCallback : " + jsonpCallback)
  9616. }
  9617. return response[0];
  9618. };
  9619. c.dataType.length = 2;
  9620. // 利用 script transport 发送 script 请求
  9621. c.dataType[0] = 'script';
  9622. c.dataType[1] = 'json';
  9623. }
  9624. });
  9625. return io;
  9626. }, {
  9627. requires:['./base']
  9628. });
  9629. /**
  9630. * @fileOverview script transport for kissy io
  9631. * @description: modified version of S.getScript , add abort ability
  9632. * @author yiminghe@gmail.com
  9633. */
  9634. KISSY.add("ajax/script", function(S, io) {
  9635. var doc = document;
  9636. var OK_CODE = 200,ERROR_CODE = 500;
  9637. io.setupConfig({
  9638. accepts:{
  9639. script:"text/javascript, " +
  9640. "application/javascript, " +
  9641. "application/ecmascript, " +
  9642. "application/x-ecmascript"
  9643. },
  9644. contents:{
  9645. script:/javascript|ecmascript/
  9646. },
  9647. converters:{
  9648. text:{
  9649. // 如果以 xhr+eval 需要下面的,
  9650. // 否则直接 script node 不需要,引擎自己执行了,
  9651. // 不需要手动 eval
  9652. script:function(text) {
  9653. S.globalEval(text);
  9654. return text;
  9655. }
  9656. }
  9657. }
  9658. });
  9659. function ScriptTransport(xhrObj) {
  9660. // 优先使用 xhr+eval 来执行脚本, ie 下可以探测到(更多)失败状态
  9661. if (!xhrObj.config.crossDomain &&
  9662. !xhrObj.config['forceScript']) {
  9663. return new (io.getTransport("*"))(xhrObj);
  9664. }
  9665. this.xhrObj = xhrObj;
  9666. return 0;
  9667. }
  9668. S.augment(ScriptTransport, {
  9669. send:function() {
  9670. var self = this,
  9671. script,
  9672. xhrObj = this.xhrObj,
  9673. c = xhrObj.config,
  9674. head = doc['head'] ||
  9675. doc.getElementsByTagName("head")[0] ||
  9676. doc.documentElement;
  9677. self.head = head;
  9678. script = doc.createElement("script");
  9679. self.script = script;
  9680. script.async = "async";
  9681. if (c['scriptCharset']) {
  9682. script.charset = c['scriptCharset'];
  9683. }
  9684. script.src = c.url;
  9685. script.onerror =
  9686. script.onload =
  9687. script.onreadystatechange = function(e) {
  9688. e = e || window.event;
  9689. // firefox onerror 没有 type ?!
  9690. self._callback((e.type || "error").toLowerCase());
  9691. };
  9692. head.insertBefore(script, head.firstChild);
  9693. },
  9694. _callback:function(event, abort) {
  9695. var script = this.script,
  9696. xhrObj = this.xhrObj,
  9697. head = this.head;
  9698. // 防止重复调用,成功后 abort
  9699. if (!script) {
  9700. return;
  9701. }
  9702. if (abort ||
  9703. !script.readyState ||
  9704. /loaded|complete/.test(script.readyState)
  9705. || event == "error"
  9706. ) {
  9707. script['onerror'] = script.onload = script.onreadystatechange = null;
  9708. // Remove the script
  9709. if (head && script.parentNode) {
  9710. // ie 报错载入无效 js
  9711. // 怎么 abort ??
  9712. // script.src = "#";
  9713. head.removeChild(script);
  9714. }
  9715. this.script = undefined;
  9716. this.head = undefined;
  9717. // Callback if not abort
  9718. if (!abort && event != "error") {
  9719. xhrObj.callback(OK_CODE, "success");
  9720. }
  9721. // 非 ie<9 可以判断出来
  9722. else if (event == "error") {
  9723. xhrObj.callback(ERROR_CODE, "scripterror");
  9724. }
  9725. }
  9726. },
  9727. abort:function() {
  9728. this._callback(0, 1);
  9729. }
  9730. });
  9731. io.setupTransport("script", ScriptTransport);
  9732. return io;
  9733. }, {
  9734. requires:['./base','./xhr']
  9735. });/**
  9736. * @fileOverview solve io between sub domains using proxy page
  9737. * @author yiminghe@gmail.com
  9738. */
  9739. KISSY.add("ajax/subdomain", function(S, XhrBase, Event, DOM) {
  9740. var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  9741. PROXY_PAGE = "/sub_domain_proxy.html",
  9742. doc = document,
  9743. iframeMap = {
  9744. // hostname:{iframe: , ready:}
  9745. };
  9746. function SubDomain(xhrObj) {
  9747. var self = this,
  9748. c = xhrObj.config;
  9749. self.xhrObj = xhrObj;
  9750. var m = c.url.match(rurl);
  9751. self.__hostname = m[2];
  9752. self.__protocol = m[1];
  9753. c.crossDomain = false;
  9754. }
  9755. S.augment(SubDomain, XhrBase.proto, {
  9756. send:function() {
  9757. var self = this,
  9758. c = self.xhrObj.config,
  9759. hostname = self.__hostname,
  9760. iframe,
  9761. iframeDesc = iframeMap[hostname];
  9762. var proxy = PROXY_PAGE;
  9763. if (c['xdr'] && c['xdr']['subDomain'] && c['xdr']['subDomain'].proxy) {
  9764. proxy = c['xdr']['subDomain'].proxy;
  9765. }
  9766. if (iframeDesc && iframeDesc.ready) {
  9767. self.xhr = XhrBase.xhr(0, iframeDesc.iframe.contentWindow);
  9768. if (self.xhr) {
  9769. self.sendInternal();
  9770. } else {
  9771. S.error("document.domain not set correctly!");
  9772. }
  9773. return;
  9774. }
  9775. if (!iframeDesc) {
  9776. iframeDesc = iframeMap[hostname] = {};
  9777. iframe = iframeDesc.iframe = document.createElement("iframe");
  9778. DOM.css(iframe, {
  9779. position:'absolute',
  9780. left:'-9999px',
  9781. top:'-9999px'
  9782. });
  9783. DOM.prepend(iframe, doc.body || doc.documentElement);
  9784. iframe.src = self.__protocol + "//" + hostname + proxy;
  9785. } else {
  9786. iframe = iframeDesc.iframe;
  9787. }
  9788. Event.on(iframe, "load", _onLoad, self);
  9789. }
  9790. });
  9791. function _onLoad() {
  9792. var self = this,
  9793. hostname = self.__hostname,
  9794. iframeDesc = iframeMap[hostname];
  9795. iframeDesc.ready = 1;
  9796. Event.detach(iframeDesc.iframe, "load", _onLoad, self);
  9797. self.send();
  9798. }
  9799. return SubDomain;
  9800. }, {
  9801. requires:['./xhrbase','event','dom']
  9802. });/**
  9803. * @fileOverview use flash to accomplish cross domain request , usage scenario ? why not jsonp ?
  9804. * @author yiminghe@gmail.com
  9805. */
  9806. KISSY.add("ajax/xdr", function(S, io, DOM) {
  9807. var // current running request instances
  9808. maps = {},
  9809. ID = "io_swf",
  9810. // flash transporter
  9811. flash,
  9812. doc = document,
  9813. // whether create the flash transporter
  9814. init = false;
  9815. // create the flash transporter
  9816. function _swf(uri, _, uid) {
  9817. if (init) {
  9818. return;
  9819. }
  9820. init = true;
  9821. var o = '<object id="' + ID +
  9822. '" type="application/x-shockwave-flash" data="' +
  9823. uri + '" width="0" height="0">' +
  9824. '<param name="movie" value="' +
  9825. uri + '" />' +
  9826. '<param name="FlashVars" value="yid=' +
  9827. _ + '&uid=' +
  9828. uid +
  9829. '&host=KISSY.io" />' +
  9830. '<param name="allowScriptAccess" value="always" />' +
  9831. '</object>',
  9832. c = doc.createElement('div');
  9833. DOM.prepend(c, doc.body || doc.documentElement);
  9834. c.innerHTML = o;
  9835. }
  9836. function XdrTransport(xhrObj) {
  9837. S.log("use flash xdr");
  9838. this.xhrObj = xhrObj;
  9839. }
  9840. S.augment(XdrTransport, {
  9841. // rewrite send to support flash xdr
  9842. send:function() {
  9843. var self = this,
  9844. xhrObj = self.xhrObj,
  9845. c = xhrObj.config;
  9846. var xdr = c['xdr'] || {};
  9847. // 不提供则使用 cdn 默认的 flash
  9848. _swf(xdr.src || (S.Config.base + "ajax/io.swf"), 1, 1);
  9849. // 简便起见,用轮训
  9850. if (!flash) {
  9851. // S.log("detect xdr flash");
  9852. setTimeout(function() {
  9853. self.send();
  9854. }, 200);
  9855. return;
  9856. }
  9857. self._uid = S.guid();
  9858. maps[self._uid] = self;
  9859. // ie67 send 出错?
  9860. flash.send(c.url, {
  9861. id:self._uid,
  9862. uid:self._uid,
  9863. method:c.type,
  9864. data:c.hasContent && c.data || {}
  9865. });
  9866. },
  9867. abort:function() {
  9868. flash.abort(this._uid);
  9869. },
  9870. _xdrResponse:function(e, o) {
  9871. // S.log(e);
  9872. var self = this,
  9873. ret,
  9874. xhrObj = self.xhrObj;
  9875. // need decodeURI to get real value from flash returned value
  9876. xhrObj.responseText = decodeURI(o.c.responseText);
  9877. switch (e) {
  9878. case 'success':
  9879. ret = { status: 200, statusText: "success" };
  9880. delete maps[o.id];
  9881. break;
  9882. case 'abort':
  9883. delete maps[o.id];
  9884. break;
  9885. case 'timeout':
  9886. case 'transport error':
  9887. case 'failure':
  9888. delete maps[o.id];
  9889. ret = { status: 500, statusText: e };
  9890. break;
  9891. }
  9892. if (ret) {
  9893. xhrObj.callback(ret.status, ret.statusText);
  9894. }
  9895. }
  9896. });
  9897. /*called by flash*/
  9898. io['applyTo'] = function(_, cmd, args) {
  9899. // S.log(cmd + " execute");
  9900. var cmds = cmd.split("."),
  9901. func = S;
  9902. S.each(cmds, function(c) {
  9903. func = func[c];
  9904. });
  9905. func.apply(null, args);
  9906. };
  9907. // when flash is loaded
  9908. io['xdrReady'] = function() {
  9909. flash = doc.getElementById(ID);
  9910. };
  9911. /**
  9912. * when response is returned from server
  9913. * @param e response status
  9914. * @param o internal data
  9915. * @param c internal data
  9916. */
  9917. io['xdrResponse'] = function(e, o, c) {
  9918. var xhr = maps[o.uid];
  9919. xhr && xhr._xdrResponse(e, o, c);
  9920. };
  9921. // export io for flash to call
  9922. S.io = io;
  9923. return XdrTransport;
  9924. }, {
  9925. requires:["./base",'dom']
  9926. });/**
  9927. * @fileOverview ajax xhr transport class , route subdomain , xdr
  9928. * @author yiminghe@gmail.com
  9929. */
  9930. KISSY.add("ajax/xhr", function(S, io, XhrBase, SubDomain, XdrTransport) {
  9931. var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/;
  9932. var _XDomainRequest = window['XDomainRequest'];
  9933. var detectXhr = XhrBase.xhr();
  9934. if (detectXhr) {
  9935. // slice last two pars
  9936. // xx.taobao.com => taobao.com
  9937. function getMainDomain(host) {
  9938. var t = host.split('.');
  9939. if (t.length < 2) {
  9940. return t.join(".");
  9941. } else {
  9942. return t.reverse().slice(0, 2).reverse().join('.');
  9943. }
  9944. }
  9945. function XhrTransport(xhrObj) {
  9946. var c = xhrObj.config,
  9947. xdrCfg = c['xdr'] || {};
  9948. if (c.crossDomain) {
  9949. var parts = c.url.match(rurl);
  9950. // 跨子域
  9951. if (getMainDomain(location.hostname) == getMainDomain(parts[2])) {
  9952. return new SubDomain(xhrObj);
  9953. }
  9954. /**
  9955. * ie>7 强制使用 flash xdr
  9956. */
  9957. if (!("withCredentials" in detectXhr) &&
  9958. (String(xdrCfg.use) === "flash" || !_XDomainRequest)) {
  9959. return new XdrTransport(xhrObj);
  9960. }
  9961. }
  9962. this.xhrObj = xhrObj;
  9963. return undefined;
  9964. }
  9965. S.augment(XhrTransport, XhrBase.proto, {
  9966. send:function() {
  9967. var self = this,
  9968. xhrObj = self.xhrObj,
  9969. c = xhrObj.config;
  9970. self.xhr = XhrBase.xhr(c.crossDomain);
  9971. self.sendInternal();
  9972. }
  9973. });
  9974. io.setupTransport("*", XhrTransport);
  9975. }
  9976. return io;
  9977. }, {
  9978. requires:["./base",'./xhrbase','./subdomain',"./xdr"]
  9979. });
  9980. /**
  9981. * 借鉴 jquery,优化使用原型替代闭包
  9982. **//**
  9983. * @fileOverview base for xhr and subdomain
  9984. * @author yiminghe@gmail.com
  9985. */
  9986. KISSY.add("ajax/xhrbase", function (S, io) {
  9987. var OK_CODE = 200,
  9988. win = window,
  9989. // http://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx
  9990. _XDomainRequest = win['XDomainRequest'],
  9991. NO_CONTENT_CODE = 204,
  9992. NOT_FOUND_CODE = 404,
  9993. NO_CONTENT_CODE2 = 1223,
  9994. XhrBase = {
  9995. proto:{}
  9996. };
  9997. function createStandardXHR(_, refWin) {
  9998. try {
  9999. return new (refWin || win)['XMLHttpRequest']();
  10000. } catch (e) {
  10001. //S.log("createStandardXHR error");
  10002. }
  10003. return undefined;
  10004. }
  10005. function createActiveXHR(_, refWin) {
  10006. try {
  10007. return new (refWin || win)['ActiveXObject']("Microsoft.XMLHTTP");
  10008. } catch (e) {
  10009. S.log("createActiveXHR error");
  10010. }
  10011. return undefined;
  10012. }
  10013. XhrBase.xhr = win.ActiveXObject ? function (crossDomain, refWin) {
  10014. if (crossDomain && _XDomainRequest) {
  10015. return new _XDomainRequest();
  10016. }
  10017. // ie7 XMLHttpRequest 不能访问本地文件
  10018. return !io.isLocal && createStandardXHR(crossDomain, refWin) || createActiveXHR(crossDomain, refWin);
  10019. } : createStandardXHR;
  10020. function isInstanceOfXDomainRequest(xhr) {
  10021. return _XDomainRequest && (xhr instanceof _XDomainRequest);
  10022. }
  10023. S.mix(XhrBase.proto, {
  10024. sendInternal:function () {
  10025. var self = this,
  10026. xhrObj = self.xhrObj,
  10027. c = xhrObj.config;
  10028. var xhr = self.xhr,
  10029. xhrFields,
  10030. i;
  10031. if (c['username']) {
  10032. xhr.open(c.type, c.url, c.async, c['username'], c.password)
  10033. } else {
  10034. xhr.open(c.type, c.url, c.async);
  10035. }
  10036. if (xhrFields = c['xhrFields']) {
  10037. for (i in xhrFields) {
  10038. if (xhrFields.hasOwnProperty(i)) {
  10039. xhr[ i ] = xhrFields[ i ];
  10040. }
  10041. }
  10042. }
  10043. // Override mime type if supported
  10044. if (xhrObj.mimeType && xhr.overrideMimeType) {
  10045. xhr.overrideMimeType(xhrObj.mimeType);
  10046. }
  10047. // yui3 and jquery both have
  10048. if (!c.crossDomain && !xhrObj.requestHeaders["X-Requested-With"]) {
  10049. xhrObj.requestHeaders[ "X-Requested-With" ] = "XMLHttpRequest";
  10050. }
  10051. try {
  10052. // 跨域时,不能设,否则请求变成
  10053. // OPTIONS /xhr/r.php HTTP/1.1
  10054. if (!c.crossDomain) {
  10055. for (i in xhrObj.requestHeaders) {
  10056. xhr.setRequestHeader(i, xhrObj.requestHeaders[ i ]);
  10057. }
  10058. }
  10059. } catch (e) {
  10060. S.log("setRequestHeader in xhr error : ");
  10061. S.log(e);
  10062. }
  10063. xhr.send(c.hasContent && c.data || null);
  10064. if (!c.async || xhr.readyState == 4) {
  10065. self._callback();
  10066. } else {
  10067. // _XDomainRequest 单独的回调机制
  10068. if (isInstanceOfXDomainRequest(xhr)) {
  10069. xhr.onload = function () {
  10070. xhr.readyState = 4;
  10071. xhr.status = 200;
  10072. self._callback();
  10073. };
  10074. xhr.onerror = function () {
  10075. xhr.readyState = 4;
  10076. xhr.status = 500;
  10077. self._callback();
  10078. };
  10079. } else {
  10080. xhr.onreadystatechange = function () {
  10081. self._callback();
  10082. };
  10083. }
  10084. }
  10085. },
  10086. // 由 xhrObj.abort 调用,自己不可以调用 xhrObj.abort
  10087. abort:function () {
  10088. this._callback(0, 1);
  10089. },
  10090. _callback:function (event, abort) {
  10091. // Firefox throws exceptions when accessing properties
  10092. // of an xhr when a network error occured
  10093. // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
  10094. try {
  10095. var self = this,
  10096. xhr = self.xhr,
  10097. xhrObj = self.xhrObj,
  10098. c = xhrObj.config;
  10099. //abort or complete
  10100. if (abort || xhr.readyState == 4) {
  10101. // ie6 ActiveObject 设置不恰当属性导致出错
  10102. if (isInstanceOfXDomainRequest(xhr)) {
  10103. xhr.onerror = S.noop;
  10104. xhr.onload = S.noop;
  10105. } else {
  10106. // ie6 ActiveObject 只能设置,不能读取这个属性,否则出错!
  10107. xhr.onreadystatechange = S.noop;
  10108. }
  10109. if (abort) {
  10110. // 完成以后 abort 不要调用
  10111. if (xhr.readyState !== 4) {
  10112. xhr.abort();
  10113. }
  10114. } else {
  10115. var status = xhr.status;
  10116. // _XDomainRequest 不能获取响应头
  10117. if (!isInstanceOfXDomainRequest(xhr)) {
  10118. xhrObj.responseHeadersString = xhr.getAllResponseHeaders();
  10119. }
  10120. var xml = xhr.responseXML;
  10121. // Construct response list
  10122. if (xml && xml.documentElement /* #4958 */) {
  10123. xhrObj.responseXML = xml;
  10124. }
  10125. xhrObj.responseText = xhr.responseText;
  10126. // Firefox throws an exception when accessing
  10127. // statusText for faulty cross-domain requests
  10128. try {
  10129. var statusText = xhr.statusText;
  10130. } catch (e) {
  10131. S.log("xhr statustext error : ");
  10132. S.log(e);
  10133. // We normalize with Webkit giving an empty statusText
  10134. statusText = "";
  10135. }
  10136. // Filter status for non standard behaviors
  10137. // If the request is local and we have data: assume a success
  10138. // (success with no data won't get notified, that's the best we
  10139. // can do given current implementations)
  10140. if (!status && io.isLocal && !c.crossDomain) {
  10141. status = xhrObj.responseText ? OK_CODE : NOT_FOUND_CODE;
  10142. // IE - #1450: sometimes returns 1223 when it should be 204
  10143. } else if (status === NO_CONTENT_CODE2) {
  10144. status = NO_CONTENT_CODE;
  10145. }
  10146. xhrObj.callback(status, statusText);
  10147. }
  10148. }
  10149. } catch (firefoxAccessException) {
  10150. xhr.onreadystatechange = S.noop;
  10151. if (!abort) {
  10152. xhrObj.callback(-1, firefoxAccessException);
  10153. }
  10154. }
  10155. }
  10156. });
  10157. return XhrBase;
  10158. }, {
  10159. requires:['./base']
  10160. });/**
  10161. * @fileOverview encapsulation of io object . as transaction object in yui3
  10162. * @author yiminghe@gmail.com
  10163. */
  10164. KISSY.add("ajax/xhrobject", function(S, Event) {
  10165. var OK_CODE = 200,
  10166. MULTIPLE_CHOICES = 300,
  10167. NOT_MODIFIED = 304,
  10168. // get individual response header from responseheader str
  10169. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg;
  10170. function handleResponseData(xhr) {
  10171. // text xml 是否原生转化支持
  10172. var text = xhr.responseText,
  10173. xml = xhr.responseXML,
  10174. c = xhr.config,
  10175. cConverts = c.converters,
  10176. xConverts = xhr.converters || {},
  10177. type,
  10178. responseData,
  10179. contents = c.contents,
  10180. dataType = c.dataType;
  10181. // 例如 script 直接是js引擎执行,没有返回值,不需要自己处理初始返回值
  10182. // jsonp 时还需要把 script 转换成 json,后面还得自己来
  10183. if (text || xml) {
  10184. var contentType = xhr.mimeType || xhr.getResponseHeader("Content-Type");
  10185. // 去除无用的通用格式
  10186. while (dataType[0] == "*") {
  10187. dataType.shift();
  10188. }
  10189. if (!dataType.length) {
  10190. // 获取源数据格式,放在第一个
  10191. for (type in contents) {
  10192. if (contents[type].test(contentType)) {
  10193. if (dataType[0] != type) {
  10194. dataType.unshift(type);
  10195. }
  10196. break;
  10197. }
  10198. }
  10199. }
  10200. // 服务器端没有告知(并且客户端没有mimetype)默认 text 类型
  10201. dataType[0] = dataType[0] || "text";
  10202. //获得合适的初始数据
  10203. if (dataType[0] == "text" && text !== undefined) {
  10204. responseData = text;
  10205. }
  10206. // 有 xml 值才直接取,否则可能还要从 xml 转
  10207. else if (dataType[0] == "xml" && xml !== undefined) {
  10208. responseData = xml;
  10209. } else {
  10210. // 看能否从 text xml 转换到合适数据
  10211. S.each(["text","xml"], function(prevType) {
  10212. var type = dataType[0],
  10213. converter = xConverts[prevType] && xConverts[prevType][type] ||
  10214. cConverts[prevType] && cConverts[prevType][type];
  10215. if (converter) {
  10216. dataType.unshift(prevType);
  10217. responseData = prevType == "text" ? text : xml;
  10218. return false;
  10219. }
  10220. });
  10221. }
  10222. }
  10223. var prevType = dataType[0];
  10224. // 按照转化链把初始数据转换成我们想要的数据类型
  10225. for (var i = 1; i < dataType.length; i++) {
  10226. type = dataType[i];
  10227. var converter = xConverts[prevType] && xConverts[prevType][type] ||
  10228. cConverts[prevType] && cConverts[prevType][type];
  10229. if (!converter) {
  10230. throw "no covert for " + prevType + " => " + type;
  10231. }
  10232. responseData = converter(responseData);
  10233. prevType = type;
  10234. }
  10235. xhr.responseData = responseData;
  10236. }
  10237. /**
  10238. * @class 请求对象类型
  10239. * @memberOf io
  10240. * @param c 请求发送配置选项
  10241. */
  10242. function XhrObject(c) {
  10243. S.mix(this, {
  10244. // 结构化数据,如 json
  10245. responseData:null,
  10246. config:c || {},
  10247. timeoutTimer:null,
  10248. responseText:null,
  10249. responseXML:null,
  10250. responseHeadersString:"",
  10251. responseHeaders:null,
  10252. requestHeaders:{},
  10253. readyState:0,
  10254. //internal state
  10255. state:0,
  10256. statusText:null,
  10257. status:0,
  10258. transport:null
  10259. });
  10260. }
  10261. S.augment(XhrObject, Event.Target, {
  10262. // Caches the header
  10263. setRequestHeader: function(name, value) {
  10264. this.requestHeaders[ name ] = value;
  10265. return this;
  10266. },
  10267. // Raw string
  10268. getAllResponseHeaders: function() {
  10269. return this.state === 2 ? this.responseHeadersString : null;
  10270. },
  10271. // Builds headers hashtable if needed
  10272. getResponseHeader: function(key) {
  10273. var match;
  10274. if (this.state === 2) {
  10275. if (!this.responseHeaders) {
  10276. this.responseHeaders = {};
  10277. while (( match = rheaders.exec(this.responseHeadersString) )) {
  10278. this.responseHeaders[ match[1] ] = match[ 2 ];
  10279. }
  10280. }
  10281. match = this.responseHeaders[ key];
  10282. }
  10283. return match === undefined ? null : match;
  10284. },
  10285. // Overrides response content-type header
  10286. overrideMimeType: function(type) {
  10287. if (!this.state) {
  10288. this.mimeType = type;
  10289. }
  10290. return this;
  10291. },
  10292. // Cancel the request
  10293. abort: function(statusText) {
  10294. statusText = statusText || "abort";
  10295. if (this.transport) {
  10296. this.transport.abort(statusText);
  10297. }
  10298. this.callback(0, statusText);
  10299. return this;
  10300. },
  10301. callback:function(status, statusText) {
  10302. //debugger
  10303. var xhr = this;
  10304. // 只能执行一次,防止重复执行
  10305. // 例如完成后,调用 abort
  10306. // 到这要么成功,调用success
  10307. // 要么失败,调用 error
  10308. // 最终都会调用 complete
  10309. if (xhr.state == 2) {
  10310. return;
  10311. }
  10312. xhr.state = 2;
  10313. xhr.readyState = 4;
  10314. var isSuccess;
  10315. if (status >= OK_CODE && status < MULTIPLE_CHOICES || status == NOT_MODIFIED) {
  10316. if (status == NOT_MODIFIED) {
  10317. statusText = "notmodified";
  10318. isSuccess = true;
  10319. } else {
  10320. try {
  10321. handleResponseData(xhr);
  10322. statusText = "success";
  10323. isSuccess = true;
  10324. } catch(e) {
  10325. statusText = "parsererror : " + e;
  10326. }
  10327. }
  10328. } else {
  10329. if (status < 0) {
  10330. status = 0;
  10331. }
  10332. }
  10333. xhr.status = status;
  10334. xhr.statusText = statusText;
  10335. if (isSuccess) {
  10336. xhr.fire("success");
  10337. } else {
  10338. xhr.fire("error");
  10339. }
  10340. xhr.fire("complete");
  10341. xhr.transport = undefined;
  10342. }
  10343. }
  10344. );
  10345. return XhrObject;
  10346. }, {
  10347. requires:["event"]
  10348. });
  10349. /*
  10350. Copyright 2011, KISSY UI Library v1.30dev
  10351. MIT Licensed
  10352. build time: Dec 31 15:26
  10353. */
  10354. /**
  10355. * @fileOverview cookie
  10356. * @author lifesinger@gmail.com
  10357. */
  10358. KISSY.add('cookie', function (S) {
  10359. var doc = document,
  10360. MILLISECONDS_OF_DAY = 24 * 60 * 60 * 1000,
  10361. encode = encodeURIComponent,
  10362. decode = decodeURIComponent;
  10363. function isNotEmptyString(val) {
  10364. return S.isString(val) && val !== '';
  10365. }
  10366. return {
  10367. /**
  10368. * 获取 cookie 值
  10369. * @return {string} 如果 name 不存在,返回 undefined
  10370. */
  10371. get:function (name) {
  10372. var ret, m;
  10373. if (isNotEmptyString(name)) {
  10374. if ((m = String(doc.cookie).match(
  10375. new RegExp('(?:^| )' + name + '(?:(?:=([^;]*))|;|$)')))) {
  10376. ret = m[1] ? decode(m[1]) : '';
  10377. }
  10378. }
  10379. return ret;
  10380. },
  10381. set:function (name, val, expires, domain, path, secure) {
  10382. var text = String(encode(val)), date = expires;
  10383. // 从当前时间开始,多少天后过期
  10384. if (typeof date === 'number') {
  10385. date = new Date();
  10386. date.setTime(date.getTime() + expires * MILLISECONDS_OF_DAY);
  10387. }
  10388. // expiration date
  10389. if (date instanceof Date) {
  10390. text += '; expires=' + date.toUTCString();
  10391. }
  10392. // domain
  10393. if (isNotEmptyString(domain)) {
  10394. text += '; domain=' + domain;
  10395. }
  10396. // path
  10397. if (isNotEmptyString(path)) {
  10398. text += '; path=' + path;
  10399. }
  10400. // secure
  10401. if (secure) {
  10402. text += '; secure';
  10403. }
  10404. //S.log(text);
  10405. doc.cookie = name + '=' + text;
  10406. },
  10407. remove:function (name, domain, path, secure) {
  10408. // 置空,并立刻过期
  10409. this.set(name, '', -1, domain, path, secure);
  10410. }
  10411. };
  10412. });
  10413. /**
  10414. * NOTES:
  10415. *
  10416. * 2010.04
  10417. * - get 方法要考虑 ie 下,
  10418. * 值为空的 cookie 为 'test3; test3=3; test3tt=2; test1=t1test3; test3', 没有等于号。
  10419. * 除了正则获取,还可以 split 字符串的方式来获取。
  10420. * - api 设计上,原本想借鉴 jQuery 的简明风格:S.cookie(name, ...), 但考虑到可扩展性,目前
  10421. * 独立成静态工具类的方式更优。
  10422. */
  10423. /*
  10424. Copyright 2012, KISSY UI Library v1.30dev
  10425. MIT Licensed
  10426. build time: Jan 4 20:38
  10427. */
  10428. /**
  10429. * @fileOverview attribute management
  10430. * @author yiminghe@gmail.com, lifesinger@gmail.com
  10431. */
  10432. KISSY.add('base/attribute', function (S, undef) {
  10433. // atomic flag
  10434. Attribute.INVALID = {};
  10435. var INVALID = Attribute.INVALID;
  10436. /**
  10437. *
  10438. * @param host
  10439. * @param method
  10440. * @return method if fn or host[method]
  10441. */
  10442. function normalFn(host, method) {
  10443. if (S.isString(method)) {
  10444. return host[method];
  10445. }
  10446. return method;
  10447. }
  10448. /**
  10449. * fire attribute value change
  10450. */
  10451. function __fireAttrChange(self, when, name, prevVal, newVal, subAttrName, attrName) {
  10452. attrName = attrName || name;
  10453. return self.fire(when + capitalFirst(name) + 'Change', {
  10454. attrName:attrName,
  10455. subAttrName:subAttrName,
  10456. prevVal:prevVal,
  10457. newVal:newVal
  10458. });
  10459. }
  10460. /**
  10461. *
  10462. * @param obj
  10463. * @param name
  10464. * @param [create]
  10465. * @return non-empty property value of obj
  10466. */
  10467. function ensureNonEmpty(obj, name, create) {
  10468. var ret = obj[name] || {};
  10469. if (create) {
  10470. obj[name] = ret;
  10471. }
  10472. return ret;
  10473. }
  10474. /**
  10475. *
  10476. * @param self
  10477. * @return non-empty attr config holder
  10478. */
  10479. function getAttrs(self) {
  10480. /**
  10481. * attribute meta information
  10482. {
  10483. attrName: {
  10484. getter: function,
  10485. setter: function,
  10486. // 注意:只能是普通对象以及系统内置类型,而不能是 new Xx(),否则用 valueFn 替代
  10487. value: v, // default value
  10488. valueFn: function
  10489. }
  10490. }
  10491. */
  10492. return ensureNonEmpty(self, "__attrs", true);
  10493. }
  10494. /**
  10495. *
  10496. * @param self
  10497. * @return non-empty attr value holder
  10498. */
  10499. function getAttrVals(self) {
  10500. /**
  10501. * attribute value
  10502. {
  10503. attrName: attrVal
  10504. }
  10505. */
  10506. return ensureNonEmpty(self, "__attrVals", true);
  10507. }
  10508. /**
  10509. * o, [x,y,z] => o[x][y][z]
  10510. * @param o
  10511. * @param path
  10512. */
  10513. function getValueByPath(o, path) {
  10514. for (var i = 0, len = path.length;
  10515. o != undef && i < len;
  10516. i++) {
  10517. o = o[path[i]];
  10518. }
  10519. return o;
  10520. }
  10521. /**
  10522. * o, [x,y,z], val => o[x][y][z]=val
  10523. * @param o
  10524. * @param path
  10525. * @param val
  10526. */
  10527. function setValueByPath(o, path, val) {
  10528. var rlen = path.length - 1,
  10529. s = o;
  10530. if (rlen >= 0) {
  10531. for (var i = 0; i < rlen; i++) {
  10532. o = o[path[i]];
  10533. }
  10534. if (o != undef) {
  10535. o[path[i]] = val;
  10536. } else {
  10537. s = undef;
  10538. }
  10539. }
  10540. return s;
  10541. }
  10542. function setInternal(self, name, value, opts, attrs) {
  10543. var ret;
  10544. opts = opts || {};
  10545. var dot = ".",
  10546. path,
  10547. subVal,
  10548. prevVal,
  10549. fullName = name;
  10550. if (name.indexOf(dot) !== -1) {
  10551. path = name.split(dot);
  10552. name = path.shift();
  10553. }
  10554. prevVal = self.get(name);
  10555. if (path) {
  10556. subVal = getValueByPath(prevVal, path);
  10557. }
  10558. // if no change, just return
  10559. if (!path && prevVal === value) {
  10560. return undefined;
  10561. } else if (path && subVal === value) {
  10562. return undefined;
  10563. }
  10564. if (path) {
  10565. var tmp = S.clone(prevVal);
  10566. setValueByPath(tmp, path, value);
  10567. value = tmp;
  10568. }
  10569. // check before event
  10570. if (!opts['silent']) {
  10571. if (false === __fireAttrChange(self, 'before', name, prevVal, value, fullName)) {
  10572. return false;
  10573. }
  10574. }
  10575. // set it
  10576. ret = self.__set(name, value);
  10577. if (ret === false) {
  10578. return ret;
  10579. }
  10580. // fire after event
  10581. if (!opts['silent']) {
  10582. value = getAttrVals(self)[name];
  10583. __fireAttrChange(self, 'after', name, prevVal, value, fullName);
  10584. if (!attrs) {
  10585. __fireAttrChange(self,
  10586. '', '*',
  10587. [prevVal], [value],
  10588. [fullName], [name]);
  10589. } else {
  10590. attrs.push({
  10591. prevVal:prevVal,
  10592. newVal:value,
  10593. attrName:name,
  10594. subAttrName:fullName
  10595. });
  10596. }
  10597. }
  10598. return self;
  10599. }
  10600. /**
  10601. * 提供属性管理机制
  10602. * @name Attribute
  10603. * @class
  10604. */
  10605. function Attribute() {
  10606. }
  10607. S.augment(Attribute,
  10608. /**
  10609. * @lends Attribute.prototype
  10610. */
  10611. {
  10612. /**
  10613. * @return un-cloned attr config collections
  10614. */
  10615. getAttrs:function () {
  10616. return getAttrs(this);
  10617. },
  10618. /**
  10619. * @return un-cloned attr value collections
  10620. */
  10621. getAttrVals:function () {
  10622. var self = this,
  10623. o = {},
  10624. a,
  10625. attrs = getAttrs(self);
  10626. for (a in attrs) {
  10627. o[a] = self.get(a);
  10628. }
  10629. return o;
  10630. },
  10631. /**
  10632. * Adds an attribute with the provided configuration to the host object.
  10633. * @param {String} name attrName
  10634. * @param {Object} attrConfig The config supports the following properties
  10635. * @param [attrConfig.value] simple object or system native object
  10636. * @param [attrConfig.valueFn] a function which can return current attribute's default value
  10637. * @param {Function(*)} [attrConfig.setter] call when set attribute's value
  10638. * pass current attribute's value as parameter
  10639. * if return value is not undefined,set returned value as real value
  10640. * @param {Function(*)} [attrConfig.getter] call when get attribute's value
  10641. * pass current attribute's value as parameter
  10642. * return getter's returned value to invoker
  10643. * @param {Function(*)} [attrConfig.validator] call before set attribute's value
  10644. * if return false,cancel this set action
  10645. * @param {boolean} [override] whether override existing attribute config ,default true
  10646. */
  10647. addAttr:function (name, attrConfig, override) {
  10648. var self = this,
  10649. attrs = getAttrs(self),
  10650. cfg = S.clone(attrConfig);
  10651. if (!attrs[name]) {
  10652. attrs[name] = cfg;
  10653. } else {
  10654. S.mix(attrs[name], cfg, override);
  10655. }
  10656. return self;
  10657. },
  10658. /**
  10659. * Configures a group of attributes, and sets initial values.
  10660. * @param {Object} attrConfigs An object with attribute name/configuration pairs.
  10661. * @param {Object} initialValues user defined initial values
  10662. */
  10663. addAttrs:function (attrConfigs, initialValues) {
  10664. var self = this;
  10665. S.each(attrConfigs, function (attrConfig, name) {
  10666. self.addAttr(name, attrConfig);
  10667. });
  10668. if (initialValues) {
  10669. self.set(initialValues);
  10670. }
  10671. return self;
  10672. },
  10673. /**
  10674. * Checks if the given attribute has been added to the host.
  10675. */
  10676. hasAttr:function (name) {
  10677. return name && getAttrs(this).hasOwnProperty(name);
  10678. },
  10679. /**
  10680. * Removes an attribute from the host object.
  10681. */
  10682. removeAttr:function (name) {
  10683. var self = this;
  10684. if (self.hasAttr(name)) {
  10685. delete getAttrs(self)[name];
  10686. delete getAttrVals(self)[name];
  10687. }
  10688. return self;
  10689. },
  10690. /**
  10691. * Sets the value of an attribute.
  10692. * @param {String|Object} name attribute's name or attribute name and value map
  10693. * @param [value] attribute's value
  10694. * @param {Object} [opts] some options
  10695. * @param {boolean} [opts.silent] whether fire change event
  10696. * @returns {boolean} whether pass validator
  10697. */
  10698. set:function (name, value, opts) {
  10699. var ret, self = this;
  10700. if (S.isPlainObject(name)) {
  10701. var all = Object(name);
  10702. opts = value;
  10703. var attrs = [];
  10704. for (name in all) {
  10705. ret = setInternal(self, name, all[name], opts, attrs);
  10706. if (ret === false) {
  10707. break;
  10708. }
  10709. }
  10710. var attrNames = [],
  10711. prevVals = [],
  10712. newVals = [],
  10713. subAttrNames = [];
  10714. S.each(attrs, function (attr) {
  10715. prevVals.push(attr.prevVal);
  10716. newVals.push(attr.newVal);
  10717. attrNames.push(attr.attrName);
  10718. subAttrNames.push(attr.subAttrName);
  10719. });
  10720. if (attrNames.length) {
  10721. __fireAttrChange(self,
  10722. '',
  10723. '*',
  10724. prevVals,
  10725. newVals,
  10726. subAttrNames,
  10727. attrNames);
  10728. }
  10729. return ret;
  10730. }
  10731. return setInternal(self, name, value, opts);
  10732. },
  10733. /**
  10734. * internal use, no event involved, just set.
  10735. * @protected overriden by mvc/model
  10736. */
  10737. __set:function (name, value) {
  10738. var self = this,
  10739. setValue,
  10740. // if host does not have meta info corresponding to (name,value)
  10741. // then register on demand in order to collect all data meta info
  10742. // 一定要注册属性元数据,否则其他模块通过 _attrs 不能枚举到所有有效属性
  10743. // 因为属性在声明注册前可以直接设置值
  10744. attrConfig = ensureNonEmpty(getAttrs(self), name, true),
  10745. validator = attrConfig['validator'],
  10746. setter = attrConfig['setter'];
  10747. // validator check
  10748. if (validator && (validator = normalFn(self, validator))) {
  10749. if (validator.call(self, value, name) === false) {
  10750. return false;
  10751. }
  10752. }
  10753. // if setter has effect
  10754. if (setter && (setter = normalFn(self, setter))) {
  10755. setValue = setter.call(self, value, name);
  10756. }
  10757. if (setValue === INVALID) {
  10758. return false;
  10759. }
  10760. if (setValue !== undef) {
  10761. value = setValue;
  10762. }
  10763. // finally set
  10764. getAttrVals(self)[name] = value;
  10765. },
  10766. /**
  10767. * Gets the current value of the attribute.
  10768. * @param {String} name attribute's name
  10769. */
  10770. get:function (name) {
  10771. var self = this,
  10772. dot = ".",
  10773. path,
  10774. attrVals = getAttrVals(self),
  10775. attrConfig,
  10776. getter, ret;
  10777. if (name.indexOf(dot) !== -1) {
  10778. path = name.split(dot);
  10779. name = path.shift();
  10780. }
  10781. attrConfig = ensureNonEmpty(getAttrs(self), name);
  10782. getter = attrConfig['getter'];
  10783. // get user-set value or default value
  10784. //user-set value takes privilege
  10785. ret = name in attrVals ?
  10786. attrVals[name] :
  10787. self.__getDefAttrVal(name);
  10788. // invoke getter for this attribute
  10789. if (getter && (getter = normalFn(self, getter))) {
  10790. ret = getter.call(self, ret, name);
  10791. }
  10792. if (path) {
  10793. ret = getValueByPath(ret, path);
  10794. }
  10795. return ret;
  10796. },
  10797. /**
  10798. * get default attribute value from valueFn/value
  10799. * @private
  10800. * @param name
  10801. */
  10802. __getDefAttrVal:function (name) {
  10803. var self = this,
  10804. attrs = getAttrs(self),
  10805. attrConfig = ensureNonEmpty(attrs, name),
  10806. valFn = attrConfig.valueFn,
  10807. val;
  10808. if (valFn && (valFn = normalFn(self, valFn))) {
  10809. val = valFn.call(self);
  10810. if (val !== undef) {
  10811. attrConfig.value = val;
  10812. }
  10813. delete attrConfig.valueFn;
  10814. attrs[name] = attrConfig;
  10815. }
  10816. return attrConfig.value;
  10817. },
  10818. /**
  10819. * Resets the value of an attribute.just reset what addAttr set (not what invoker set when call new Xx(cfg))
  10820. * @param {String} name name of attribute
  10821. * @param {Object} [opts] some options
  10822. * @param {boolean} [opts.silent] whether fire change event
  10823. */
  10824. reset:function (name, opts) {
  10825. var self = this;
  10826. if (S.isString(name)) {
  10827. if (self.hasAttr(name)) {
  10828. // if attribute does not have default value, then set to undefined.
  10829. return self.set(name, self.__getDefAttrVal(name), opts);
  10830. }
  10831. else {
  10832. return self;
  10833. }
  10834. }
  10835. opts = name;
  10836. var attrs = getAttrs(self),
  10837. values = {};
  10838. // reset all
  10839. for (name in attrs) {
  10840. values[name] = self.__getDefAttrVal(name);
  10841. }
  10842. self.set(values, opts);
  10843. return self;
  10844. }
  10845. });
  10846. function capitalFirst(s) {
  10847. return s.charAt(0).toUpperCase() + s.substring(1);
  10848. }
  10849. if (undef) {
  10850. Attribute.prototype.addAttrs = undef;
  10851. }
  10852. return Attribute;
  10853. });
  10854. /**
  10855. * 2011-10-18
  10856. * get/set sub attribute value ,set("x.y",val) x 最好为 {} ,不要是 new Clz() 出来的
  10857. * add validator
  10858. */
  10859. /**
  10860. * @fileOverview attribute management and event in one
  10861. * @author yiminghe@gmail.com,lifesinger@gmail.com
  10862. */
  10863. KISSY.add('base', function (S, Attribute, Event) {
  10864. /**
  10865. * @name Base
  10866. * @extends Event.Target
  10867. * @extends Attribute
  10868. * @class Base for class-based component
  10869. */
  10870. function Base(config) {
  10871. var c = this.constructor;
  10872. // define
  10873. while (c) {
  10874. addAttrs(this, c['ATTRS']);
  10875. c = c.superclass ? c.superclass.constructor : null;
  10876. }
  10877. // initial
  10878. initAttrs(this, config);
  10879. }
  10880. function addAttrs(host, attrs) {
  10881. if (attrs) {
  10882. for (var attr in attrs) {
  10883. // 子类上的 ATTRS 配置优先
  10884. if (attrs.hasOwnProperty(attr)) {
  10885. // 父类后加,父类不覆盖子类的相同设置
  10886. // 属性对象会 merge a: {y:{getter:fn}}, b:{y:{value:3}}, b extends a => b {y:{value:3}}
  10887. host.addAttr(attr, attrs[attr], false);
  10888. }
  10889. }
  10890. }
  10891. }
  10892. function initAttrs(host, config) {
  10893. if (config) {
  10894. for (var attr in config) {
  10895. if (config.hasOwnProperty(attr)) {
  10896. //用户设置会调用 setter/validator 的,但不会触发属性变化事件
  10897. host.__set(attr, config[attr]);
  10898. }
  10899. }
  10900. }
  10901. }
  10902. S.augment(Base, Event.Target, Attribute);
  10903. Base.Attribute = Attribute;
  10904. return Base;
  10905. }, {
  10906. requires:["base/attribute", "event"]
  10907. });
  10908. /*
  10909. Copyright 2011, KISSY UI Library v1.30dev
  10910. MIT Licensed
  10911. build time: Dec 31 15:25
  10912. */
  10913. /**
  10914. * @fileOverview anim
  10915. */
  10916. KISSY.add("anim", function(S, Anim,Easing) {
  10917. Anim.Easing=Easing;
  10918. return Anim;
  10919. }, {
  10920. requires:["anim/base","anim/easing","anim/color","anim/backgroundPosition"]
  10921. });/**
  10922. * @fileOverview special patch for anim backgroundPosition
  10923. * @author yiminghe@gmail.com
  10924. */
  10925. KISSY.add("anim/backgroundPosition", function (S, DOM, Anim, Fx) {
  10926. function numeric(bp) {
  10927. bp = bp.replace(/left|top/g, '0px')
  10928. .replace(/right|bottom/g, '100%')
  10929. .replace(/([0-9\.]+)(\s|\)|$)/g, "$1px$2");
  10930. var res = bp.match(/(-?[0-9\.]+)(px|%|em|pt)\s(-?[0-9\.]+)(px|%|em|pt)/);
  10931. return [parseFloat(res[1]), res[2], parseFloat(res[3]), res[4]];
  10932. }
  10933. function BackgroundPositionFx() {
  10934. BackgroundPositionFx.superclass.constructor.apply(this, arguments);
  10935. }
  10936. S.extend(BackgroundPositionFx, Fx, {
  10937. load:function () {
  10938. var self = this, fromUnit;
  10939. BackgroundPositionFx.superclass.load.apply(self, arguments);
  10940. fromUnit = self.unit = ["px", "px"];
  10941. if (self.from) {
  10942. var from = numeric(self.from);
  10943. self.from = [from[0], from[2]];
  10944. fromUnit = [from[1], from[3]];
  10945. } else {
  10946. self.from = [0, 0];
  10947. }
  10948. if (self.to) {
  10949. var to = numeric(self.to);
  10950. self.to = [to[0], to[2]];
  10951. self.unit = [to[1], to[3]];
  10952. } else {
  10953. self.to = [0, 0];
  10954. }
  10955. if (fromUnit) {
  10956. if (fromUnit[0] !== self.unit[0] || fromUnit[1] !== self.unit[1]) {
  10957. S.log("BackgroundPosition x y unit is not same :", "warn");
  10958. S.log(fromUnit, "warn");
  10959. S.log(self.unit, "warn");
  10960. }
  10961. }
  10962. },
  10963. interpolate:function (from, to, pos) {
  10964. var unit = this.unit, interpolate = BackgroundPositionFx.superclass.interpolate;
  10965. return interpolate(from[0], to[0], pos) + unit[0] + " " +
  10966. interpolate(from[1], to[1], pos) + unit[1];
  10967. },
  10968. cur:function () {
  10969. return DOM.css(this.elem, "backgroundPosition");
  10970. },
  10971. update:function () {
  10972. var self = this,
  10973. prop = self.prop,
  10974. elem = self.elem,
  10975. from = self.from,
  10976. to = self.to,
  10977. val = self.interpolate(from, to, self.pos);
  10978. DOM.css(elem, prop, val);
  10979. }
  10980. });
  10981. Fx.Factories["backgroundPosition"] = BackgroundPositionFx;
  10982. return BackgroundPositionFx;
  10983. }, {
  10984. requires:["dom", "./base", "./fx"]
  10985. });/**
  10986. * @fileOverview animation framework for KISSY
  10987. * @author yiminghe@gmail.com,lifesinger@gmail.com
  10988. */
  10989. KISSY.add('anim/base', function (S, DOM, Event, Easing, UA, AM, Fx, Q) {
  10990. var camelCase = DOM._camelCase,
  10991. _isElementNode = DOM._isElementNode,
  10992. specialVals = ["hide", "show", "toggle"],
  10993. // shorthand css properties
  10994. SHORT_HANDS = {
  10995. // http://www.w3.org/Style/CSS/Tracker/issues/9
  10996. // http://snook.ca/archives/html_and_css/background-position-x-y
  10997. // backgroundPositionX backgroundPositionY does not support
  10998. background:[
  10999. "backgroundPosition"
  11000. ],
  11001. border:[
  11002. "borderBottomWidth",
  11003. "borderLeftWidth",
  11004. 'borderRightWidth',
  11005. // 'borderSpacing', 组合属性?
  11006. 'borderTopWidth'
  11007. ],
  11008. "borderBottom":["borderBottomWidth"],
  11009. "borderLeft":["borderLeftWidth"],
  11010. borderTop:["borderTopWidth"],
  11011. borderRight:["borderRightWidth"],
  11012. font:[
  11013. 'fontSize',
  11014. 'fontWeight'
  11015. ],
  11016. margin:[
  11017. 'marginBottom',
  11018. 'marginLeft',
  11019. 'marginRight',
  11020. 'marginTop'
  11021. ],
  11022. padding:[
  11023. 'paddingBottom',
  11024. 'paddingLeft',
  11025. 'paddingRight',
  11026. 'paddingTop'
  11027. ]
  11028. },
  11029. defaultConfig = {
  11030. duration:1,
  11031. easing:'easeNone'
  11032. },
  11033. rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i;
  11034. Anim.SHORT_HANDS = SHORT_HANDS;
  11035. /**
  11036. * get a anim instance associate
  11037. * @param {HTMLElement|window} elem 元素或者 window ( window 时只能动画 scrollTop/scrollLeft )
  11038. * @param {Object} props style map
  11039. * @param {Number|Object} [duration] duration(s) or anim config
  11040. * @param {String|Function} [duration.easing] easing fn or string
  11041. * @param {Function} [duration.complete] callback function when this animation is complete
  11042. * @param {Number} [duration.duration] duration(s)
  11043. * @param {String|Boolean} [duration.queue] current animation's queue, if false then no queue
  11044. * @param {Function|String} [easing] easing fn or string
  11045. * @param {Function} [callback] callback function when this animation is complete
  11046. * @extends Event.Target
  11047. * @name Anim
  11048. * @class
  11049. */
  11050. function Anim(elem, props, duration, easing, callback) {
  11051. var self = this, config;
  11052. // ignore non-exist element
  11053. if (!(elem = DOM.get(elem))) {
  11054. return;
  11055. }
  11056. // factory or constructor
  11057. if (!(self instanceof Anim)) {
  11058. return new Anim(elem, props, duration, easing, callback);
  11059. }
  11060. /**
  11061. * the transition properties
  11062. */
  11063. if (S.isString(props)) {
  11064. props = S.unparam(String(props), ";", ":");
  11065. } else {
  11066. // clone to prevent collision within multiple instance
  11067. props = S.clone(props);
  11068. }
  11069. /**
  11070. * 驼峰属性名
  11071. */
  11072. for (var prop in props) {
  11073. var camelProp = camelCase(S.trim(prop));
  11074. if (prop != camelProp) {
  11075. props[camelProp] = props[prop];
  11076. delete props[prop];
  11077. }
  11078. }
  11079. /**
  11080. * animation config
  11081. */
  11082. if (S.isPlainObject(duration)) {
  11083. config = S.clone(duration);
  11084. } else {
  11085. config = {
  11086. duration:parseFloat(duration) || undefined,
  11087. easing:easing,
  11088. complete:callback
  11089. };
  11090. }
  11091. config = S.merge(defaultConfig, config);
  11092. self.config = config;
  11093. config.duration *= 1000;
  11094. // domEl deprecated!
  11095. self.elem = self['domEl'] = elem;
  11096. self.props = props;
  11097. // 实例属性
  11098. self._backupProps = {};
  11099. self._fxs = {};
  11100. // register callback
  11101. self.on("complete", onComplete);
  11102. }
  11103. function onComplete(e) {
  11104. var self = this,
  11105. _backupProps,
  11106. config = self.config;
  11107. // only recover after complete anim
  11108. if (!S.isEmptyObject(_backupProps = self._backupProps)) {
  11109. DOM.css(self.elem, _backupProps);
  11110. }
  11111. if (config.complete) {
  11112. config.complete.call(self, e);
  11113. }
  11114. }
  11115. function runInternal() {
  11116. var self = this,
  11117. config = self.config,
  11118. _backupProps = self._backupProps,
  11119. elem = self.elem,
  11120. hidden,
  11121. val,
  11122. prop,
  11123. specialEasing = (config['specialEasing'] || {}),
  11124. fxs = self._fxs,
  11125. props = self.props;
  11126. // 进入该函数即代表执行(q[0] 已经是 ...)
  11127. saveRunning(self);
  11128. if (self.fire("start") === false) {
  11129. // no need to invoke complete
  11130. self.stop(0);
  11131. return;
  11132. }
  11133. if (_isElementNode(elem)) {
  11134. hidden = DOM.css(elem, "display") == "none";
  11135. for (prop in props) {
  11136. val = props[prop];
  11137. // 直接结束
  11138. if (val == "hide" && hidden || val == 'show' && !hidden) {
  11139. // need to invoke complete
  11140. self.stop(1);
  11141. return;
  11142. }
  11143. }
  11144. }
  11145. // 分离 easing
  11146. S.each(props, function (val, prop) {
  11147. if (!props.hasOwnProperty(prop)) {
  11148. return;
  11149. }
  11150. var easing;
  11151. if (S.isArray(val)) {
  11152. easing = specialEasing[prop] = val[1];
  11153. props[prop] = val[0];
  11154. } else {
  11155. easing = specialEasing[prop] = (specialEasing[prop] || config.easing);
  11156. }
  11157. if (S.isString(easing)) {
  11158. easing = specialEasing[prop] = Easing[easing];
  11159. }
  11160. specialEasing[prop] = easing || Easing.easeNone;
  11161. });
  11162. // 扩展分属性
  11163. S.each(SHORT_HANDS, function (shortHands, p) {
  11164. var sh,
  11165. origin,
  11166. val;
  11167. if (val = props[p]) {
  11168. origin = {};
  11169. S.each(shortHands, function (sh) {
  11170. // 得到原始分属性之前值
  11171. origin[sh] = DOM.css(elem, sh);
  11172. specialEasing[sh] = specialEasing[p];
  11173. });
  11174. DOM.css(elem, p, val);
  11175. for (sh in origin) {
  11176. // 得到期待的分属性最后值
  11177. props[sh] = DOM.css(elem, sh);
  11178. // 还原
  11179. DOM.css(elem, sh, origin[sh]);
  11180. }
  11181. // 删除复合属性
  11182. delete props[p];
  11183. }
  11184. });
  11185. // 取得单位,并对单个属性构建 Fx 对象
  11186. for (prop in props) {
  11187. if (!props.hasOwnProperty(prop)) {
  11188. continue;
  11189. }
  11190. val = S.trim(props[prop]);
  11191. var to,
  11192. from,
  11193. propCfg = {
  11194. elem:elem,
  11195. prop:prop,
  11196. duration:config.duration,
  11197. easing:specialEasing[prop]
  11198. },
  11199. fx = Fx.getFx(propCfg);
  11200. // hide/show/toggle : special treat!
  11201. if (S.inArray(val, specialVals)) {
  11202. // backup original value
  11203. _backupProps[prop] = DOM.style(elem, prop);
  11204. if (val == "toggle") {
  11205. val = hidden ? "show" : "hide";
  11206. }
  11207. if (val == "hide") {
  11208. to = 0;
  11209. from = fx.cur();
  11210. // 执行完后隐藏
  11211. _backupProps.display = 'none';
  11212. } else {
  11213. from = 0;
  11214. to = fx.cur();
  11215. // prevent flash of content
  11216. DOM.css(elem, prop, from);
  11217. DOM.show(elem);
  11218. }
  11219. val = to;
  11220. } else {
  11221. to = val;
  11222. from = fx.cur();
  11223. }
  11224. val += "";
  11225. var unit = "",
  11226. parts = val.match(rfxnum);
  11227. if (parts) {
  11228. to = parseFloat(parts[2]);
  11229. unit = parts[3];
  11230. // 有单位但单位不是 px
  11231. if (unit && unit !== "px") {
  11232. DOM.css(elem, prop, val);
  11233. from = (to / fx.cur()) * from;
  11234. DOM.css(elem, prop, from + unit);
  11235. }
  11236. // 相对
  11237. if (parts[1]) {
  11238. to = ( (parts[ 1 ] === "-=" ? -1 : 1) * to ) + from;
  11239. }
  11240. }
  11241. propCfg.from = from;
  11242. propCfg.to = to;
  11243. propCfg.unit = unit;
  11244. fx.load(propCfg);
  11245. fxs[prop] = fx;
  11246. }
  11247. if (_isElementNode(elem) &&
  11248. (props.width || props.height)) {
  11249. // Make sure that nothing sneaks out
  11250. // Record all 3 overflow attributes because IE does not
  11251. // change the overflow attribute when overflowX and
  11252. // overflowY are set to the same value
  11253. S.mix(_backupProps, {
  11254. overflow:DOM.style(elem, "overflow"),
  11255. "overflow-x":DOM.style(elem, "overflowX"),
  11256. "overflow-y":DOM.style(elem, "overflowY")
  11257. });
  11258. DOM.css(elem, "overflow", "hidden");
  11259. // inline element should has layout/inline-block
  11260. if (DOM.css(elem, "display") === "inline" &&
  11261. DOM.css(elem, "float") === "none") {
  11262. if (UA['ie']) {
  11263. DOM.css(elem, "zoom", 1);
  11264. } else {
  11265. DOM.css(elem, "display", "inline-block");
  11266. }
  11267. }
  11268. }
  11269. AM.start(self);
  11270. }
  11271. S.augment(Anim, Event.Target,
  11272. /**
  11273. * @lends Anim.prototype
  11274. */
  11275. {
  11276. /**
  11277. * @return {boolean} 是否在运行
  11278. */
  11279. isRunning:function () {
  11280. return isRunning(this);
  11281. },
  11282. _runInternal:runInternal,
  11283. /**
  11284. * 开始动画
  11285. */
  11286. run:function () {
  11287. var self = this,
  11288. queueName = self.config.queue;
  11289. if (queueName === false) {
  11290. runInternal.call(self);
  11291. } else {
  11292. // 当前动画对象加入队列
  11293. Q.queue(self);
  11294. }
  11295. return self;
  11296. },
  11297. _frame:function () {
  11298. var self = this,
  11299. prop,
  11300. config = self.config,
  11301. end = 1,
  11302. c,
  11303. fx,
  11304. fxs = self._fxs;
  11305. for (prop in fxs) {
  11306. if (fxs.hasOwnProperty(prop) &&
  11307. // 当前属性没有结束
  11308. !((fx = fxs[prop]).finished)) {
  11309. // 非短路
  11310. if (config.frame) {
  11311. c = config.frame(fx);
  11312. }
  11313. // 结束
  11314. if (c == 1 ||
  11315. // 不执行自带
  11316. c == 0) {
  11317. fx.finished = c;
  11318. end &= c;
  11319. }
  11320. else {
  11321. end &= fx.frame();
  11322. }
  11323. }
  11324. }
  11325. if ((self.fire("step") === false) ||
  11326. end) {
  11327. // complete 事件只在动画到达最后一帧时才触发
  11328. self.stop(end);
  11329. }
  11330. },
  11331. /**
  11332. * 结束动画
  11333. * @param {boolean} finish whether jump to the last position of this animation
  11334. */
  11335. stop:function (finish) {
  11336. var self = this,
  11337. config = self.config,
  11338. queueName = config.queue,
  11339. prop,
  11340. fxs = self._fxs;
  11341. // already stopped
  11342. if (!self.isRunning()) {
  11343. // 从自己的队列中移除
  11344. if (queueName !== false) {
  11345. Q.remove(self);
  11346. }
  11347. return;
  11348. }
  11349. if (finish) {
  11350. for (prop in fxs) {
  11351. if (fxs.hasOwnProperty(prop)) {
  11352. fxs[prop].frame(1);
  11353. }
  11354. }
  11355. self.fire("complete");
  11356. }
  11357. AM.stop(self);
  11358. removeRunning(self);
  11359. if (queueName !== false) {
  11360. // notify next anim to run in the same queue
  11361. Q.dequeue(self);
  11362. }
  11363. return self;
  11364. }
  11365. });
  11366. var runningKey = S.guid("ks-anim-unqueued-" + S.now() + "-");
  11367. function saveRunning(anim) {
  11368. var elem = anim.elem,
  11369. allRunning = DOM.data(elem, runningKey);
  11370. if (!allRunning) {
  11371. DOM.data(elem, runningKey, allRunning = {});
  11372. }
  11373. allRunning[S.stamp(anim)] = anim;
  11374. }
  11375. function removeRunning(anim) {
  11376. var elem = anim.elem,
  11377. allRunning = DOM.data(elem, runningKey);
  11378. if (allRunning) {
  11379. delete allRunning[S.stamp(anim)];
  11380. if (S.isEmptyObject(allRunning)) {
  11381. DOM.removeData(elem, runningKey);
  11382. }
  11383. }
  11384. }
  11385. function isRunning(anim) {
  11386. var elem = anim.elem,
  11387. allRunning = DOM.data(elem, runningKey);
  11388. if (allRunning) {
  11389. return !!allRunning[S.stamp(anim)];
  11390. }
  11391. return 0;
  11392. }
  11393. /**
  11394. * stop all the anims currently running
  11395. * @param {HTMLElement} elem element which anim belongs to
  11396. * @param {boolean} end whether jump to last position
  11397. * @param {boolean} clearQueue whether clean current queue
  11398. * @param {String|Boolean} queueName current queue's name to be cleared
  11399. * @private
  11400. */
  11401. Anim.stop = function (elem, end, clearQueue, queueName) {
  11402. if (
  11403. // default queue
  11404. queueName === null ||
  11405. // name of specified queue
  11406. S.isString(queueName) ||
  11407. // anims not belong to any queue
  11408. queueName === false
  11409. ) {
  11410. return stopQueue.apply(undefined, arguments);
  11411. }
  11412. // first stop first anim in queues
  11413. if (clearQueue) {
  11414. Q.removeQueues(elem);
  11415. }
  11416. var allRunning = DOM.data(elem, runningKey),
  11417. // can not stop in for/in , stop will modified allRunning too
  11418. anims = S.merge(allRunning);
  11419. for (var k in anims) {
  11420. anims[k].stop(end);
  11421. }
  11422. };
  11423. /**
  11424. *
  11425. * @param elem element which anim belongs to
  11426. * @param queueName queue'name if set to false only remove
  11427. * @param end
  11428. * @param clearQueue
  11429. * @private
  11430. */
  11431. function stopQueue(elem, end, clearQueue, queueName) {
  11432. if (clearQueue && queueName !== false) {
  11433. Q.removeQueue(elem, queueName);
  11434. }
  11435. var allRunning = DOM.data(elem, runningKey),
  11436. anims = S.merge(allRunning);
  11437. for (var k in anims) {
  11438. var anim = anims[k];
  11439. if (anim.config.queue == queueName) {
  11440. anim.stop(end);
  11441. }
  11442. }
  11443. }
  11444. /**
  11445. * whether elem is running anim
  11446. * @param {HTMLElement} elem
  11447. * @private
  11448. */
  11449. Anim.isRunning = function (elem) {
  11450. var allRunning = DOM.data(elem, runningKey);
  11451. return allRunning && !S.isEmptyObject(allRunning);
  11452. };
  11453. Anim.Q = Q;
  11454. if (SHORT_HANDS) {
  11455. }
  11456. return Anim;
  11457. }, {
  11458. requires:["dom", "event", "./easing", "ua", "./manager", "./fx", "./queue"]
  11459. });
  11460. /**
  11461. * 2011-11
  11462. * - 重构,抛弃 emile,优化性能,只对需要的属性进行动画
  11463. * - 添加 stop/stopQueue/isRunning,支持队列管理
  11464. *
  11465. * 2011-04
  11466. * - 借鉴 yui3 ,中央定时器,否则 ie6 内存泄露?
  11467. * - 支持配置 scrollTop/scrollLeft
  11468. *
  11469. *
  11470. * TODO:
  11471. * - 效率需要提升,当使用 nativeSupport 时仍做了过多动作
  11472. * - opera nativeSupport 存在 bug ,浏览器自身 bug ?
  11473. * - 实现 jQuery Effects 的 queue / specialEasing / += / 等特性
  11474. *
  11475. * NOTES:
  11476. * - 与 emile 相比,增加了 borderStyle, 使得 border: 5px solid #ccc 能从无到有,正确显示
  11477. * - api 借鉴了 YUI, jQuery 以及 http://www.w3.org/TR/css3-transitions/
  11478. * - 代码实现了借鉴了 Emile.js: http://github.com/madrobby/emile *
  11479. */
  11480. /**
  11481. * @fileOverview special patch for making color gradual change
  11482. * @author yiminghe@gmail.com
  11483. */
  11484. KISSY.add("anim/color", function (S, DOM, Anim, Fx) {
  11485. var HEX_BASE = 16,
  11486. floor = Math.floor,
  11487. KEYWORDS = {
  11488. "black":[0, 0, 0],
  11489. "silver":[192, 192, 192],
  11490. "gray":[128, 128, 128],
  11491. "white":[255, 255, 255],
  11492. "maroon":[128, 0, 0],
  11493. "red":[255, 0, 0],
  11494. "purple":[128, 0, 128],
  11495. "fuchsia":[255, 0, 255],
  11496. "green":[0, 128, 0],
  11497. "lime":[0, 255, 0],
  11498. "olive":[128, 128, 0],
  11499. "yellow":[255, 255, 0],
  11500. "navy":[0, 0, 128],
  11501. "blue":[0, 0, 255],
  11502. "teal":[0, 128, 128],
  11503. "aqua":[0, 255, 255]
  11504. },
  11505. re_RGB = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
  11506. re_RGBA = /^rgba\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+),\s*([0-9]+)\)$/i,
  11507. re_hex = /^#?([0-9A-F]{1,2})([0-9A-F]{1,2})([0-9A-F]{1,2})$/i,
  11508. SHORT_HANDS = Anim.SHORT_HANDS,
  11509. COLORS = [
  11510. 'backgroundColor' ,
  11511. 'borderBottomColor' ,
  11512. 'borderLeftColor' ,
  11513. 'borderRightColor' ,
  11514. 'borderTopColor' ,
  11515. 'color' ,
  11516. 'outlineColor'
  11517. ];
  11518. SHORT_HANDS['background'] = SHORT_HANDS['background'] || [];
  11519. SHORT_HANDS['background'].push('backgroundColor');
  11520. SHORT_HANDS['borderColor'] = [
  11521. 'borderBottomColor',
  11522. 'borderLeftColor',
  11523. 'borderRightColor',
  11524. 'borderTopColor'
  11525. ];
  11526. SHORT_HANDS['border'].push(
  11527. 'borderBottomColor',
  11528. 'borderLeftColor',
  11529. 'borderRightColor',
  11530. 'borderTopColor'
  11531. );
  11532. SHORT_HANDS['borderBottom'].push(
  11533. 'borderBottomColor'
  11534. );
  11535. SHORT_HANDS['borderLeft'].push(
  11536. 'borderLeftColor'
  11537. );
  11538. SHORT_HANDS['borderRight'].push(
  11539. 'borderRightColor'
  11540. );
  11541. SHORT_HANDS['borderTop'].push(
  11542. 'borderTopColor'
  11543. );
  11544. //得到颜色的数值表示,红绿蓝数字数组
  11545. function numericColor(val) {
  11546. val = (val + "");
  11547. var match;
  11548. if (match = val.match(re_RGB)) {
  11549. return [
  11550. parseInt(match[1]),
  11551. parseInt(match[2]),
  11552. parseInt(match[3])
  11553. ];
  11554. }
  11555. else if (match = val.match(re_RGBA)) {
  11556. return [
  11557. parseInt(match[1]),
  11558. parseInt(match[2]),
  11559. parseInt(match[3]),
  11560. parseInt(match[4])
  11561. ];
  11562. }
  11563. else if (match = val.match(re_hex)) {
  11564. for (var i = 1; i < match.length; i++) {
  11565. if (match[i].length < 2) {
  11566. match[i] += match[i];
  11567. }
  11568. }
  11569. return [
  11570. parseInt(match[1], HEX_BASE),
  11571. parseInt(match[2], HEX_BASE),
  11572. parseInt(match[3], HEX_BASE)
  11573. ];
  11574. }
  11575. if (KEYWORDS[val = val.toLowerCase()]) {
  11576. return KEYWORDS[val];
  11577. }
  11578. //transparent 或者 颜色字符串返回
  11579. S.log("only allow rgb or hex color string : " + val, "warn");
  11580. return [255, 255, 255];
  11581. }
  11582. function ColorFx() {
  11583. ColorFx.superclass.constructor.apply(this, arguments);
  11584. }
  11585. S.extend(ColorFx, Fx, {
  11586. load:function () {
  11587. var self = this;
  11588. ColorFx.superclass.load.apply(self, arguments);
  11589. if (self.from) {
  11590. self.from = numericColor(self.from);
  11591. }
  11592. if (self.to) {
  11593. self.to = numericColor(self.to);
  11594. }
  11595. },
  11596. interpolate:function (from, to, pos) {
  11597. var interpolate = ColorFx.superclass.interpolate;
  11598. if (from.length == 3 && to.length == 3) {
  11599. return 'rgb(' + [
  11600. floor(interpolate(from[0], to[0], pos)),
  11601. floor(interpolate(from[1], to[1], pos)),
  11602. floor(interpolate(from[2], to[2], pos))
  11603. ].join(', ') + ')';
  11604. } else if (from.length == 4 || to.length == 4) {
  11605. return 'rgba(' + [
  11606. floor(interpolate(from[0], to[0], pos)),
  11607. floor(interpolate(from[1], to[1], pos)),
  11608. floor(interpolate(from[2], to[2], pos)),
  11609. // 透明度默认 1
  11610. floor(interpolate(from[3] || 1, to[3] || 1, pos))
  11611. ].join(', ') + ')';
  11612. } else {
  11613. S.log("anim/color unknown value : " + from);
  11614. }
  11615. }
  11616. });
  11617. S.each(COLORS, function (color) {
  11618. Fx.Factories[color] = ColorFx;
  11619. });
  11620. return ColorFx;
  11621. }, {
  11622. requires:["dom", "./base", "./fx"]
  11623. });
  11624. /**
  11625. * TODO
  11626. * 支持 hsla
  11627. * - https://github.com/jquery/jquery-color/blob/master/jquery.color.js
  11628. **//**
  11629. * @fileOverview Easing equation from yui3
  11630. */
  11631. KISSY.add('anim/easing', function () {
  11632. // Based on Easing Equations (c) 2003 Robert Penner, all rights reserved.
  11633. // This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html
  11634. // Preview: http://www.robertpenner.com/Easing/easing_demo.html
  11635. /**
  11636. * 和 YUI 的 Easing 相比,S.Easing 进行了归一化处理,参数调整为:
  11637. * @param {Number} t Time value used to compute current value 保留 0 =< t <= 1
  11638. * @param {Number} b Starting value b = 0
  11639. * @param {Number} c Delta between start and end values c = 1
  11640. * @param {Number} d Total length of animation d = 1
  11641. */
  11642. var PI = Math.PI,
  11643. pow = Math.pow,
  11644. sin = Math.sin,
  11645. BACK_CONST = 1.70158;
  11646. /**
  11647. * Easing Functions
  11648. * @memberOf Anim
  11649. * @name Easing
  11650. * @namespace
  11651. */
  11652. var Easing =
  11653. /**
  11654. * @lends Anim.Easing
  11655. */
  11656. {
  11657. swing:function (t) {
  11658. return ( -Math.cos(t * PI) / 2 ) + 0.5;
  11659. },
  11660. /**
  11661. * Uniform speed between points.
  11662. */
  11663. "easeNone":function (t) {
  11664. return t;
  11665. },
  11666. /**
  11667. * Begins slowly and accelerates towards end. (quadratic)
  11668. */
  11669. "easeIn":function (t) {
  11670. return t * t;
  11671. },
  11672. /**
  11673. * Begins quickly and decelerates towards end. (quadratic)
  11674. */
  11675. easeOut:function (t) {
  11676. return ( 2 - t) * t;
  11677. },
  11678. /**
  11679. * Begins slowly and decelerates towards end. (quadratic)
  11680. */
  11681. easeBoth:function (t) {
  11682. return (t *= 2) < 1 ?
  11683. .5 * t * t :
  11684. .5 * (1 - (--t) * (t - 2));
  11685. },
  11686. /**
  11687. * Begins slowly and accelerates towards end. (quartic)
  11688. */
  11689. "easeInStrong":function (t) {
  11690. return t * t * t * t;
  11691. },
  11692. /**
  11693. * Begins quickly and decelerates towards end. (quartic)
  11694. */
  11695. easeOutStrong:function (t) {
  11696. return 1 - (--t) * t * t * t;
  11697. },
  11698. /**
  11699. * Begins slowly and decelerates towards end. (quartic)
  11700. */
  11701. "easeBothStrong":function (t) {
  11702. return (t *= 2) < 1 ?
  11703. .5 * t * t * t * t :
  11704. .5 * (2 - (t -= 2) * t * t * t);
  11705. },
  11706. /**
  11707. * Snap in elastic effect.
  11708. */
  11709. "elasticIn":function (t) {
  11710. var p = .3, s = p / 4;
  11711. if (t === 0 || t === 1) return t;
  11712. return -(pow(2, 10 * (t -= 1)) * sin((t - s) * (2 * PI) / p));
  11713. },
  11714. /**
  11715. * Snap out elastic effect.
  11716. */
  11717. elasticOut:function (t) {
  11718. var p = .3, s = p / 4;
  11719. if (t === 0 || t === 1) return t;
  11720. return pow(2, -10 * t) * sin((t - s) * (2 * PI) / p) + 1;
  11721. },
  11722. /**
  11723. * Snap both elastic effect.
  11724. */
  11725. "elasticBoth":function (t) {
  11726. var p = .45, s = p / 4;
  11727. if (t === 0 || (t *= 2) === 2) return t;
  11728. if (t < 1) {
  11729. return -.5 * (pow(2, 10 * (t -= 1)) *
  11730. sin((t - s) * (2 * PI) / p));
  11731. }
  11732. return pow(2, -10 * (t -= 1)) *
  11733. sin((t - s) * (2 * PI) / p) * .5 + 1;
  11734. },
  11735. /**
  11736. * Backtracks slightly, then reverses direction and moves to end.
  11737. */
  11738. "backIn":function (t) {
  11739. if (t === 1) t -= .001;
  11740. return t * t * ((BACK_CONST + 1) * t - BACK_CONST);
  11741. },
  11742. /**
  11743. * Overshoots end, then reverses and comes back to end.
  11744. */
  11745. backOut:function (t) {
  11746. return (t -= 1) * t * ((BACK_CONST + 1) * t + BACK_CONST) + 1;
  11747. },
  11748. /**
  11749. * Backtracks slightly, then reverses direction, overshoots end,
  11750. * then reverses and comes back to end.
  11751. */
  11752. "backBoth":function (t) {
  11753. if ((t *= 2 ) < 1) {
  11754. return .5 * (t * t * (((BACK_CONST *= (1.525)) + 1) * t - BACK_CONST));
  11755. }
  11756. return .5 * ((t -= 2) * t * (((BACK_CONST *= (1.525)) + 1) * t + BACK_CONST) + 2);
  11757. },
  11758. /**
  11759. * Bounce off of start.
  11760. */
  11761. bounceIn:function (t) {
  11762. return 1 - Easing.bounceOut(1 - t);
  11763. },
  11764. /**
  11765. * Bounces off end.
  11766. */
  11767. bounceOut:function (t) {
  11768. var s = 7.5625, r;
  11769. if (t < (1 / 2.75)) {
  11770. r = s * t * t;
  11771. }
  11772. else if (t < (2 / 2.75)) {
  11773. r = s * (t -= (1.5 / 2.75)) * t + .75;
  11774. }
  11775. else if (t < (2.5 / 2.75)) {
  11776. r = s * (t -= (2.25 / 2.75)) * t + .9375;
  11777. }
  11778. else {
  11779. r = s * (t -= (2.625 / 2.75)) * t + .984375;
  11780. }
  11781. return r;
  11782. },
  11783. /**
  11784. * Bounces off start and end.
  11785. */
  11786. "bounceBoth":function (t) {
  11787. if (t < .5) {
  11788. return Easing.bounceIn(t * 2) * .5;
  11789. }
  11790. return Easing.bounceOut(t * 2 - 1) * .5 + .5;
  11791. }
  11792. };
  11793. return Easing;
  11794. });
  11795. /**
  11796. * TODO:
  11797. * - test-Easing.html 详细的测试 + 曲线可视化
  11798. *
  11799. * NOTES:
  11800. * - 综合比较 jQuery UI/scripty2/YUI 的 Easing 命名,还是觉得 YUI 的对用户
  11801. * 最友好。因此这次完全照搬 YUI 的 Easing, 只是代码上做了点压缩优化。
  11802. * - 和原生对应关系:
  11803. * Easing.NativeTimeFunction = {
  11804. * easeNone: 'linear',
  11805. * ease: 'ease',
  11806. *
  11807. * easeIn: 'ease-in',
  11808. * easeOut: 'ease-out',
  11809. * easeBoth: 'ease-in-out',
  11810. *
  11811. * // Ref:
  11812. * // 1. http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
  11813. * // 2. http://www.robertpenner.com/Easing/easing_demo.html
  11814. * // 3. assets/cubic-bezier-timing-function.html
  11815. * // 注:是模拟值,非精确推导值
  11816. * easeInStrong: 'cubic-bezier(0.9, 0.0, 0.9, 0.5)',
  11817. * easeOutStrong: 'cubic-bezier(0.1, 0.5, 0.1, 1.0)',
  11818. * easeBothStrong: 'cubic-bezier(0.9, 0.0, 0.1, 1.0)'
  11819. * };
  11820. */
  11821. /**
  11822. * @fileOverview animate on single property
  11823. * @author yiminghe@gmail.com
  11824. */
  11825. KISSY.add("anim/fx", function (S, DOM, undefined) {
  11826. /**
  11827. * basic animation about single css property or element attribute
  11828. * @param cfg
  11829. */
  11830. function Fx(cfg) {
  11831. this.load(cfg);
  11832. }
  11833. S.augment(Fx, {
  11834. load:function (cfg) {
  11835. var self = this;
  11836. S.mix(self, cfg);
  11837. self.startTime = S.now();
  11838. self.pos = 0;
  11839. self.unit = self.unit || "";
  11840. },
  11841. frame:function (end) {
  11842. var self = this,
  11843. endFlag = 0,
  11844. elapsedTime;
  11845. if (self.finished) {
  11846. return 1;
  11847. }
  11848. var t = S.now();
  11849. if (end || t >= self.duration + self.startTime) {
  11850. self.pos = 1;
  11851. endFlag = 1;
  11852. } else {
  11853. elapsedTime = t - self.startTime;
  11854. self.pos = self.easing(elapsedTime / self.duration);
  11855. }
  11856. self.update();
  11857. self.finished = self.finished || endFlag;
  11858. return endFlag;
  11859. },
  11860. /**
  11861. * 数值插值函数
  11862. * @param {Number} from 源值
  11863. * @param {Number} to 目的值
  11864. * @param {Number} pos 当前位置,从 easing 得到 0~1
  11865. * @return {Number} 当前值
  11866. */
  11867. interpolate:function (from, to, pos) {
  11868. // 默认只对数字进行 easing
  11869. if (S.isNumber(from) &&
  11870. S.isNumber(to)) {
  11871. return (from + (to - from) * pos).toFixed(3);
  11872. } else {
  11873. return undefined;
  11874. }
  11875. },
  11876. update:function () {
  11877. var self = this,
  11878. prop = self.prop,
  11879. elem = self.elem,
  11880. from = self.from,
  11881. to = self.to,
  11882. val = self.interpolate(from, to, self.pos);
  11883. if (val === undefined) {
  11884. // 插值出错,直接设置为最终值
  11885. if (!self.finished) {
  11886. self.finished = 1;
  11887. DOM.css(elem, prop, to);
  11888. S.log(self.prop + " update directly ! : " + val + " : " + from + " : " + to);
  11889. }
  11890. } else {
  11891. val += self.unit;
  11892. if (isAttr(elem, prop)) {
  11893. DOM.attr(elem, prop, val, 1);
  11894. } else {
  11895. DOM.css(elem, prop, val);
  11896. }
  11897. }
  11898. },
  11899. /**
  11900. * current value
  11901. */
  11902. cur:function () {
  11903. var self = this,
  11904. prop = self.prop,
  11905. elem = self.elem;
  11906. if (isAttr(elem, prop)) {
  11907. return DOM.attr(elem, prop, undefined, 1);
  11908. }
  11909. var parsed,
  11910. r = DOM.css(elem, prop);
  11911. // Empty strings, null, undefined and "auto" are converted to 0,
  11912. // complex values such as "rotate(1rad)" or "0px 10px" are returned as is,
  11913. // simple values such as "10px" are parsed to Float.
  11914. return isNaN(parsed = parseFloat(r)) ?
  11915. !r || r === "auto" ? 0 : r
  11916. : parsed;
  11917. }
  11918. });
  11919. function isAttr(elem, prop) {
  11920. // support scrollTop/Left now!
  11921. if ((!elem.style || elem.style[ prop ] == null) &&
  11922. DOM.attr(elem, prop, undefined, 1) != null) {
  11923. return 1;
  11924. }
  11925. return 0;
  11926. }
  11927. Fx.Factories = {};
  11928. Fx.getFx = function (cfg) {
  11929. var Constructor = Fx.Factories[cfg.prop] || Fx;
  11930. return new Constructor(cfg);
  11931. };
  11932. return Fx;
  11933. }, {
  11934. requires:['dom']
  11935. });
  11936. /**
  11937. * TODO
  11938. * 支持 transform ,ie 使用 matrix
  11939. * - http://shawphy.com/2011/01/transformation-matrix-in-front-end.html
  11940. * - http://www.cnblogs.com/winter-cn/archive/2010/12/29/1919266.html
  11941. * - 标准:http://www.zenelements.com/blog/css3-transform/
  11942. * - ie: http://www.useragentman.com/IETransformsTranslator/
  11943. * - wiki: http://en.wikipedia.org/wiki/Transformation_matrix
  11944. * - jq 插件: http://plugins.jquery.com/project/2d-transform
  11945. **//**
  11946. * @fileOverview single timer for the whole anim module
  11947. * @author yiminghe@gmail.com
  11948. */
  11949. KISSY.add("anim/manager", function(S) {
  11950. var stamp = S.stamp;
  11951. return {
  11952. interval:15,
  11953. runnings:{},
  11954. timer:null,
  11955. start:function(anim) {
  11956. var self = this,
  11957. kv = stamp(anim);
  11958. if (self.runnings[kv]) {
  11959. return;
  11960. }
  11961. self.runnings[kv] = anim;
  11962. self.startTimer();
  11963. },
  11964. stop:function(anim) {
  11965. this.notRun(anim);
  11966. },
  11967. notRun:function(anim) {
  11968. var self = this,
  11969. kv = stamp(anim);
  11970. delete self.runnings[kv];
  11971. if (S.isEmptyObject(self.runnings)) {
  11972. self.stopTimer();
  11973. }
  11974. },
  11975. pause:function(anim) {
  11976. this.notRun(anim);
  11977. },
  11978. resume:function(anim) {
  11979. this.start(anim);
  11980. },
  11981. startTimer:function() {
  11982. var self = this;
  11983. if (!self.timer) {
  11984. self.timer = setTimeout(function() {
  11985. if (!self.runFrames()) {
  11986. self.timer = 0;
  11987. self.startTimer();
  11988. } else {
  11989. self.stopTimer();
  11990. }
  11991. }, self.interval);
  11992. }
  11993. },
  11994. stopTimer:function() {
  11995. var self = this,
  11996. t = self.timer;
  11997. if (t) {
  11998. clearTimeout(t);
  11999. self.timer = 0;
  12000. }
  12001. },
  12002. runFrames:function() {
  12003. var self = this,
  12004. done = 1,
  12005. runnings = self.runnings;
  12006. for (var r in runnings) {
  12007. if (runnings.hasOwnProperty(r)) {
  12008. done = 0;
  12009. runnings[r]._frame();
  12010. }
  12011. }
  12012. return done;
  12013. }
  12014. };
  12015. });/**
  12016. * @fileOverview queue of anim objects
  12017. * @author yiminghe@gmail.com
  12018. */
  12019. KISSY.add("anim/queue", function(S, DOM) {
  12020. var /*队列集合容器*/
  12021. queueCollectionKey = S.guid("ks-queue-" + S.now() + "-"),
  12022. /*默认队列*/
  12023. queueKey = S.guid("ks-queue-" + S.now() + "-"),
  12024. // 当前队列是否有动画正在执行
  12025. processing = "...";
  12026. function getQueue(elem, name, readOnly) {
  12027. name = name || queueKey;
  12028. var qu,
  12029. quCollection = DOM.data(elem, queueCollectionKey);
  12030. if (!quCollection && !readOnly) {
  12031. DOM.data(elem, queueCollectionKey, quCollection = {});
  12032. }
  12033. if (quCollection) {
  12034. qu = quCollection[name];
  12035. if (!qu && !readOnly) {
  12036. qu = quCollection[name] = [];
  12037. }
  12038. }
  12039. return qu;
  12040. }
  12041. function removeQueue(elem, name) {
  12042. name = name || queueKey;
  12043. var quCollection = DOM.data(elem, queueCollectionKey);
  12044. if (quCollection) {
  12045. delete quCollection[name];
  12046. }
  12047. if (S.isEmptyObject(quCollection)) {
  12048. DOM.removeData(elem, queueCollectionKey);
  12049. }
  12050. }
  12051. var q = {
  12052. queueCollectionKey:queueCollectionKey,
  12053. queue:function(anim) {
  12054. var elem = anim.elem,
  12055. name = anim.config.queue,
  12056. qu = getQueue(elem, name);
  12057. qu.push(anim);
  12058. if (qu[0] !== processing) {
  12059. q.dequeue(anim);
  12060. }
  12061. return qu;
  12062. },
  12063. remove:function(anim) {
  12064. var elem = anim.elem,
  12065. name = anim.config.queue,
  12066. qu = getQueue(elem, name, 1),index;
  12067. if (qu) {
  12068. index = S.indexOf(anim, qu);
  12069. if (index > -1) {
  12070. qu.splice(index, 1);
  12071. }
  12072. }
  12073. },
  12074. removeQueues:function(elem) {
  12075. DOM.removeData(elem, queueCollectionKey);
  12076. },
  12077. removeQueue:removeQueue,
  12078. dequeue:function(anim) {
  12079. var elem = anim.elem,
  12080. name = anim.config.queue,
  12081. qu = getQueue(elem, name, 1),
  12082. nextAnim = qu && qu.shift();
  12083. if (nextAnim == processing) {
  12084. nextAnim = qu.shift();
  12085. }
  12086. if (nextAnim) {
  12087. qu.unshift(processing);
  12088. nextAnim._runInternal();
  12089. } else {
  12090. // remove queue data
  12091. removeQueue(elem, name);
  12092. }
  12093. }
  12094. };
  12095. return q;
  12096. }, {
  12097. requires:['dom']
  12098. });
  12099. /*
  12100. Copyright 2012, KISSY UI Library v1.30dev
  12101. MIT Licensed
  12102. build time: Jan 5 19:50
  12103. */
  12104. /**
  12105. * @fileOverview anim-node-plugin
  12106. * @author yiminghe@gmail.com,
  12107. * lifesinger@gmail.com,
  12108. * qiaohua@taobao.com,
  12109. *
  12110. */
  12111. KISSY.add('node/anim', function(S, DOM, Anim, Node, undefined) {
  12112. var FX = [
  12113. // height animations
  12114. [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
  12115. // width animations
  12116. [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
  12117. // opacity animations
  12118. [ "opacity" ]
  12119. ];
  12120. function getFxs(type, num, from) {
  12121. var ret = [],
  12122. obj = {};
  12123. for (var i = from || 0; i < num; i++) {
  12124. ret.push.apply(ret, FX[i]);
  12125. }
  12126. for (i = 0; i < ret.length; i++) {
  12127. obj[ret[i]] = type;
  12128. }
  12129. return obj;
  12130. }
  12131. S.augment(Node, {
  12132. animate:function() {
  12133. var self = this,
  12134. args = S.makeArray(arguments);
  12135. S.each(self, function(elem) {
  12136. Anim.apply(undefined, [elem].concat(args)).run();
  12137. });
  12138. return self;
  12139. },
  12140. stop:function(end, clearQueue, queue) {
  12141. var self = this;
  12142. S.each(self, function(elem) {
  12143. Anim.stop(elem, end, clearQueue, queue);
  12144. });
  12145. return self;
  12146. },
  12147. isRunning:function() {
  12148. var self = this;
  12149. for (var i = 0; i < self.length; i++) {
  12150. if (Anim.isRunning(self[i])) {
  12151. return 1;
  12152. }
  12153. }
  12154. return 0;
  12155. }
  12156. });
  12157. S.each({
  12158. show: getFxs("show", 3),
  12159. hide: getFxs("hide", 3),
  12160. toggle:getFxs("toggle", 3),
  12161. fadeIn: getFxs("show", 3, 2),
  12162. fadeOut: getFxs("hide", 3, 2),
  12163. fadeToggle:getFxs("toggle", 3, 2),
  12164. slideDown: getFxs("show", 1),
  12165. slideUp: getFxs("hide", 1),
  12166. slideToggle:getFxs("toggle", 1)
  12167. },
  12168. function(v, k) {
  12169. Node.prototype[k] = function(speed, callback, easing) {
  12170. var self = this;
  12171. // 没有参数时,调用 DOM 中的对应方法
  12172. if (DOM[k] && !speed) {
  12173. DOM[k](self);
  12174. } else {
  12175. S.each(self, function(elem) {
  12176. Anim(elem, v, speed, easing || 'easeOut', callback).run();
  12177. });
  12178. }
  12179. return self;
  12180. };
  12181. });
  12182. }, {
  12183. requires:["dom","anim","./base"]
  12184. });
  12185. /**
  12186. * 2011-11-10
  12187. * - 重写,逻辑放到 Anim 模块,这边只进行转发
  12188. *
  12189. * 2011-05-17
  12190. * - 承玉:添加 stop ,随时停止动画
  12191. *
  12192. * TODO
  12193. * - anim needs queue mechanism ?
  12194. */
  12195. /**
  12196. * @fileOverview import methods from DOM to NodeList.prototype
  12197. * @author yiminghe@gmail.com
  12198. */
  12199. KISSY.add('node/attach', function (S, DOM, Event, NodeList, undefined) {
  12200. var NLP = NodeList.prototype,
  12201. makeArray = S.makeArray,
  12202. // DOM 添加到 NP 上的方法
  12203. // if DOM methods return undefined , Node methods need to transform result to itself
  12204. DOM_INCLUDES_NORM = [
  12205. "equals",
  12206. "contains",
  12207. "scrollTop",
  12208. "scrollLeft",
  12209. "height",
  12210. "width",
  12211. "innerHeight",
  12212. "innerWidth",
  12213. "outerHeight",
  12214. "outerWidth",
  12215. "addStyleSheet",
  12216. // "append" will be overridden
  12217. "appendTo",
  12218. // "prepend" will be overridden
  12219. "prependTo",
  12220. "insertBefore",
  12221. "before",
  12222. "after",
  12223. "insertAfter",
  12224. "test",
  12225. "hasClass",
  12226. "addClass",
  12227. "removeClass",
  12228. "replaceClass",
  12229. "toggleClass",
  12230. "removeAttr",
  12231. "hasAttr",
  12232. "hasProp",
  12233. // anim override
  12234. // "show",
  12235. // "hide",
  12236. // "toggle",
  12237. "scrollIntoView",
  12238. "remove",
  12239. "empty",
  12240. "removeData",
  12241. "hasData",
  12242. "unselectable"
  12243. ],
  12244. // if return array ,need transform to nodelist
  12245. DOM_INCLUDES_NORM_NODE_LIST = [
  12246. "filter",
  12247. "first",
  12248. "last",
  12249. "parent",
  12250. "closest",
  12251. "next",
  12252. "prev",
  12253. "clone",
  12254. "siblings",
  12255. "children"
  12256. ],
  12257. // if set return this else if get return true value ,no nodelist transform
  12258. DOM_INCLUDES_NORM_IF = {
  12259. // dom method : set parameter index
  12260. "attr":1,
  12261. "text":0,
  12262. "css":1,
  12263. "style":1,
  12264. "val":0,
  12265. "prop":1,
  12266. "offset":0,
  12267. "html":0,
  12268. "data":1
  12269. },
  12270. // Event 添加到 NP 上的方法
  12271. EVENT_INCLUDES = [
  12272. "on",
  12273. "detach",
  12274. "fire",
  12275. "fireHandler",
  12276. "delegate",
  12277. "undelegate"
  12278. ];
  12279. function accessNorm(fn, self, args) {
  12280. args.unshift(self);
  12281. var ret = DOM[fn].apply(DOM, args);
  12282. if (ret === undefined) {
  12283. return self;
  12284. }
  12285. return ret;
  12286. }
  12287. function accessNormList(fn, self, args) {
  12288. args.unshift(self);
  12289. var ret = DOM[fn].apply(DOM, args);
  12290. if (ret === undefined) {
  12291. return self;
  12292. }
  12293. else if (ret === null) {
  12294. return null;
  12295. }
  12296. return new NodeList(ret);
  12297. }
  12298. function accessNormIf(fn, self, index, args) {
  12299. // get
  12300. if (args[index] === undefined
  12301. // 并且第一个参数不是对象,否则可能是批量设置写
  12302. && !S.isObject(args[0])) {
  12303. args.unshift(self);
  12304. return DOM[fn].apply(DOM, args);
  12305. }
  12306. // set
  12307. return accessNorm(fn, self, args);
  12308. }
  12309. S.each(DOM_INCLUDES_NORM, function (k) {
  12310. NLP[k] = function () {
  12311. var args = makeArray(arguments);
  12312. return accessNorm(k, this, args);
  12313. };
  12314. });
  12315. S.each(DOM_INCLUDES_NORM_NODE_LIST, function (k) {
  12316. NLP[k] = function () {
  12317. var args = makeArray(arguments);
  12318. return accessNormList(k, this, args);
  12319. };
  12320. });
  12321. S.each(DOM_INCLUDES_NORM_IF, function (index, k) {
  12322. NLP[k] = function () {
  12323. var args = makeArray(arguments);
  12324. return accessNormIf(k, this, index, args);
  12325. };
  12326. });
  12327. S.each(EVENT_INCLUDES, function (k) {
  12328. NLP[k] = function () {
  12329. var self = this,
  12330. args = makeArray(arguments);
  12331. args.unshift(self);
  12332. Event[k].apply(Event, args);
  12333. return self;
  12334. }
  12335. });
  12336. }, {
  12337. requires:["dom", "event", "./base"]
  12338. });
  12339. /**
  12340. * 2011-05-24
  12341. * - 承玉:
  12342. * - 将 DOM 中的方法包装成 NodeList 方法
  12343. * - Node 方法调用参数中的 KISSY NodeList 要转换成第一个 HTML Node
  12344. * - 要注意链式调用,如果 DOM 方法返回 undefined (无返回值),则 NodeList 对应方法返回 this
  12345. * - 实际上可以完全使用 NodeList 来代替 DOM,不和节点关联的方法如:viewportHeight 等,在 window,document 上调用
  12346. * - 存在 window/document 虚节点,通过 S.one(window)/new Node(window) ,S.one(document)/new NodeList(document) 获得
  12347. */
  12348. /**
  12349. * @fileOverview definition for node and nodelist
  12350. * @author yiminghe@gmail.com,lifesinger@gmail.com
  12351. */
  12352. KISSY.add("node/base", function(S, DOM, undefined) {
  12353. var AP = Array.prototype,
  12354. makeArray = S.makeArray,
  12355. isNodeList = DOM._isNodeList;
  12356. /**
  12357. * The NodeList class provides a wrapper for manipulating DOM Node.
  12358. * @class
  12359. * @name NodeList
  12360. */
  12361. function NodeList(html, props, ownerDocument) {
  12362. var self = this,
  12363. domNode;
  12364. if (!(self instanceof NodeList)) {
  12365. return new NodeList(html, props, ownerDocument);
  12366. }
  12367. // handle NodeList(''), NodeList(null), or NodeList(undefined)
  12368. if (!html) {
  12369. return undefined;
  12370. }
  12371. else if (S.isString(html)) {
  12372. // create from html
  12373. domNode = DOM.create(html, props, ownerDocument);
  12374. // ('<p>1</p><p>2</p>') 转换为 NodeList
  12375. if (domNode.nodeType === DOM.DOCUMENT_FRAGMENT_NODE) { // fragment
  12376. AP.push.apply(this, makeArray(domNode.childNodes));
  12377. return undefined;
  12378. }
  12379. }
  12380. else if (S.isArray(html) || isNodeList(html)) {
  12381. AP.push.apply(this, makeArray(html));
  12382. return undefined;
  12383. }
  12384. else {
  12385. // node, document, window
  12386. domNode = html;
  12387. }
  12388. self[0] = domNode;
  12389. self.length = 1;
  12390. return undefined;
  12391. }
  12392. S.augment(NodeList, {
  12393. /**
  12394. * 默认长度为 0
  12395. */
  12396. length: 0,
  12397. item: function(index) {
  12398. var self = this;
  12399. if (S.isNumber(index)) {
  12400. if (index >= self.length) {
  12401. return null;
  12402. } else {
  12403. return new NodeList(self[index]);
  12404. }
  12405. } else {
  12406. return new NodeList(index);
  12407. }
  12408. },
  12409. add:function(selector, context, index) {
  12410. if (S.isNumber(context)) {
  12411. index = context;
  12412. context = undefined;
  12413. }
  12414. var list = NodeList.all(selector, context).getDOMNodes(),
  12415. ret = new NodeList(this);
  12416. if (index === undefined) {
  12417. AP.push.apply(ret, list);
  12418. } else {
  12419. var args = [index,0];
  12420. args.push.apply(args, list);
  12421. AP.splice.apply(ret, args);
  12422. }
  12423. return ret;
  12424. },
  12425. slice:function(start, end) {
  12426. return new NodeList(AP.slice.call(this, start, end));
  12427. },
  12428. /**
  12429. * Retrieves the DOMNodes.
  12430. */
  12431. getDOMNodes: function() {
  12432. return AP.slice.call(this);
  12433. },
  12434. /**
  12435. * Applies the given function to each Node in the NodeList.
  12436. * @param fn The function to apply. It receives 3 arguments: the current node instance, the node's index, and the NodeList instance
  12437. * @param [context] An optional context to apply the function with Default context is the current NodeList instance
  12438. */
  12439. each: function(fn, context) {
  12440. var self = this;
  12441. S.each(self, function(n, i) {
  12442. n = new NodeList(n);
  12443. return fn.call(context || n, n, i, self);
  12444. });
  12445. return self;
  12446. },
  12447. /**
  12448. * Retrieves the DOMNode.
  12449. */
  12450. getDOMNode: function() {
  12451. return this[0];
  12452. },
  12453. /**
  12454. * stack sub query
  12455. */
  12456. end:function() {
  12457. var self = this;
  12458. return self.__parent || self;
  12459. },
  12460. all:function(selector) {
  12461. var ret,self = this;
  12462. if (self.length > 0) {
  12463. ret = NodeList.all(selector, self);
  12464. } else {
  12465. ret = new NodeList();
  12466. }
  12467. ret.__parent = self;
  12468. return ret;
  12469. },
  12470. one:function(selector) {
  12471. var self = this,all = self.all(selector),
  12472. ret = all.length ? all.slice(0, 1) : null;
  12473. if (ret) {
  12474. ret.__parent = self;
  12475. }
  12476. return ret;
  12477. }
  12478. });
  12479. S.mix(NodeList, {
  12480. /**
  12481. * 查找位于上下文中并且符合选择器定义的节点列表或根据 html 生成新节点
  12482. * @param {String|HTMLElement[]|NodeList} selector html 字符串或<a href='http://docs.kissyui.com/docs/html/api/core/dom/selector.html'>选择器</a>或节点列表
  12483. * @param {String|Array<HTMLElement>|NodeList|HTMLElement|Document} [context] 上下文定义
  12484. * @returns {NodeList} 节点列表对象
  12485. */
  12486. all:function(selector, context) {
  12487. // are we dealing with html string ?
  12488. // TextNode 仍需要自己 new Node
  12489. if (S.isString(selector)
  12490. && (selector = S.trim(selector))
  12491. && selector.length >= 3
  12492. && S.startsWith(selector, "<")
  12493. && S.endsWith(selector, ">")
  12494. ) {
  12495. if (context) {
  12496. if (context.getDOMNode) {
  12497. context = context.getDOMNode();
  12498. }
  12499. if (context.ownerDocument) {
  12500. context = context.ownerDocument;
  12501. }
  12502. }
  12503. return new NodeList(selector, undefined, context);
  12504. }
  12505. return new NodeList(DOM.query(selector, context));
  12506. },
  12507. one:function(selector, context) {
  12508. var all = NodeList.all(selector, context);
  12509. return all.length ? all.slice(0, 1) : null;
  12510. }
  12511. });
  12512. S.mix(NodeList, DOM._NODE_TYPE);
  12513. return NodeList;
  12514. }, {
  12515. requires:["dom"]
  12516. });
  12517. /**
  12518. * Notes:
  12519. * 2011-05-25
  12520. * - 承玉:参考 jquery,只有一个 NodeList 对象,Node 就是 NodeList 的别名
  12521. *
  12522. * 2010.04
  12523. * - each 方法传给 fn 的 this, 在 jQuery 里指向原生对象,这样可以避免性能问题。
  12524. * 但从用户角度讲,this 的第一直觉是 $(this), kissy 和 yui3 保持一致,牺牲
  12525. * 性能,以易用为首。
  12526. * - 有了 each 方法,似乎不再需要 import 所有 dom 方法,意义不大。
  12527. * - dom 是低级 api, node 是中级 api, 这是分层的一个原因。还有一个原因是,如果
  12528. * 直接在 node 里实现 dom 方法,则不大好将 dom 的方法耦合到 nodelist 里。可
  12529. * 以说,技术成本会制约 api 设计。
  12530. */
  12531. /**
  12532. * @fileOverview node
  12533. * @author yiminghe@gmail.com
  12534. */
  12535. KISSY.add("node", function(S, Event, Node) {
  12536. Node.KeyCodes = Event.KeyCodes;
  12537. return Node;
  12538. }, {
  12539. requires:[
  12540. "event",
  12541. "node/base",
  12542. "node/attach",
  12543. "node/override",
  12544. "node/anim"]
  12545. });/**
  12546. * @fileOverview overrides methods in NodeList.prototype
  12547. * @author yiminghe@gmail.com
  12548. */
  12549. KISSY.add("node/override", function(S, DOM, Event, NodeList) {
  12550. /**
  12551. * append(node ,parent) : 参数顺序反过来了
  12552. * appendTo(parent,node) : 才是正常
  12553. *
  12554. */
  12555. S.each(['append', 'prepend','before','after'], function(insertType) {
  12556. NodeList.prototype[insertType] = function(html) {
  12557. var newNode = html,self = this;
  12558. // 创建
  12559. if (S.isString(newNode)) {
  12560. newNode = DOM.create(newNode);
  12561. }
  12562. if (newNode) {
  12563. DOM[insertType](newNode, self);
  12564. }
  12565. return self;
  12566. };
  12567. });
  12568. }, {
  12569. requires:["dom","event","./base","./attach"]
  12570. });
  12571. /**
  12572. * 2011-05-24
  12573. * - 承玉:
  12574. * - 重写 NodeList 的某些方法
  12575. * - 添加 one ,all ,从当前 NodeList 往下开始选择节点
  12576. * - 处理 append ,prepend 和 DOM 的参数实际上是反过来的
  12577. * - append/prepend 参数是节点时,如果当前 NodeList 数量 > 1 需要经过 clone,因为同一节点不可能被添加到多个节点中去(NodeList)
  12578. */
  12579. KISSY.use("ua,dom,event,node,json,ajax,anim,base,cookie", function(S, UA, DOM, Event, Node, JSON, Ajax, Anim, Base, Cookie) {
  12580. S.mix(S, {
  12581. UA:UA,
  12582. DOM:DOM,
  12583. Event:Event,
  12584. EventTarget:Event.Target,
  12585. "EventObject":Event.Object,
  12586. Node:Node,
  12587. NodeList:Node,
  12588. JSON:JSON,
  12589. "Ajax":Ajax,
  12590. "IO":Ajax,
  12591. ajax:Ajax,
  12592. io:Ajax,
  12593. jsonp:Ajax.jsonp,
  12594. Anim:Anim,
  12595. Easing:Anim.Easing,
  12596. Base:Base,
  12597. "Cookie":Cookie,
  12598. one:Node.one,
  12599. all:Node.all,
  12600. get:DOM.get,
  12601. query:DOM.query
  12602. });
  12603. });