kissy.js 432 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455
  1. /*
  2. Copyright 2012, KISSY UI Library v1.20
  3. MIT Licensed
  4. build time: Feb 8 17:28
  5. */
  6. /*
  7. * 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 KISSY
  13. */
  14. var host = this,
  15. meta = {
  16. /**
  17. * Copies all the properties of s to r.
  18. * @param deep {boolean} whether recursive mix if encounter object
  19. * @return {Object} the augmented object
  20. */
  21. mix:function (r, s, ov, wl, deep) {
  22. if (!s || !r) {
  23. return r;
  24. }
  25. if (ov === undefined) {
  26. ov = true;
  27. }
  28. var i, p, len;
  29. if (wl && (len = wl.length)) {
  30. for (i = 0; i < len; i++) {
  31. p = wl[i];
  32. if (p in s) {
  33. _mix(p, r, s, ov, deep);
  34. }
  35. }
  36. } else {
  37. for (p in s) {
  38. _mix(p, r, s, ov, deep);
  39. }
  40. }
  41. return r;
  42. }
  43. },
  44. _mix = function (p, r, s, ov, deep) {
  45. if (ov || !(p in r)) {
  46. var target = r[p], src = s[p];
  47. // prevent never-end loop
  48. if (target === src) {
  49. return;
  50. }
  51. // 来源是数组和对象,并且要求深度 mix
  52. if (deep && src && (S.isArray(src) || S.isPlainObject(src))) {
  53. // 目标值为对象或数组,直接 mix
  54. // 否则 新建一个和源值类型一样的空数组/对象,递归 mix
  55. var clone = target && (S.isArray(target) || S.isPlainObject(target)) ?
  56. target :
  57. (S.isArray(src) ? [] : {});
  58. r[p] = S.mix(clone, src, ov, undefined, true);
  59. } else if (src !== undefined) {
  60. r[p] = s[p];
  61. }
  62. }
  63. },
  64. // If KISSY is already defined, the existing KISSY object will not
  65. // be overwritten so that defined namespaces are preserved.
  66. seed = (host && host[S]) || {},
  67. guid = 0,
  68. EMPTY = '';
  69. // The host of runtime environment. specify by user's seed or <this>,
  70. // compatibled for '<this> is null' in unknown engine.
  71. host = seed.__HOST || (seed.__HOST = host || {});
  72. // shortcut and meta for seed.
  73. // override previous kissy
  74. S = host[S] = meta.mix(seed, meta);
  75. S.mix(S, {
  76. configs:{},
  77. // S.app() with these members.
  78. __APP_MEMBERS:['namespace'],
  79. __APP_INIT_METHODS:['__init'],
  80. /**
  81. * The version of the library.
  82. * @type {String}
  83. */
  84. version:'1.20',
  85. buildTime:'20120208172832',
  86. /**
  87. * Returns a new object containing all of the properties of
  88. * all the supplied objects. The properties from later objects
  89. * will overwrite those in earlier objects. Passing in a
  90. * single object will create a shallow copy of it.
  91. * @return {Object} the new merged object
  92. */
  93. merge:function () {
  94. var o = {}, i, l = arguments.length;
  95. for (i = 0; i < l; i++) {
  96. S.mix(o, arguments[i]);
  97. }
  98. return o;
  99. },
  100. /**
  101. * Applies prototype properties from the supplier to the receiver.
  102. * @return {Object} the augmented object
  103. */
  104. augment:function (/*r, s1, s2, ..., ov, wl*/) {
  105. var args = S.makeArray(arguments),
  106. len = args.length - 2,
  107. r = args[0],
  108. ov = args[len],
  109. wl = args[len + 1],
  110. i = 1;
  111. if (!S.isArray(wl)) {
  112. ov = wl;
  113. wl = undefined;
  114. len++;
  115. }
  116. if (!S.isBoolean(ov)) {
  117. ov = undefined;
  118. len++;
  119. }
  120. for (; i < len; i++) {
  121. S.mix(r.prototype, args[i].prototype || args[i], ov, wl);
  122. }
  123. return r;
  124. },
  125. /**
  126. * Utility to set up the prototype, constructor and superclass properties to
  127. * support an inheritance strategy that can chain constructors and methods.
  128. * Static members will not be inherited.
  129. * @param r {Function} the object to modify
  130. * @param s {Function} the object to inherit
  131. * @param px {Object} prototype properties to add/override
  132. * @param {Object} [sx] static properties to add/override
  133. * @return r {Object}
  134. */
  135. extend:function (r, s, px, sx) {
  136. if (!s || !r) {
  137. return r;
  138. }
  139. var create = Object.create ?
  140. function (proto, c) {
  141. return Object.create(proto, {
  142. constructor:{
  143. value:c
  144. }
  145. });
  146. } :
  147. function (proto, c) {
  148. function F() {
  149. }
  150. F.prototype = proto;
  151. var o = new F();
  152. o.constructor = c;
  153. return o;
  154. },
  155. sp = s.prototype,
  156. rp;
  157. // add prototype chain
  158. rp = create(sp, r);
  159. r.prototype = S.mix(rp, r.prototype);
  160. r.superclass = create(sp, s);
  161. // add prototype overrides
  162. if (px) {
  163. S.mix(rp, px);
  164. }
  165. // add object overrides
  166. if (sx) {
  167. S.mix(r, sx);
  168. }
  169. return r;
  170. },
  171. /****************************************************************************************
  172. * The KISSY System Framework *
  173. ****************************************************************************************/
  174. /**
  175. * Initializes KISSY
  176. */
  177. __init:function () {
  178. this.Config = this.Config || {};
  179. this.Env = this.Env || {};
  180. // NOTICE: '@DEBUG@' will replace with '' when compressing.
  181. // So, if loading source file, debug is on by default.
  182. // If loading min version, debug is turned off automatically.
  183. this.Config.debug = '@DEBUG@';
  184. },
  185. /**
  186. * Returns the namespace specified and creates it if it doesn't exist. Be careful
  187. * when naming packages. Reserved words may work in some browsers and not others.
  188. * <code>
  189. * S.namespace('KISSY.app'); // returns KISSY.app
  190. * S.namespace('app.Shop'); // returns KISSY.app.Shop
  191. * S.namespace('TB.app.Shop', true); // returns TB.app.Shop
  192. * </code>
  193. * @return {Object} A reference to the last namespace object created
  194. */
  195. namespace:function () {
  196. var args = S.makeArray(arguments),
  197. l = args.length,
  198. o = null, i, j, p,
  199. global = (args[l - 1] === true && l--);
  200. for (i = 0; i < l; i++) {
  201. p = (EMPTY + args[i]).split('.');
  202. o = global ? host : this;
  203. for (j = (host[p[0]] === o) ? 1 : 0; j < p.length; ++j) {
  204. o = o[p[j]] = o[p[j]] || { };
  205. }
  206. }
  207. return o;
  208. },
  209. /**
  210. * create app based on KISSY.
  211. * @param name {String} the app name
  212. * @param sx {Object} static properties to add/override
  213. * <code>
  214. * S.app('TB');
  215. * TB.namespace('app'); // returns TB.app
  216. * </code>
  217. * @return {Object} A reference to the app global object
  218. */
  219. app:function (name, sx) {
  220. var isStr = S.isString(name),
  221. O = isStr ? host[name] || {} : name,
  222. i = 0,
  223. len = S.__APP_INIT_METHODS.length;
  224. S.mix(O, this, true, S.__APP_MEMBERS);
  225. for (; i < len; i++) {
  226. S[S.__APP_INIT_METHODS[i]].call(O);
  227. }
  228. S.mix(O, S.isFunction(sx) ? sx() : sx);
  229. isStr && (host[name] = O);
  230. return O;
  231. },
  232. config:function (c) {
  233. var configs, cfg, r;
  234. for (var p in c) {
  235. if (c.hasOwnProperty(p)) {
  236. if ((configs = this['configs']) &&
  237. (cfg = configs[p])) {
  238. r = cfg(c[p]);
  239. }
  240. }
  241. }
  242. return r;
  243. },
  244. /**
  245. * Prints debug info.
  246. * @param msg {String} the message to log.
  247. * @param {String} [cat] the log category for the message. Default
  248. * categories are "info", "warn", "error", "time" etc.
  249. * @param {String} [src] the source of the the message (opt)
  250. */
  251. log:function (msg, cat, src) {
  252. if (S.Config.debug) {
  253. if (src) {
  254. msg = src + ': ' + msg;
  255. }
  256. if (host['console'] !== undefined && console.log) {
  257. console[cat && console[cat] ? cat : 'log'](msg);
  258. }
  259. }
  260. },
  261. /**
  262. * Throws error message.
  263. */
  264. error:function (msg) {
  265. if (S.Config.debug) {
  266. throw msg;
  267. }
  268. },
  269. /*
  270. * Generate a global unique id.
  271. * @param {String} [pre] guid prefix
  272. * @return {String} the guid
  273. */
  274. guid:function (pre) {
  275. return (pre || EMPTY) + guid++;
  276. }
  277. });
  278. S.__init();
  279. return S;
  280. })('KISSY', undefined);
  281. /**
  282. * @module lang
  283. * @author lifesinger@gmail.com,yiminghe@gmail.com
  284. * @description this code can run in any ecmascript compliant environment
  285. */
  286. (function (S, undefined) {
  287. var host = S.__HOST,
  288. TRUE = true,
  289. FALSE = false,
  290. OP = Object.prototype,
  291. toString = OP.toString,
  292. hasOwnProperty = OP.hasOwnProperty,
  293. AP = Array.prototype,
  294. indexOf = AP.indexOf,
  295. lastIndexOf = AP.lastIndexOf,
  296. filter = AP.filter,
  297. every = AP.every,
  298. some = AP.some,
  299. //reduce = AP.reduce,
  300. trim = String.prototype.trim,
  301. map = AP.map,
  302. EMPTY = '',
  303. HEX_BASE = 16,
  304. CLONE_MARKER = '__~ks_cloned',
  305. COMPARE_MARKER = '__~ks_compared',
  306. STAMP_MARKER = '__~ks_stamped',
  307. RE_TRIM = /^[\s\xa0]+|[\s\xa0]+$/g,
  308. encode = encodeURIComponent,
  309. decode = decodeURIComponent,
  310. SEP = '&',
  311. EQ = '=',
  312. // [[Class]] -> type pairs
  313. class2type = {},
  314. // http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
  315. htmlEntities = {
  316. '&amp;':'&',
  317. '&gt;':'>',
  318. '&lt;':'<',
  319. '&#x60;':'`',
  320. '&#x2F;':'/',
  321. '&quot;':'"',
  322. '&#x27;':"'"
  323. },
  324. reverseEntities = {},
  325. escapeReg,
  326. unEscapeReg,
  327. // - # $ ^ * ( ) + [ ] { } | \ , . ?
  328. escapeRegExp = /[\-#$\^*()+\[\]{}|\\,.?\s]/g;
  329. (function () {
  330. for (var k in htmlEntities) {
  331. if (htmlEntities.hasOwnProperty(k)) {
  332. reverseEntities[htmlEntities[k]] = k;
  333. }
  334. }
  335. })();
  336. function getEscapeReg() {
  337. if (escapeReg) {
  338. return escapeReg
  339. }
  340. var str = EMPTY;
  341. S.each(htmlEntities, function (entity) {
  342. str += entity + '|';
  343. });
  344. str = str.slice(0, -1);
  345. return escapeReg = new RegExp(str, "g");
  346. }
  347. function getUnEscapeReg() {
  348. if (unEscapeReg) {
  349. return unEscapeReg
  350. }
  351. var str = EMPTY;
  352. S.each(reverseEntities, function (entity) {
  353. str += entity + '|';
  354. });
  355. str += '&#(\\d{1,5});';
  356. return unEscapeReg = new RegExp(str, "g");
  357. }
  358. function isValidParamValue(val) {
  359. var t = typeof val;
  360. // If the type of val is null, undefined, number, string, boolean, return true.
  361. return nullOrUndefined(val) || (t !== 'object' && t !== 'function');
  362. }
  363. S.mix(S, {
  364. /**
  365. * stamp a object by guid
  366. * @return guid associated with this object
  367. */
  368. stamp:function (o, readOnly, marker) {
  369. if (!o) {
  370. return o
  371. }
  372. marker = marker || STAMP_MARKER;
  373. var guid = o[marker];
  374. if (guid) {
  375. return guid;
  376. } else if (!readOnly) {
  377. try {
  378. guid = o[marker] = S.guid(marker);
  379. }
  380. catch (e) {
  381. guid = undefined;
  382. }
  383. }
  384. return guid;
  385. },
  386. noop:function () {
  387. },
  388. /**
  389. * Determine the internal JavaScript [[Class]] of an object.
  390. */
  391. type:function (o) {
  392. return nullOrUndefined(o) ?
  393. String(o) :
  394. class2type[toString.call(o)] || 'object';
  395. },
  396. isNullOrUndefined:nullOrUndefined,
  397. isNull:function (o) {
  398. return o === null;
  399. },
  400. isUndefined:function (o) {
  401. return o === undefined;
  402. },
  403. /**
  404. * Checks to see if an object is empty.
  405. */
  406. isEmptyObject:function (o) {
  407. for (var p in o) {
  408. if (p !== undefined) {
  409. return FALSE;
  410. }
  411. }
  412. return TRUE;
  413. },
  414. /**
  415. * Checks to see if an object is a plain object (created using "{}"
  416. * or "new Object()" or "new FunctionClass()").
  417. * Ref: http://lifesinger.org/blog/2010/12/thinking-of-isplainobject/
  418. */
  419. isPlainObject:function (o) {
  420. /**
  421. * note by yiminghe
  422. * isPlainObject(node=document.getElementById("xx")) -> false
  423. * toString.call(node) : ie678 == '[object Object]',other =='[object HTMLElement]'
  424. * 'isPrototypeOf' in node : ie678 === false ,other === true
  425. */
  426. return o && toString.call(o) === '[object Object]' && 'isPrototypeOf' in o;
  427. },
  428. /**
  429. * 两个目标是否内容相同
  430. *
  431. * @param a 比较目标1
  432. * @param b 比较目标2
  433. * @param [mismatchKeys] internal use
  434. * @param [mismatchValues] internal use
  435. */
  436. equals:function (a, b, /*internal use*/mismatchKeys, /*internal use*/mismatchValues) {
  437. // inspired by jasmine
  438. mismatchKeys = mismatchKeys || [];
  439. mismatchValues = mismatchValues || [];
  440. if (a === b) {
  441. return TRUE;
  442. }
  443. if (a === undefined || a === null || b === undefined || b === null) {
  444. // need type coercion
  445. return nullOrUndefined(a) && nullOrUndefined(b);
  446. }
  447. if (a instanceof Date && b instanceof Date) {
  448. return a.getTime() == b.getTime();
  449. }
  450. if (S.isString(a) && S.isString(b)) {
  451. return (a == b);
  452. }
  453. if (S.isNumber(a) && S.isNumber(b)) {
  454. return (a == b);
  455. }
  456. if (typeof a === "object" && typeof b === "object") {
  457. return compareObjects(a, b, mismatchKeys, mismatchValues);
  458. }
  459. // Straight check
  460. return (a === b);
  461. },
  462. /**
  463. * Creates a deep copy of a plain object or array. Others are returned untouched.
  464. * 稍微改改就和规范一样了 :)
  465. * @param input
  466. * @param {Function} filter filter function
  467. * @refer http://www.w3.org/TR/html5/common-dom-interfaces.html#safe-passing-of-structured-data
  468. */
  469. clone:function (input, filter) {
  470. // Let memory be an association list of pairs of objects,
  471. // initially empty. This is used to handle duplicate references.
  472. // In each pair of objects, one is called the source object
  473. // and the other the destination object.
  474. var memory = {},
  475. ret = cloneInternal(input, filter, memory);
  476. S.each(memory, function (v) {
  477. // 清理在源对象上做的标记
  478. v = v.input;
  479. if (v[CLONE_MARKER]) {
  480. try {
  481. delete v[CLONE_MARKER];
  482. } catch (e) {
  483. S.log("delete CLONE_MARKER error : ");
  484. v[CLONE_MARKER] = undefined;
  485. }
  486. }
  487. });
  488. memory = null;
  489. return ret;
  490. },
  491. /**
  492. * Removes the whitespace from the beginning and end of a string.
  493. */
  494. trim:trim ?
  495. function (str) {
  496. return nullOrUndefined(str) ? EMPTY : trim.call(str);
  497. } :
  498. function (str) {
  499. return nullOrUndefined(str) ? EMPTY : str.toString().replace(RE_TRIM, EMPTY);
  500. },
  501. /**
  502. * Substitutes keywords in a string using an object/array.
  503. * Removes undefined keywords and ignores escaped keywords.
  504. */
  505. substitute:function (str, o, regexp) {
  506. if (!S.isString(str)
  507. || !S.isPlainObject(o)) {
  508. return str;
  509. }
  510. return str.replace(regexp || /\\?\{([^{}]+)\}/g, function (match, name) {
  511. if (match.charAt(0) === '\\') {
  512. return match.slice(1);
  513. }
  514. return (o[name] === undefined) ? EMPTY : o[name];
  515. });
  516. },
  517. /**
  518. * Executes the supplied function on each item in the array.
  519. * @param object {Object} the object to iterate
  520. * @param fn {Function} the function to execute on each item. The function
  521. * receives three arguments: the value, the index, the full array.
  522. * @param {Object} [context]
  523. */
  524. each:function (object, fn, context) {
  525. if (object) {
  526. var key,
  527. val,
  528. i = 0,
  529. length = object && object.length,
  530. isObj = length === undefined || S.type(object) === 'function';
  531. context = context || host;
  532. if (isObj) {
  533. for (key in object) {
  534. // can not use hasOwnProperty
  535. if (fn.call(context, object[key], key, object) === FALSE) {
  536. break;
  537. }
  538. }
  539. } else {
  540. for (val = object[0];
  541. i < length && fn.call(context, val, i, object) !== FALSE; val = object[++i]) {
  542. }
  543. }
  544. }
  545. return object;
  546. },
  547. /**
  548. * Search for a specified value within an array.
  549. */
  550. indexOf:indexOf ?
  551. function (item, arr) {
  552. return indexOf.call(arr, item);
  553. } :
  554. function (item, arr) {
  555. for (var i = 0, len = arr.length; i < len; ++i) {
  556. if (arr[i] === item) {
  557. return i;
  558. }
  559. }
  560. return -1;
  561. },
  562. /**
  563. * Returns the index of the last item in the array
  564. * that contains the specified value, -1 if the
  565. * value isn't found.
  566. */
  567. lastIndexOf:(lastIndexOf) ?
  568. function (item, arr) {
  569. return lastIndexOf.call(arr, item);
  570. } :
  571. function (item, arr) {
  572. for (var i = arr.length - 1; i >= 0; i--) {
  573. if (arr[i] === item) {
  574. break;
  575. }
  576. }
  577. return i;
  578. },
  579. /**
  580. * Returns a copy of the array with the duplicate entries removed
  581. * @param a {Array} the array to find the subset of uniques for
  582. * @param override {Boolean}
  583. * if override is true, S.unique([a, b, a]) => [b, a]
  584. * if override is false, S.unique([a, b, a]) => [a, b]
  585. * @return {Array} a copy of the array with duplicate entries removed
  586. */
  587. unique:function (a, override) {
  588. var b = a.slice();
  589. if (override) {
  590. b.reverse();
  591. }
  592. var i = 0,
  593. n,
  594. item;
  595. while (i < b.length) {
  596. item = b[i];
  597. while ((n = S.lastIndexOf(item, b)) !== i) {
  598. b.splice(n, 1);
  599. }
  600. i += 1;
  601. }
  602. if (override) {
  603. b.reverse();
  604. }
  605. return b;
  606. },
  607. /**
  608. * Search for a specified value index within an array.
  609. */
  610. inArray:function (item, arr) {
  611. return S.indexOf(item, arr) > -1;
  612. },
  613. /**
  614. * Executes the supplied function on each item in the array.
  615. * Returns a new array containing the items that the supplied
  616. * function returned true for.
  617. * @param arr {Array} the array to iterate
  618. * @param fn {Function} the function to execute on each item
  619. * @param context {Object} optional context object
  620. * @return {Array} The items on which the supplied function
  621. * returned true. If no items matched an empty array is
  622. * returned.
  623. */
  624. filter:filter ?
  625. function (arr, fn, context) {
  626. return filter.call(arr, fn, context || this);
  627. } :
  628. function (arr, fn, context) {
  629. var ret = [];
  630. S.each(arr, function (item, i, arr) {
  631. if (fn.call(context || this, item, i, arr)) {
  632. ret.push(item);
  633. }
  634. });
  635. return ret;
  636. },
  637. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map
  638. map:map ?
  639. function (arr, fn, context) {
  640. return map.call(arr, fn, context || this);
  641. } :
  642. function (arr, fn, context) {
  643. var len = arr.length,
  644. res = new Array(len);
  645. for (var i = 0; i < len; i++) {
  646. var el = S.isString(arr) ? arr.charAt(i) : arr[i];
  647. if (el
  648. ||
  649. //ie<9 in invalid when typeof arr == string
  650. i in arr) {
  651. res[i] = fn.call(context || this, el, i, arr);
  652. }
  653. }
  654. return res;
  655. },
  656. /**
  657. * @refer https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/reduce
  658. */
  659. reduce:/*
  660. NaN ?
  661. reduce ? function(arr, callback, initialValue) {
  662. return arr.reduce(callback, initialValue);
  663. } : */function (arr, callback, initialValue) {
  664. var len = arr.length;
  665. if (typeof callback !== "function") {
  666. throw new TypeError("callback is not function!");
  667. }
  668. // no value to return if no initial value and an empty array
  669. if (len === 0 && arguments.length == 2) {
  670. throw new TypeError("arguments invalid");
  671. }
  672. var k = 0;
  673. var accumulator;
  674. if (arguments.length >= 3) {
  675. accumulator = arguments[2];
  676. }
  677. else {
  678. do {
  679. if (k in arr) {
  680. accumulator = arr[k++];
  681. break;
  682. }
  683. // if array contains no values, no initial value to return
  684. k += 1;
  685. if (k >= len) {
  686. throw new TypeError();
  687. }
  688. }
  689. while (TRUE);
  690. }
  691. while (k < len) {
  692. if (k in arr) {
  693. accumulator = callback.call(undefined, accumulator, arr[k], k, arr);
  694. }
  695. k++;
  696. }
  697. return accumulator;
  698. },
  699. every:every ?
  700. function (arr, fn, context) {
  701. return every.call(arr, fn, context || this);
  702. } :
  703. function (arr, fn, context) {
  704. var len = arr && arr.length || 0;
  705. for (var i = 0; i < len; i++) {
  706. if (i in arr && !fn.call(context, arr[i], i, arr)) {
  707. return FALSE;
  708. }
  709. }
  710. return TRUE;
  711. },
  712. some:some ?
  713. function (arr, fn, context) {
  714. return some.call(arr, fn, context || this);
  715. } :
  716. function (arr, fn, context) {
  717. var len = arr && arr.length || 0;
  718. for (var i = 0; i < len; i++) {
  719. if (i in arr && fn.call(context, arr[i], i, arr)) {
  720. return TRUE;
  721. }
  722. }
  723. return FALSE;
  724. },
  725. /**
  726. * it is not same with native bind
  727. * @refer https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
  728. */
  729. bind:function (fn, obj) {
  730. var slice = [].slice,
  731. args = slice.call(arguments, 2),
  732. fNOP = function () {
  733. },
  734. bound = function () {
  735. return fn.apply(this instanceof fNOP ? this : obj,
  736. args.concat(slice.call(arguments)));
  737. };
  738. fNOP.prototype = fn.prototype;
  739. bound.prototype = new fNOP();
  740. return bound;
  741. },
  742. /**
  743. * Gets current date in milliseconds.
  744. * @refer https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/now
  745. * http://j-query.blogspot.com/2011/02/timing-ecmascript-5-datenow-function.html
  746. * http://kangax.github.com/es5-compat-table/
  747. */
  748. now:Date.now || function () {
  749. return +new Date();
  750. },
  751. /**
  752. * frequently used in taobao cookie about nick
  753. */
  754. fromUnicode:function (str) {
  755. return str.replace(/\\u([a-f\d]{4})/ig, function (m, u) {
  756. return String.fromCharCode(parseInt(u, HEX_BASE));
  757. });
  758. },
  759. /**
  760. * escape string to html
  761. * @refer http://yiminghe.javaeye.com/blog/788929
  762. * http://wonko.com/post/html-escaping
  763. * @param str {string} text2html show
  764. */
  765. escapeHTML:function (str) {
  766. return str.replace(getEscapeReg(), function (m) {
  767. return reverseEntities[m];
  768. });
  769. },
  770. escapeRegExp:function (str) {
  771. return str.replace(escapeRegExp, '\\$&');
  772. },
  773. /**
  774. * unescape html to string
  775. * @param str {string} html2text
  776. */
  777. unEscapeHTML:function (str) {
  778. return str.replace(getUnEscapeReg(), function (m, n) {
  779. return htmlEntities[m] || String.fromCharCode(+n);
  780. });
  781. },
  782. /**
  783. * Converts object to a true array.
  784. * @param o {object|Array} array like object or array
  785. * @return {Array}
  786. */
  787. makeArray:function (o) {
  788. if (nullOrUndefined(o)) {
  789. return [];
  790. }
  791. if (S.isArray(o)) {
  792. return o;
  793. }
  794. // The strings and functions also have 'length'
  795. if (typeof o.length !== 'number' || S.isString(o) || S.isFunction(o)) {
  796. return [o];
  797. }
  798. var ret = [];
  799. for (var i = 0, l = o.length; i < l; i++) {
  800. ret[i] = o[i];
  801. }
  802. return ret;
  803. },
  804. /**
  805. * Creates a serialized string of an array or object.
  806. * @return {String}
  807. * <code>
  808. * {foo: 1, bar: 2} // -> 'foo=1&bar=2'
  809. * {foo: 1, bar: [2, 3]} // -> 'foo=1&bar=2&bar=3'
  810. * {foo: '', bar: 2} // -> 'foo=&bar=2'
  811. * {foo: undefined, bar: 2} // -> 'foo=undefined&bar=2'
  812. * {foo: true, bar: 2} // -> 'foo=true&bar=2'
  813. * </code>
  814. */
  815. param:function (o, sep, eq, arr) {
  816. if (!S.isPlainObject(o)) {
  817. return EMPTY;
  818. }
  819. sep = sep || SEP;
  820. eq = eq || EQ;
  821. if (S.isUndefined(arr)) {
  822. arr = TRUE;
  823. }
  824. var buf = [], key, val;
  825. for (key in o) {
  826. if (o.hasOwnProperty(key)) {
  827. val = o[key];
  828. key = encode(key);
  829. // val is valid non-array value
  830. if (isValidParamValue(val)) {
  831. buf.push(key, eq, encode(val + EMPTY), sep);
  832. }
  833. // val is not empty array
  834. else if (S.isArray(val) && val.length) {
  835. for (var i = 0, len = val.length; i < len; ++i) {
  836. if (isValidParamValue(val[i])) {
  837. buf.push(key,
  838. (arr ? encode("[]") : EMPTY),
  839. eq, encode(val[i] + EMPTY), sep);
  840. }
  841. }
  842. }
  843. // ignore other cases, including empty array, Function, RegExp, Date etc.
  844. }
  845. }
  846. buf.pop();
  847. return buf.join(EMPTY);
  848. },
  849. /**
  850. * Parses a URI-like query string and returns an object composed of parameter/value pairs.
  851. * <code>
  852. * 'section=blog&id=45' // -> {section: 'blog', id: '45'}
  853. * 'section=blog&tag=js&tag=doc' // -> {section: 'blog', tag: ['js', 'doc']}
  854. * 'tag=ruby%20on%20rails' // -> {tag: 'ruby on rails'}
  855. * 'id=45&raw' // -> {id: '45', raw: ''}
  856. * </code>
  857. */
  858. unparam:function (str, sep, eq) {
  859. if (typeof str !== 'string'
  860. || (str = S.trim(str)).length === 0) {
  861. return {};
  862. }
  863. sep = sep || SEP;
  864. eq = eq || EQ;
  865. var ret = {},
  866. pairs = str.split(sep),
  867. pair, key, val,
  868. i = 0, len = pairs.length;
  869. for (; i < len; ++i) {
  870. pair = pairs[i].split(eq);
  871. key = decode(pair[0]);
  872. try {
  873. val = decode(pair[1] || EMPTY);
  874. } catch (e) {
  875. S.log(e + "decodeURIComponent error : " + pair[1], "error");
  876. val = pair[1] || EMPTY;
  877. }
  878. if (S.endsWith(key, "[]")) {
  879. key = key.substring(0, key.length - 2);
  880. }
  881. if (hasOwnProperty.call(ret, key)) {
  882. if (S.isArray(ret[key])) {
  883. ret[key].push(val);
  884. } else {
  885. ret[key] = [ret[key], val];
  886. }
  887. } else {
  888. ret[key] = val;
  889. }
  890. }
  891. return ret;
  892. },
  893. /**
  894. * Executes the supplied function in the context of the supplied
  895. * object 'when' milliseconds later. Executes the function a
  896. * single time unless periodic is set to true.
  897. * @param fn {Function|String} the function to execute or the name of the method in
  898. * the 'o' object to execute.
  899. * @param when {Number} the number of milliseconds to wait until the fn is executed.
  900. * @param periodic {Boolean} if true, executes continuously at supplied interval
  901. * until canceled.
  902. * @param context {Object} the context object.
  903. * @param [data] that is provided to the function. This accepts either a single
  904. * item or an array. If an array is provided, the function is executed with
  905. * one parameter for each array item. If you need to pass a single array
  906. * parameter, it needs to be wrapped in an array [myarray].
  907. * @return {Object} a timer object. Call the cancel() method on this object to stop
  908. * the timer.
  909. */
  910. later:function (fn, when, periodic, context, data) {
  911. when = when || 0;
  912. var m = fn,
  913. d = S.makeArray(data),
  914. f,
  915. r;
  916. if (S.isString(fn)) {
  917. m = context[fn];
  918. }
  919. if (!m) {
  920. S.error('method undefined');
  921. }
  922. f = function () {
  923. m.apply(context, d);
  924. };
  925. r = (periodic) ? setInterval(f, when) : setTimeout(f, when);
  926. return {
  927. id:r,
  928. interval:periodic,
  929. cancel:function () {
  930. if (this.interval) {
  931. clearInterval(r);
  932. } else {
  933. clearTimeout(r);
  934. }
  935. }
  936. };
  937. },
  938. startsWith:function (str, prefix) {
  939. return str.lastIndexOf(prefix, 0) === 0;
  940. },
  941. endsWith:function (str, suffix) {
  942. var ind = str.length - suffix.length;
  943. return ind >= 0 && str.indexOf(suffix, ind) == ind;
  944. },
  945. /**
  946. * Based on YUI3
  947. * Throttles a call to a method based on the time between calls.
  948. * @param {function} fn The function call to throttle.
  949. * @param {object} context ontext fn to run
  950. * @param {Number} ms The number of milliseconds to throttle the method call.
  951. * Passing a -1 will disable the throttle. Defaults to 150.
  952. * @return {function} Returns a wrapped function that calls fn throttled.
  953. */
  954. throttle:function (fn, ms, context) {
  955. ms = ms || 150;
  956. if (ms === -1) {
  957. return (function () {
  958. fn.apply(context || this, arguments);
  959. });
  960. }
  961. var last = S.now();
  962. return (function () {
  963. var now = S.now();
  964. if (now - last > ms) {
  965. last = now;
  966. fn.apply(context || this, arguments);
  967. }
  968. });
  969. },
  970. /**
  971. * buffers a call between a fixed time
  972. * @param {function} fn
  973. * @param {object} [context]
  974. * @param {Number} ms
  975. */
  976. buffer:function (fn, ms, context) {
  977. ms = ms || 150;
  978. if (ms === -1) {
  979. return (function () {
  980. fn.apply(context || this, arguments);
  981. });
  982. }
  983. var bufferTimer = null;
  984. function f() {
  985. f.stop();
  986. bufferTimer = S.later(fn, ms, FALSE, context || this);
  987. }
  988. f.stop = function () {
  989. if (bufferTimer) {
  990. bufferTimer.cancel();
  991. bufferTimer = 0;
  992. }
  993. };
  994. return f;
  995. }
  996. });
  997. // for idea ..... auto-hint
  998. S.mix(S, {
  999. isBoolean:isValidParamValue,
  1000. isNumber:isValidParamValue,
  1001. isString:isValidParamValue,
  1002. isFunction:isValidParamValue,
  1003. isArray:isValidParamValue,
  1004. isDate:isValidParamValue,
  1005. isRegExp:isValidParamValue,
  1006. isObject:isValidParamValue
  1007. });
  1008. S.each('Boolean Number String Function Array Date RegExp Object'.split(' '),
  1009. function (name, lc) {
  1010. // populate the class2type map
  1011. class2type['[object ' + name + ']'] = (lc = name.toLowerCase());
  1012. // add isBoolean/isNumber/...
  1013. S['is' + name] = function (o) {
  1014. return S.type(o) == lc;
  1015. }
  1016. });
  1017. function nullOrUndefined(o) {
  1018. return S.isNull(o) || S.isUndefined(o);
  1019. }
  1020. function cloneInternal(input, f, memory) {
  1021. var destination = input,
  1022. isArray,
  1023. isPlainObject,
  1024. k,
  1025. stamp;
  1026. if (!input) {
  1027. return destination;
  1028. }
  1029. // If input is the source object of a pair of objects in memory,
  1030. // then return the destination object in that pair of objects .
  1031. // and abort these steps.
  1032. if (input[CLONE_MARKER]) {
  1033. // 对应的克隆后对象
  1034. return memory[input[CLONE_MARKER]].destination;
  1035. } else if (typeof input === "object") {
  1036. // 引用类型要先记录
  1037. var constructor = input.constructor;
  1038. if (S.inArray(constructor, [Boolean, String, Number, Date, RegExp])) {
  1039. destination = new constructor(input.valueOf());
  1040. }
  1041. // ImageData , File, Blob , FileList .. etc
  1042. else if (isArray = S.isArray(input)) {
  1043. destination = f ? S.filter(input, f) : input.concat();
  1044. } else if (isPlainObject = S.isPlainObject(input)) {
  1045. destination = {};
  1046. }
  1047. // Add a mapping from input (the source object)
  1048. // to output (the destination object) to memory.
  1049. // 做标记
  1050. input[CLONE_MARKER] = (stamp = S.guid());
  1051. // 存储源对象以及克隆后的对象
  1052. memory[stamp] = {destination:destination, input:input};
  1053. }
  1054. // If input is an Array object or an Object object,
  1055. // then, for each enumerable property in input,
  1056. // add a new property to output having the same name,
  1057. // and having a value created from invoking the internal structured cloning algorithm recursively
  1058. // with the value of the property as the "input" argument and memory as the "memory" argument.
  1059. // The order of the properties in the input and output objects must be the same.
  1060. // clone it
  1061. if (isArray) {
  1062. for (var i = 0; i < destination.length; i++) {
  1063. destination[i] = cloneInternal(destination[i], f, memory);
  1064. }
  1065. } else if (isPlainObject) {
  1066. for (k in input) {
  1067. if (input.hasOwnProperty(k)) {
  1068. if (k !== CLONE_MARKER &&
  1069. (!f || (f.call(input, input[k], k, input) !== FALSE))) {
  1070. destination[k] = cloneInternal(input[k], f, memory);
  1071. }
  1072. }
  1073. }
  1074. }
  1075. return destination;
  1076. }
  1077. function compareObjects(a, b, mismatchKeys, mismatchValues) {
  1078. // 两个比较过了,无需再比较,防止循环比较
  1079. if (a[COMPARE_MARKER] === b && b[COMPARE_MARKER] === a) {
  1080. return TRUE;
  1081. }
  1082. a[COMPARE_MARKER] = b;
  1083. b[COMPARE_MARKER] = a;
  1084. var hasKey = function (obj, keyName) {
  1085. return (obj !== null && obj !== undefined) && obj[keyName] !== undefined;
  1086. };
  1087. for (var property in b) {
  1088. if (b.hasOwnProperty(property)) {
  1089. if (!hasKey(a, property) && hasKey(b, property)) {
  1090. mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
  1091. }
  1092. }
  1093. }
  1094. for (property in a) {
  1095. if (a.hasOwnProperty(property)) {
  1096. if (!hasKey(b, property) && hasKey(a, property)) {
  1097. mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
  1098. }
  1099. }
  1100. }
  1101. for (property in b) {
  1102. if (b.hasOwnProperty(property)) {
  1103. if (property == COMPARE_MARKER) {
  1104. continue;
  1105. }
  1106. if (!S.equals(a[property], b[property], mismatchKeys, mismatchValues)) {
  1107. mismatchValues.push("'" + property + "' was '" + (b[property] ? (b[property].toString()) : b[property])
  1108. + "' in expected, but was '" +
  1109. (a[property] ? (a[property].toString()) : a[property]) + "' in actual.");
  1110. }
  1111. }
  1112. }
  1113. if (S.isArray(a) && S.isArray(b) && a.length != b.length) {
  1114. mismatchValues.push("arrays were not the same length");
  1115. }
  1116. delete a[COMPARE_MARKER];
  1117. delete b[COMPARE_MARKER];
  1118. return (mismatchKeys.length === 0 && mismatchValues.length === 0);
  1119. }
  1120. })(KISSY, undefined);
  1121. /**
  1122. * setup data structure for kissy loader
  1123. * @author yiminghe@gmail.com
  1124. */
  1125. (function(S){
  1126. if("require" in this) {
  1127. return;
  1128. }
  1129. S.__loader={};
  1130. S.__loaderUtils={};
  1131. S.__loaderData={};
  1132. })(KISSY);/**
  1133. * map mechanism
  1134. * @author yiminghe@gmail.com
  1135. */
  1136. (function (S, loader) {
  1137. if ("require" in this) {
  1138. return;
  1139. }
  1140. /**
  1141. * modify current module path
  1142. * @param rules
  1143. * @example
  1144. * [
  1145. * [/(.+-)min(.js(\?t=\d+)?)$/,"$1$2"],
  1146. * [/(.+-)min(.js(\?t=\d+)?)$/,function(_,m1,m2){
  1147. * return m1+m2;
  1148. * }]
  1149. * ]
  1150. */
  1151. S.configs.map = function (rules) {
  1152. S.Config.mappedRules = (S.Config.mappedRules || []).concat(rules);
  1153. };
  1154. S.mix(loader, {
  1155. __getMappedPath:function (path) {
  1156. var __mappedRules = S.Config.mappedRules || [];
  1157. for (var i = 0; i < __mappedRules.length; i++) {
  1158. var m, rule = __mappedRules[i];
  1159. if (m = path.match(rule[0])) {
  1160. return path.replace(rule[0], rule[1]);
  1161. }
  1162. }
  1163. return path;
  1164. }
  1165. });
  1166. })(KISSY, KISSY.__loader);/**
  1167. * combine mechanism
  1168. * @author yiminghe@gmail.com
  1169. */
  1170. (function (S, loader) {
  1171. if ("require" in this) {
  1172. return;
  1173. }
  1174. var combines;
  1175. /**
  1176. * compress 'from module' to 'to module'
  1177. * {
  1178. * core:['dom','ua','event','node','json','ajax','anim','base','cookie']
  1179. * }
  1180. */
  1181. combines = S.configs.combines = function (from, to) {
  1182. var cs;
  1183. if (S.isObject(from)) {
  1184. S.each(from, function (v, k) {
  1185. S.each(v, function (v2) {
  1186. combines(v2, k);
  1187. });
  1188. });
  1189. return;
  1190. }
  1191. cs = S.Config.combines = S.Config.combines || {};
  1192. if (to) {
  1193. cs[from] = to;
  1194. } else {
  1195. return cs[from] || from;
  1196. }
  1197. };
  1198. S.mix(loader, {
  1199. __getCombinedMod:function (modName) {
  1200. var cs;
  1201. cs = S.Config.combines = S.Config.combines || {};
  1202. return cs[modName] || modName;
  1203. }
  1204. });
  1205. })(KISSY, KISSY.__loader);/**
  1206. * status constants
  1207. * @author yiminghe@gmail.com
  1208. */
  1209. (function(S, data) {
  1210. if ("require" in this) {
  1211. return;
  1212. }
  1213. // 脚本(loadQueue)/模块(mod) 公用状态
  1214. S.mix(data, {
  1215. "INIT":0,
  1216. "LOADING" : 1,
  1217. "LOADED" : 2,
  1218. "ERROR" : 3,
  1219. // 模块特有
  1220. "ATTACHED" : 4
  1221. });
  1222. })(KISSY, KISSY.__loaderData);/**
  1223. * utils for kissy loader
  1224. * @author yiminghe@gmail.com
  1225. */
  1226. (function(S, loader, utils) {
  1227. if ("require" in this) {
  1228. return;
  1229. }
  1230. var ua = navigator.userAgent,doc = document;
  1231. S.mix(utils, {
  1232. docHead:function() {
  1233. return doc.getElementsByTagName('head')[0] || doc.documentElement;
  1234. },
  1235. isWebKit:!!ua.match(/AppleWebKit/),
  1236. IE : !!ua.match(/MSIE/),
  1237. isCss:function(url) {
  1238. return /\.css(?:\?|$)/i.test(url);
  1239. },
  1240. isLinkNode:function(n) {
  1241. return n.nodeName.toLowerCase() == 'link';
  1242. },
  1243. /**
  1244. * resolve relative part of path
  1245. * x/../y/z -> y/z
  1246. * x/./y/z -> x/y/z
  1247. * @param path uri path
  1248. * @return {string} resolved path
  1249. * @description similar to path.normalize in nodejs
  1250. */
  1251. normalizePath:function(path) {
  1252. var paths = path.split("/"),
  1253. re = [],
  1254. p;
  1255. for (var i = 0; i < paths.length; i++) {
  1256. p = paths[i];
  1257. if (p == ".") {
  1258. } else if (p == "..") {
  1259. re.pop();
  1260. } else {
  1261. re.push(p);
  1262. }
  1263. }
  1264. return re.join("/");
  1265. },
  1266. /**
  1267. * 根据当前模块以及依赖模块的相对路径,得到依赖模块的绝对路径
  1268. * @param moduleName 当前模块
  1269. * @param depName 依赖模块
  1270. * @return {string|Array} 依赖模块的绝对路径
  1271. * @description similar to path.resolve in nodejs
  1272. */
  1273. normalDepModuleName:function normalDepModuleName(moduleName, depName) {
  1274. if (!depName) {
  1275. return depName;
  1276. }
  1277. if (S.isArray(depName)) {
  1278. for (var i = 0; i < depName.length; i++) {
  1279. depName[i] = normalDepModuleName(moduleName, depName[i]);
  1280. }
  1281. return depName;
  1282. }
  1283. if (startsWith(depName, "../") || startsWith(depName, "./")) {
  1284. var anchor = "",index;
  1285. // x/y/z -> x/y/
  1286. if ((index = moduleName.lastIndexOf("/")) != -1) {
  1287. anchor = moduleName.substring(0, index + 1);
  1288. }
  1289. return normalizePath(anchor + depName);
  1290. } else if (depName.indexOf("./") != -1
  1291. || depName.indexOf("../") != -1) {
  1292. return normalizePath(depName);
  1293. } else {
  1294. return depName;
  1295. }
  1296. },
  1297. //去除后缀名,要考虑时间戳?
  1298. removePostfix:function (path) {
  1299. return path.replace(/(-min)?\.js[^/]*$/i, "");
  1300. },
  1301. /**
  1302. * 路径正则化,不能是相对地址
  1303. * 相对地址则转换成相对页面的绝对地址
  1304. * 用途:
  1305. * package path 相对地址则相对于当前页面获取绝对地址
  1306. */
  1307. normalBasePath:function (path) {
  1308. path = S.trim(path);
  1309. // path 为空时,不能变成 "/"
  1310. if (path && path.charAt(path.length - 1) != '/') {
  1311. path += "/";
  1312. }
  1313. /**
  1314. * 一定要正则化,防止出现 ../ 等相对路径
  1315. * 考虑本地路径
  1316. */
  1317. if (!path.match(/^(http(s)?)|(file):/i)
  1318. && !startsWith(path, "/")) {
  1319. path = loader.__pagePath + path;
  1320. }
  1321. return normalizePath(path);
  1322. },
  1323. /**
  1324. * 相对路径文件名转换为绝对路径
  1325. * @param path
  1326. */
  1327. absoluteFilePath:function(path) {
  1328. path = utils.normalBasePath(path);
  1329. return path.substring(0, path.length - 1);
  1330. },
  1331. //http://wiki.commonjs.org/wiki/Packages/Mappings/A
  1332. //如果模块名以 / 结尾,自动加 index
  1333. indexMapping:function (names) {
  1334. for (var i = 0; i < names.length; i++) {
  1335. if (names[i].match(/\/$/)) {
  1336. names[i] += "index";
  1337. }
  1338. }
  1339. return names;
  1340. }
  1341. });
  1342. var startsWith = S.startsWith,normalizePath = utils.normalizePath;
  1343. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  1344. * script/css load across browser
  1345. * @author yiminghe@gmail.com
  1346. */
  1347. (function(S, utils) {
  1348. if ("require" in this) {
  1349. return;
  1350. }
  1351. var CSS_POLL_INTERVAL = 30,
  1352. /**
  1353. * central poll for link node
  1354. */
  1355. timer = 0,
  1356. monitors = {
  1357. /**
  1358. * node.id:[callback]
  1359. */
  1360. };
  1361. function startCssTimer() {
  1362. if (!timer) {
  1363. S.log("start css polling");
  1364. cssPoll();
  1365. }
  1366. }
  1367. // single thread is ok
  1368. function cssPoll() {
  1369. for (var url in monitors) {
  1370. var callbacks = monitors[url],
  1371. node = callbacks.node,
  1372. loaded = 0;
  1373. if (utils.isWebKit) {
  1374. if (node['sheet']) {
  1375. S.log("webkit loaded : " + url);
  1376. loaded = 1;
  1377. }
  1378. } else if (node['sheet']) {
  1379. try {
  1380. var cssRules;
  1381. if (cssRules = node['sheet'].cssRules) {
  1382. S.log('firefox ' + cssRules + ' loaded : ' + url);
  1383. loaded = 1;
  1384. }
  1385. } catch(ex) {
  1386. // S.log('firefox ' + ex.name + ' ' + ex.code + ' ' + url);
  1387. // if (ex.name === 'NS_ERROR_DOM_SECURITY_ERR') {
  1388. if (ex.code === 1000) {
  1389. S.log('firefox ' + ex.name + ' loaded : ' + url);
  1390. loaded = 1;
  1391. }
  1392. }
  1393. }
  1394. if (loaded) {
  1395. for (var i = 0; i < callbacks.length; i++) {
  1396. callbacks[i].call(node);
  1397. }
  1398. delete monitors[url];
  1399. }
  1400. }
  1401. if (S.isEmptyObject(monitors)) {
  1402. timer = 0;
  1403. S.log("end css polling");
  1404. } else {
  1405. timer = setTimeout(cssPoll, CSS_POLL_INTERVAL);
  1406. }
  1407. }
  1408. S.mix(utils, {
  1409. scriptOnload:document.addEventListener ?
  1410. function(node, callback) {
  1411. if (utils.isLinkNode(node)) {
  1412. return utils.styleOnload(node, callback);
  1413. }
  1414. node.addEventListener('load', callback, false);
  1415. } :
  1416. function(node, callback) {
  1417. if (utils.isLinkNode(node)) {
  1418. return utils.styleOnload(node, callback);
  1419. }
  1420. var oldCallback = node.onreadystatechange;
  1421. node.onreadystatechange = function() {
  1422. var rs = node.readyState;
  1423. if (/loaded|complete/i.test(rs)) {
  1424. node.onreadystatechange = null;
  1425. oldCallback && oldCallback();
  1426. callback.call(this);
  1427. }
  1428. };
  1429. },
  1430. /**
  1431. * monitor css onload across browsers
  1432. * 暂时不考虑如何判断失败,如 404 等
  1433. * @refer
  1434. * - firefox 不可行(结论4错误):
  1435. * - http://yearofmoo.com/2011/03/cross-browser-stylesheet-preloading/
  1436. * - 全浏览器兼容
  1437. * - http://lifesinger.org/lab/2011/load-js-css/css-preload.html
  1438. * - 其他
  1439. * - http://www.zachleat.com/web/load-css-dynamically/
  1440. */
  1441. styleOnload:window.attachEvent ?
  1442. // ie/opera
  1443. function(node, callback) {
  1444. // whether to detach using function wrapper?
  1445. function t() {
  1446. node.detachEvent('onload', t);
  1447. S.log('ie/opera loaded : ' + node.href);
  1448. callback.call(node);
  1449. }
  1450. node.attachEvent('onload', t);
  1451. } :
  1452. // refer : http://lifesinger.org/lab/2011/load-js-css/css-preload.html
  1453. // 暂时不考虑如何判断失败,如 404 等
  1454. function(node, callback) {
  1455. var href = node.href,arr;
  1456. arr = monitors[href] = monitors[href] || [];
  1457. arr.node = node;
  1458. arr.push(callback);
  1459. startCssTimer();
  1460. }
  1461. });
  1462. })(KISSY, KISSY.__loaderUtils);/**
  1463. * getScript support for css and js callback after load
  1464. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1465. */
  1466. (function(S, utils) {
  1467. if ("require" in this) {
  1468. return;
  1469. }
  1470. var MILLISECONDS_OF_SECOND = 1000,
  1471. scriptOnload = utils.scriptOnload;
  1472. S.mix(S, {
  1473. /**
  1474. * load a css file from server using http get ,after css file load ,execute success callback
  1475. * @param url css file url
  1476. * @param success callback
  1477. * @param charset
  1478. */
  1479. getStyle:function(url, success, charset) {
  1480. var doc = document,
  1481. head = utils.docHead(),
  1482. node = doc.createElement('link'),
  1483. config = success;
  1484. if (S.isPlainObject(config)) {
  1485. success = config.success;
  1486. charset = config.charset;
  1487. }
  1488. node.href = url;
  1489. node.rel = 'stylesheet';
  1490. if (charset) {
  1491. node.charset = charset;
  1492. }
  1493. if (success) {
  1494. utils.scriptOnload(node, success);
  1495. }
  1496. head.appendChild(node);
  1497. return node;
  1498. },
  1499. /**
  1500. * Load a JavaScript/Css file from the server using a GET HTTP request, then execute it.
  1501. * <code>
  1502. * getScript(url, success, charset);
  1503. * or
  1504. * getScript(url, {
  1505. * charset: string
  1506. * success: fn,
  1507. * error: fn,
  1508. * timeout: number
  1509. * });
  1510. * </code>
  1511. */
  1512. getScript:function(url, success, charset) {
  1513. if (utils.isCss(url)) {
  1514. return S.getStyle(url, success, charset);
  1515. }
  1516. var doc = document,
  1517. head = doc.head || doc.getElementsByTagName("head")[0],
  1518. node = doc.createElement('script'),
  1519. config = success,
  1520. error,
  1521. timeout,
  1522. timer;
  1523. if (S.isPlainObject(config)) {
  1524. success = config.success;
  1525. error = config.error;
  1526. timeout = config.timeout;
  1527. charset = config.charset;
  1528. }
  1529. function clearTimer() {
  1530. if (timer) {
  1531. timer.cancel();
  1532. timer = undefined;
  1533. }
  1534. }
  1535. node.src = url;
  1536. node.async = true;
  1537. if (charset) {
  1538. node.charset = charset;
  1539. }
  1540. if (success || error) {
  1541. scriptOnload(node, function() {
  1542. clearTimer();
  1543. S.isFunction(success) && success.call(node);
  1544. });
  1545. if (S.isFunction(error)) {
  1546. //标准浏览器
  1547. if (doc.addEventListener) {
  1548. node.addEventListener("error", function() {
  1549. clearTimer();
  1550. error.call(node);
  1551. }, false);
  1552. }
  1553. timer = S.later(function() {
  1554. timer = undefined;
  1555. error();
  1556. }, (timeout || this.Config.timeout) * MILLISECONDS_OF_SECOND);
  1557. }
  1558. }
  1559. head.insertBefore(node, head.firstChild);
  1560. return node;
  1561. }
  1562. });
  1563. })(KISSY, KISSY.__loaderUtils);/**
  1564. * add module definition
  1565. * @author yiminghe@gmail.com,lifesinger@gmail.com
  1566. */
  1567. (function(S, loader, utils, data) {
  1568. if ("require" in this) {
  1569. return;
  1570. }
  1571. var IE = utils.IE,
  1572. ATTACHED = data.ATTACHED,
  1573. mix = S.mix;
  1574. mix(loader, {
  1575. /**
  1576. * Registers a module.
  1577. * @param name {String} module name
  1578. * @param def {Function|Object} entry point into the module that is used to bind module to KISSY
  1579. * @param config {Object}
  1580. * <code>
  1581. * KISSY.add('module-name', function(S){ }, {requires: ['mod1']});
  1582. * </code>
  1583. * <code>
  1584. * KISSY.add({
  1585. * 'mod-name': {
  1586. * fullpath: 'url',
  1587. * requires: ['mod1','mod2']
  1588. * }
  1589. * });
  1590. * </code>
  1591. * @return {KISSY}
  1592. */
  1593. add: function(name, def, config) {
  1594. var self = this,
  1595. mods = self.Env.mods,
  1596. o;
  1597. // S.add(name, config) => S.add( { name: config } )
  1598. if (S.isString(name)
  1599. && !config
  1600. && S.isPlainObject(def)) {
  1601. o = {};
  1602. o[name] = def;
  1603. name = o;
  1604. }
  1605. // S.add( { name: config } )
  1606. if (S.isPlainObject(name)) {
  1607. S.each(name, function(v, k) {
  1608. v.name = k;
  1609. if (mods[k]) {
  1610. // 保留之前添加的配置
  1611. mix(v, mods[k], false);
  1612. }
  1613. });
  1614. mix(mods, name);
  1615. return self;
  1616. }
  1617. // S.add(name[, fn[, config]])
  1618. if (S.isString(name)) {
  1619. var host;
  1620. if (config && ( host = config.host )) {
  1621. var hostMod = mods[host];
  1622. if (!hostMod) {
  1623. S.log("module " + host + " can not be found !", "error");
  1624. //S.error("module " + host + " can not be found !");
  1625. return self;
  1626. }
  1627. if (self.__isAttached(host)) {
  1628. def.call(self, self);
  1629. } else {
  1630. //该 host 模块纯虚!
  1631. hostMod.fns = hostMod.fns || [];
  1632. hostMod.fns.push(def);
  1633. }
  1634. return self;
  1635. }
  1636. self.__registerModule(name, def, config);
  1637. //显示指定 add 不 attach
  1638. if (config && config['attach'] === false) {
  1639. return self;
  1640. }
  1641. // 和 1.1.7 以前版本保持兼容,不得已而为之
  1642. var mod = mods[name];
  1643. var requires = utils.normalDepModuleName(name, mod.requires);
  1644. if (self.__isAttached(requires)) {
  1645. //S.log(mod.name + " is attached when add !");
  1646. self.__attachMod(mod);
  1647. }
  1648. //调试用,为什么不在 add 时 attach
  1649. else if (this.Config.debug && !mod) {
  1650. var i,modNames;
  1651. i = (modNames = S.makeArray(requires)).length - 1;
  1652. for (; i >= 0; i--) {
  1653. var requireName = modNames[i];
  1654. var requireMod = mods[requireName] || {};
  1655. if (requireMod.status !== ATTACHED) {
  1656. S.log(mod.name + " not attached when added : depends " + requireName);
  1657. }
  1658. }
  1659. }
  1660. return self;
  1661. }
  1662. // S.add(fn,config);
  1663. if (S.isFunction(name)) {
  1664. config = def;
  1665. def = name;
  1666. if (IE) {
  1667. /*
  1668. Kris Zyp
  1669. 2010年10月21日, 上午11时34分
  1670. We actually had some discussions off-list, as it turns out the required
  1671. technique is a little different than described in this thread. Briefly,
  1672. to identify anonymous modules from scripts:
  1673. * In non-IE browsers, the onload event is sufficient, it always fires
  1674. immediately after the script is executed.
  1675. * In IE, if the script is in the cache, it actually executes *during*
  1676. the DOM insertion of the script tag, so you can keep track of which
  1677. script is being requested in case define() is called during the DOM
  1678. insertion.
  1679. * In IE, if the script is not in the cache, when define() is called you
  1680. can iterate through the script tags and the currently executing one will
  1681. have a script.readyState == "interactive"
  1682. See RequireJS source code if you need more hints.
  1683. Anyway, the bottom line from a spec perspective is that it is
  1684. implemented, it works, and it is possible. Hope that helps.
  1685. Kris
  1686. */
  1687. // http://groups.google.com/group/commonjs/browse_thread/thread/5a3358ece35e688e/43145ceccfb1dc02#43145ceccfb1dc02
  1688. // use onload to get module name is not right in ie
  1689. name = self.__findModuleNameByInteractive();
  1690. S.log("old_ie get modname by interactive : " + name);
  1691. self.__registerModule(name, def, config);
  1692. self.__startLoadModuleName = null;
  1693. self.__startLoadTime = 0;
  1694. } else {
  1695. // 其他浏览器 onload 时,关联模块名与模块定义
  1696. self.__currentModule = {
  1697. def:def,
  1698. config:config
  1699. };
  1700. }
  1701. return self;
  1702. }
  1703. S.log("invalid format for KISSY.add !", "error");
  1704. return self;
  1705. }
  1706. });
  1707. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);
  1708. /**
  1709. * @refer
  1710. * - https://github.com/amdjs/amdjs-api/wiki/AMD
  1711. **//**
  1712. * build full path from relative path and base path
  1713. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1714. */
  1715. (function (S, loader, utils, data) {
  1716. if ("require" in this) {
  1717. return;
  1718. }
  1719. S.mix(loader, {
  1720. __buildPath:function (mod, base) {
  1721. var self = this,
  1722. Config = self.Config;
  1723. base = base || Config.base;
  1724. build("fullpath", "path");
  1725. if (mod["cssfullpath"] !== data.LOADED) {
  1726. build("cssfullpath", "csspath");
  1727. }
  1728. function build(fullpath, path) {
  1729. if (!mod[fullpath] && mod[path]) {
  1730. //如果是 ./ 或 ../ 则相对当前模块路径
  1731. mod[path] = utils.normalDepModuleName(mod.name, mod[path]);
  1732. mod[fullpath] = base + mod[path];
  1733. }
  1734. // debug 模式下,加载非 min 版
  1735. if (mod[fullpath] && Config.debug) {
  1736. mod[fullpath] = mod[fullpath].replace(/-min/ig, "");
  1737. }
  1738. //刷新客户端缓存,加时间戳 tag
  1739. if (mod[fullpath]
  1740. && !(mod[fullpath].match(/\?t=/))
  1741. && mod.tag) {
  1742. mod[fullpath] += "?t=" + mod.tag;
  1743. }
  1744. if (mod[fullpath]) {
  1745. mod[fullpath] = self.__getMappedPath(mod[fullpath]);
  1746. }
  1747. }
  1748. }
  1749. });
  1750. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  1751. * logic for config.global , mainly for kissy.editor
  1752. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1753. */
  1754. (function(S, loader) {
  1755. if ("require" in this) {
  1756. return;
  1757. }
  1758. S.mix(loader, {
  1759. // 按需从 global 迁移模块定义到当前 loader 实例,并根据 global 设置 fullpath
  1760. __mixMod: function(name, global) {
  1761. // 从 __mixMods 调用过来时,可能本实例没有该模块的数据结构
  1762. var self = this,
  1763. mods = self.Env.mods,
  1764. gMods = global.Env.mods,
  1765. mod = mods[name] || {},
  1766. status = mod.status;
  1767. if (gMods[name]) {
  1768. S.mix(mod, S.clone(gMods[name]));
  1769. // status 属于实例,当有值时,不能被覆盖。
  1770. // 1. 只有没有初始值时,才从 global 上继承
  1771. // 2. 初始值为 0 时,也从 global 上继承
  1772. // 其他都保存自己的状态
  1773. if (status) {
  1774. mod.status = status;
  1775. }
  1776. }
  1777. // 来自 global 的 mod, path 也应该基于 global
  1778. self.__buildPath(mod, global.Config.base);
  1779. mods[name] = mod;
  1780. }
  1781. });
  1782. })(KISSY, KISSY.__loader);/**
  1783. * for ie ,find current executive script ,then infer module name
  1784. * @author yiminghe@gmail.com
  1785. */
  1786. (function (S, loader, utils) {
  1787. if ("require" in this) {
  1788. return;
  1789. }
  1790. S.mix(loader, {
  1791. //ie 特有,找到当前正在交互的脚本,根据脚本名确定模块名
  1792. // 如果找不到,返回发送前那个脚本
  1793. __findModuleNameByInteractive:function () {
  1794. var self = this,
  1795. scripts = document.getElementsByTagName("script"),
  1796. re,
  1797. script;
  1798. for (var i = 0; i < scripts.length; i++) {
  1799. script = scripts[i];
  1800. if (script.readyState == "interactive") {
  1801. re = script;
  1802. break;
  1803. }
  1804. }
  1805. if (!re) {
  1806. // sometimes when read module file from cache , interactive status is not triggered
  1807. // module code is executed right after inserting into dom
  1808. // i has to preserve module name before insert module script into dom , then get it back here
  1809. S.log("can not find interactive script,time diff : " + (+new Date() - self.__startLoadTime), "error");
  1810. S.log("old_ie get modname from cache : " + self.__startLoadModuleName);
  1811. return self.__startLoadModuleName;
  1812. //S.error("找不到 interactive 状态的 script");
  1813. }
  1814. // src 必定是绝对路径
  1815. // or re.hasAttribute ? re.src : re.getAttribute('src', 4);
  1816. // http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx
  1817. var src = utils.absoluteFilePath(re.src);
  1818. // S.log("interactive src :" + src);
  1819. // 注意:模块名不包含后缀名以及参数,所以去除
  1820. // 系统模块去除系统路径
  1821. // 需要 base norm , 防止 base 被指定为相对路径
  1822. self.Config.base = utils.normalBasePath(self.Config.base);
  1823. if (src.lastIndexOf(self.Config.base, 0)
  1824. === 0) {
  1825. return utils.removePostfix(src.substring(self.Config.base.length));
  1826. }
  1827. var packages = self.Config.packages;
  1828. //外部模块去除包路径,得到模块名
  1829. for (var p in packages) {
  1830. if (packages.hasOwnProperty(p)) {
  1831. var p_path = packages[p].path;
  1832. if (packages.hasOwnProperty(p) &&
  1833. src.lastIndexOf(p_path, 0) === 0) {
  1834. return utils.removePostfix(src.substring(p_path.length));
  1835. }
  1836. }
  1837. }
  1838. S.log("interactive script does not have package config :" + src, "error");
  1839. }
  1840. });
  1841. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  1842. * load a single mod (js or css)
  1843. * @author lifesinger@gmail.com,yiminghe@gmail.com
  1844. */
  1845. (function(S, loader, utils, data) {
  1846. if ("require" in this) {
  1847. return;
  1848. }
  1849. var IE = utils.IE,
  1850. LOADING = data.LOADING,
  1851. LOADED = data.LOADED,
  1852. ERROR = data.ERROR,
  1853. ATTACHED = data.ATTACHED;
  1854. S.mix(loader, {
  1855. /**
  1856. * Load a single module.
  1857. */
  1858. __load: function(mod, callback, cfg) {
  1859. var self = this,
  1860. url = mod['fullpath'],
  1861. isCss = utils.isCss(url),
  1862. // 这个是全局的,防止多实例对同一模块的重复下载
  1863. loadQueque = S.Env._loadQueue,
  1864. status = loadQueque[url],
  1865. node = status;
  1866. mod.status = mod.status || 0;
  1867. // 可能已经由其它模块触发加载
  1868. if (mod.status < LOADING && status) {
  1869. // 该模块是否已经载入到 global ?
  1870. mod.status = status === LOADED ? LOADED : LOADING;
  1871. }
  1872. // 1.20 兼容 1.1x 处理:加载 cssfullpath 配置的 css 文件
  1873. // 仅发出请求,不做任何其它处理
  1874. if (S.isString(mod["cssfullpath"])) {
  1875. S.getScript(mod["cssfullpath"]);
  1876. mod["cssfullpath"] = mod.csspath = LOADED;
  1877. }
  1878. if (mod.status < LOADING && url) {
  1879. mod.status = LOADING;
  1880. if (IE && !isCss) {
  1881. self.__startLoadModuleName = mod.name;
  1882. self.__startLoadTime = Number(+new Date());
  1883. }
  1884. node = S.getScript(url, {
  1885. success: function() {
  1886. if (isCss) {
  1887. } else {
  1888. //载入 css 不需要这步了
  1889. //标准浏览器下:外部脚本执行后立即触发该脚本的 load 事件,ie9 还是不行
  1890. if (self.__currentModule) {
  1891. S.log("standard browser get modname after load : " + mod.name);
  1892. self.__registerModule(mod.name, self.__currentModule.def,
  1893. self.__currentModule.config);
  1894. self.__currentModule = null;
  1895. }
  1896. // 模块载入后,如果需要也要混入对应 global 上模块定义
  1897. mixGlobal();
  1898. if (mod.fns && mod.fns.length > 0) {
  1899. } else {
  1900. _modError();
  1901. }
  1902. }
  1903. if (mod.status != ERROR) {
  1904. S.log(mod.name + ' is loaded.', 'info');
  1905. }
  1906. _scriptOnComplete();
  1907. },
  1908. error: function() {
  1909. _modError();
  1910. _scriptOnComplete();
  1911. },
  1912. charset: mod.charset
  1913. });
  1914. loadQueque[url] = node;
  1915. }
  1916. // 已经在加载中,需要添加回调到 script onload 中
  1917. // 注意:没有考虑 error 情形
  1918. else if (mod.status === LOADING) {
  1919. utils.scriptOnload(node, function() {
  1920. // 模块载入后,如果需要也要混入对应 global 上模块定义
  1921. mixGlobal();
  1922. _scriptOnComplete();
  1923. });
  1924. }
  1925. // 是内嵌代码,或者已经 loaded
  1926. else {
  1927. // 也要混入对应 global 上模块定义
  1928. mixGlobal();
  1929. callback();
  1930. }
  1931. function _modError() {
  1932. S.log(mod.name + ' is not loaded! can not find module in path : ' + mod['fullpath'], 'error');
  1933. mod.status = ERROR;
  1934. }
  1935. function mixGlobal() {
  1936. // 对于动态下载下来的模块,loaded 后,global 上有可能更新 mods 信息
  1937. // 需要同步到 instance 上去
  1938. // 注意:要求 mod 对应的文件里,仅修改该 mod 信息
  1939. if (cfg.global) {
  1940. self.__mixMod(mod.name, cfg.global);
  1941. }
  1942. }
  1943. function _scriptOnComplete() {
  1944. loadQueque[url] = LOADED;
  1945. if (mod.status !== ERROR) {
  1946. // 注意:当多个模块依赖同一个下载中的模块A下,模块A仅需 attach 一次
  1947. // 因此要加上下面的 !== 判断,否则会出现重复 attach,
  1948. // 比如编辑器里动态加载时,被依赖的模块会重复
  1949. if (mod.status !== ATTACHED) {
  1950. mod.status = LOADED;
  1951. }
  1952. callback();
  1953. }
  1954. }
  1955. }
  1956. });
  1957. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  1958. * @module loader
  1959. * @author lifesinger@gmail.com,yiminghe@gmail.com,lijing00333@163.com
  1960. * @description: constant member and common method holder
  1961. */
  1962. (function(S, loader, data) {
  1963. if ("require" in this) {
  1964. return;
  1965. }
  1966. var ATTACHED = data.ATTACHED,
  1967. mix = S.mix;
  1968. mix(loader, {
  1969. // 当前页面所在的目录
  1970. // http://xx.com/y/z.htm#!/f/g
  1971. // ->
  1972. // http://xx.com/y/
  1973. __pagePath:location.href.replace(location.hash, "").replace(/[^/]*$/i, ""),
  1974. //firefox,ie9,chrome 如果add没有模块名,模块定义先暂存这里
  1975. __currentModule:null,
  1976. //ie6,7,8开始载入脚本的时间
  1977. __startLoadTime:0,
  1978. //ie6,7,8开始载入脚本对应的模块名
  1979. __startLoadModuleName:null,
  1980. __isAttached: function(modNames) {
  1981. var mods = this.Env.mods,
  1982. ret = true;
  1983. S.each(modNames, function(name) {
  1984. var mod = mods[name];
  1985. if (!mod || mod.status !== ATTACHED) {
  1986. ret = false;
  1987. return ret;
  1988. }
  1989. });
  1990. return ret;
  1991. }
  1992. });
  1993. })(KISSY, KISSY.__loader, KISSY.__loaderData);
  1994. /**
  1995. * 2011-01-04 chengyu<yiminghe@gmail.com> refactor:
  1996. *
  1997. * adopt requirejs :
  1998. *
  1999. * 1. packages(cfg) , cfg :{
  2000. * name : 包名,用于指定业务模块前缀
  2001. * path: 前缀包名对应的路径
  2002. * charset: 该包下所有文件的编码
  2003. *
  2004. * 2. add(moduleName,function(S,depModule){return function(){}},{requires:["depModuleName"]});
  2005. * moduleName add 时可以不写
  2006. * depModuleName 可以写相对地址 (./ , ../),相对于 moduleName
  2007. *
  2008. * 3. S.use(["dom"],function(S,DOM){
  2009. * });
  2010. * 依赖注入,发生于 add 和 use 时期
  2011. *
  2012. * 4. add,use 不支持 css loader ,getScript 仍然保留支持
  2013. *
  2014. * 5. 部分更新模块文件代码 x/y?t=2011 ,加载过程中注意去除事件戳,仅在载入文件时使用
  2015. *
  2016. * demo : http://lite-ext.googlecode.com/svn/trunk/lite-ext/playground/module_package/index.html
  2017. *
  2018. * 2011-03-01 yiminghe@gmail.com note:
  2019. *
  2020. * compatibility
  2021. *
  2022. * 1. 保持兼容性,不得已而为之
  2023. * 支持 { host : }
  2024. * 如果 requires 都已经 attached,支持 add 后立即 attach
  2025. * 支持 { attach : false } 显示控制 add 时是否 attach
  2026. * 支持 { global : Editor } 指明模块来源
  2027. *
  2028. *
  2029. * 2011-05-04 初步拆分文件,tmd 乱了
  2030. */
  2031. /**
  2032. * package mechanism
  2033. * @author yiminghe@gmail.com
  2034. */
  2035. (function (S, loader, utils) {
  2036. if ("require" in this) {
  2037. return;
  2038. }
  2039. /**
  2040. * 包声明
  2041. * biz -> .
  2042. * 表示遇到 biz/x
  2043. * 在当前网页路径找 biz/x.js
  2044. */
  2045. S.configs.packages = function (cfgs) {
  2046. var ps;
  2047. ps = S.Config.packages = S.Config.packages || {};
  2048. S.each(cfgs, function (cfg) {
  2049. ps[cfg.name] = cfg;
  2050. //注意正则化
  2051. cfg.path = cfg.path && utils.normalBasePath(cfg.path);
  2052. cfg.tag = cfg.tag && encodeURIComponent(cfg.tag);
  2053. });
  2054. };
  2055. S.mix(loader, {
  2056. __getPackagePath:function (mod) {
  2057. //缓存包路径,未申明的包的模块都到核心模块中找
  2058. if (mod.packagepath) {
  2059. return mod.packagepath;
  2060. }
  2061. var self = this,
  2062. //一个模块合并到了另一个模块文件中去
  2063. modName = S.__getCombinedMod(mod.name),
  2064. packages = self.Config.packages || {},
  2065. pName = "",
  2066. p_def;
  2067. for (var p in packages) {
  2068. if (packages.hasOwnProperty(p)) {
  2069. if (S.startsWith(modName, p) &&
  2070. p.length > pName) {
  2071. pName = p;
  2072. }
  2073. }
  2074. }
  2075. p_def = packages[pName];
  2076. mod.charset = p_def && p_def.charset || mod.charset;
  2077. if (p_def) {
  2078. mod.tag = p_def.tag;
  2079. } else {
  2080. // kissy 自身组件的事件戳后缀
  2081. mod.tag = encodeURIComponent(S.Config.tag || S.buildTime);
  2082. }
  2083. return mod.packagepath = (p_def && p_def.path) || self.Config.base;
  2084. }
  2085. });
  2086. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  2087. * register module ,associate module name with module factory(definition)
  2088. * @author yiminghe@gmail.com,lifesinger@gmail.com
  2089. */
  2090. (function(S, loader,data) {
  2091. if ("require" in this) {
  2092. return;
  2093. }
  2094. var LOADED = data.LOADED,
  2095. mix = S.mix;
  2096. mix(loader, {
  2097. //注册模块,将模块和定义 factory 关联起来
  2098. __registerModule:function(name, def, config) {
  2099. config = config || {};
  2100. var self = this,
  2101. mods = self.Env.mods,
  2102. mod = mods[name] || {};
  2103. // 注意:通过 S.add(name[, fn[, config]]) 注册的代码,无论是页面中的代码,
  2104. // 还是 js 文件里的代码,add 执行时,都意味着该模块已经 LOADED
  2105. mix(mod, { name: name, status: LOADED });
  2106. if (mod.fns && mod.fns.length) {
  2107. S.log(name + " is defined more than once");
  2108. //S.error(name + " is defined more than once");
  2109. }
  2110. //支持 host,一个模块多个 add factory
  2111. mod.fns = mod.fns || [];
  2112. mod.fns.push(def);
  2113. mix((mods[name] = mod), config);
  2114. }
  2115. });
  2116. })(KISSY, KISSY.__loader, KISSY.__loaderData);/**
  2117. * use and attach mod
  2118. * @author yiminghe@gmail.com,lifesinger@gmail.com
  2119. */
  2120. (function (S, loader, utils, data) {
  2121. if ("require" in this) {
  2122. return;
  2123. }
  2124. var LOADED = data.LOADED,
  2125. ATTACHED = data.ATTACHED;
  2126. S.mix(loader, {
  2127. /**
  2128. * Start load specific mods, and fire callback when these mods and requires are attached.
  2129. * <code>
  2130. * S.use('mod-name', callback, config);
  2131. * S.use('mod1,mod2', callback, config);
  2132. * </code>
  2133. */
  2134. use:function (modNames, callback, cfg) {
  2135. modNames = modNames.replace(/\s+/g, "").split(',');
  2136. utils.indexMapping(modNames);
  2137. cfg = cfg || {};
  2138. var self = this,
  2139. fired;
  2140. // 已经全部 attached, 直接执行回调即可
  2141. if (self.__isAttached(modNames)) {
  2142. var mods = self.__getModules(modNames);
  2143. callback && callback.apply(self, mods);
  2144. return;
  2145. }
  2146. // 有尚未 attached 的模块
  2147. S.each(modNames, function (modName) {
  2148. // 从 name 开始调用,防止不存在模块
  2149. self.__attachModByName(modName, function () {
  2150. if (!fired &&
  2151. self.__isAttached(modNames)) {
  2152. fired = true;
  2153. var mods = self.__getModules(modNames);
  2154. callback && callback.apply(self, mods);
  2155. }
  2156. }, cfg);
  2157. });
  2158. return self;
  2159. },
  2160. __getModules:function (modNames) {
  2161. var self = this,
  2162. mods = [self];
  2163. S.each(modNames, function (modName) {
  2164. if (!utils.isCss(modName)) {
  2165. mods.push(self.require(modName));
  2166. }
  2167. });
  2168. return mods;
  2169. },
  2170. /**
  2171. * get module's value defined by define function
  2172. * @param {string} moduleName
  2173. */
  2174. require:function (moduleName) {
  2175. var self = this,
  2176. mods = self.Env.mods,
  2177. mod = mods[moduleName],
  2178. re = self['onRequire'] && self['onRequire'](mod);
  2179. if (re !== undefined) {
  2180. return re;
  2181. }
  2182. return mod && mod.value;
  2183. },
  2184. // 加载指定模块名模块,如果不存在定义默认定义为内部模块
  2185. __attachModByName:function (modName, callback, cfg) {
  2186. var self = this,
  2187. mods = self.Env.mods;
  2188. var mod = mods[modName];
  2189. //没有模块定义
  2190. if (!mod) {
  2191. // 默认 js/css 名字
  2192. // 不指定 .js 默认为 js
  2193. // 指定为 css 载入 .css
  2194. var componentJsName = self.Config['componentJsName'] ||
  2195. function (m) {
  2196. var suffix = "js", match;
  2197. if (match = m.match(/(.+)\.(js|css)$/i)) {
  2198. suffix = match[2];
  2199. m = match[1];
  2200. }
  2201. return m + '-min.' + suffix;
  2202. },
  2203. path = componentJsName(S.__getCombinedMod(modName));
  2204. mod = {
  2205. path:path,
  2206. charset:'utf-8'
  2207. };
  2208. //添加模块定义
  2209. mods[modName] = mod;
  2210. }
  2211. mod.name = modName;
  2212. if (mod && mod.status === ATTACHED) {
  2213. return;
  2214. }
  2215. // 先从 global 里取
  2216. if (cfg.global) {
  2217. self.__mixMod(modName, cfg.global);
  2218. }
  2219. self.__attach(mod, callback, cfg);
  2220. },
  2221. /**
  2222. * Attach a module and all required modules.
  2223. */
  2224. __attach:function (mod, callback, cfg) {
  2225. var self = this,
  2226. r,
  2227. rMod,
  2228. i,
  2229. attached = 0,
  2230. mods = self.Env.mods,
  2231. //复制一份当前的依赖项出来,防止 add 后修改!
  2232. requires = (mod['requires'] || []).concat();
  2233. mod['requires'] = requires;
  2234. /**
  2235. * check cyclic dependency between mods
  2236. */
  2237. function cyclicCheck() {
  2238. var __allRequires,
  2239. myName = mod.name,
  2240. r, r2, rmod,
  2241. r__allRequires,
  2242. requires = mod.requires;
  2243. // one mod's all requires mods to run its callback
  2244. __allRequires = mod.__allRequires = mod.__allRequires || {};
  2245. for (var i = 0; i < requires.length; i++) {
  2246. r = requires[i];
  2247. rmod = mods[r];
  2248. __allRequires[r] = 1;
  2249. if (rmod && (r__allRequires = rmod.__allRequires)) {
  2250. for (r2 in r__allRequires) {
  2251. if (r__allRequires.hasOwnProperty(r2)) {
  2252. __allRequires[r2] = 1;
  2253. }
  2254. }
  2255. }
  2256. }
  2257. if (__allRequires[myName]) {
  2258. var t = [];
  2259. for (r in __allRequires) {
  2260. if (__allRequires.hasOwnProperty(r)) {
  2261. t.push(r);
  2262. }
  2263. }
  2264. S.error("find cyclic dependency by mod " + myName + " between mods : " + t.join(","));
  2265. }
  2266. }
  2267. if (S.Config.debug) {
  2268. cyclicCheck();
  2269. }
  2270. // attach all required modules
  2271. for (i = 0; i < requires.length; i++) {
  2272. r = requires[i] = utils.normalDepModuleName(mod.name, requires[i]);
  2273. rMod = mods[r];
  2274. if (rMod && rMod.status === ATTACHED) {
  2275. //no need
  2276. } else {
  2277. self.__attachModByName(r, fn, cfg);
  2278. }
  2279. }
  2280. // load and attach this module
  2281. self.__buildPath(mod, self.__getPackagePath(mod));
  2282. self.__load(mod, function () {
  2283. // add 可能改了 config,这里重新取下
  2284. mod['requires'] = mod['requires'] || [];
  2285. var newRequires = mod['requires'],
  2286. needToLoad = [];
  2287. //本模块下载成功后串行下载 require
  2288. for (i = 0; i < newRequires.length; i++) {
  2289. r = newRequires[i] = utils.normalDepModuleName(mod.name, newRequires[i]);
  2290. var rMod = mods[r],
  2291. inA = S.inArray(r, requires);
  2292. //已经处理过了或将要处理
  2293. if (rMod &&
  2294. rMod.status === ATTACHED
  2295. //已经正在处理了
  2296. || inA) {
  2297. //no need
  2298. } else {
  2299. //新增的依赖项
  2300. needToLoad.push(r);
  2301. }
  2302. }
  2303. if (needToLoad.length) {
  2304. for (i = 0; i < needToLoad.length; i++) {
  2305. self.__attachModByName(needToLoad[i], fn, cfg);
  2306. }
  2307. } else {
  2308. fn();
  2309. }
  2310. }, cfg);
  2311. function fn() {
  2312. if (!attached &&
  2313. self.__isAttached(mod['requires'])) {
  2314. if (mod.status === LOADED) {
  2315. self.__attachMod(mod);
  2316. }
  2317. if (mod.status === ATTACHED) {
  2318. attached = 1;
  2319. callback();
  2320. }
  2321. }
  2322. }
  2323. },
  2324. __attachMod:function (mod) {
  2325. var self = this,
  2326. fns = mod.fns;
  2327. if (fns) {
  2328. S.each(fns, function (fn) {
  2329. var value;
  2330. if (S.isFunction(fn)) {
  2331. value = fn.apply(self, self.__getModules(mod['requires']));
  2332. } else {
  2333. value = fn;
  2334. }
  2335. mod.value = mod.value || value;
  2336. });
  2337. }
  2338. mod.status = ATTACHED;
  2339. }
  2340. });
  2341. })(KISSY, KISSY.__loader, KISSY.__loaderUtils, KISSY.__loaderData);/**
  2342. * mix loader into S and infer KISSy baseUrl if not set
  2343. * @author lifesinger@gmail.com,yiminghe@gmail.com
  2344. */
  2345. (function (S, loader, utils) {
  2346. if ("require" in this) {
  2347. return;
  2348. }
  2349. S.mix(S, loader);
  2350. /**
  2351. * get base from src
  2352. * @param src script source url
  2353. * @return base for kissy
  2354. * @example:
  2355. * http://a.tbcdn.cn/s/kissy/1.1.6/??kissy-min.js,suggest/suggest-pkg-min.js
  2356. * http://a.tbcdn.cn/??s/kissy/1.1.6/kissy-min.js,s/kissy/1.1.5/suggest/suggest-pkg-min.js
  2357. * http://a.tbcdn.cn/??s/kissy/1.1.6/suggest/suggest-pkg-min.js,s/kissy/1.1.5/kissy-min.js
  2358. * http://a.tbcdn.cn/s/kissy/1.1.6/kissy-min.js?t=20101215.js
  2359. * @notice: custom combo rules, such as yui3:
  2360. * <script src="path/to/kissy" data-combo-prefix="combo?" data-combo-sep="&"></script>
  2361. */
  2362. // notice: timestamp
  2363. var baseReg = /^(.*)(seed|kissy)(-aio)?(-min)?\.js[^/]*/i,
  2364. baseTestReg = /(seed|kissy)(-aio)?(-min)?\.js/i;
  2365. function getBaseUrl(script) {
  2366. var src = utils.absoluteFilePath(script.src),
  2367. prefix = script.getAttribute('data-combo-prefix') || '??',
  2368. sep = script.getAttribute('data-combo-sep') || ',',
  2369. parts = src.split(sep),
  2370. base,
  2371. part0 = parts[0],
  2372. index = part0.indexOf(prefix);
  2373. // no combo
  2374. if (index == -1) {
  2375. base = src.replace(baseReg, '$1');
  2376. } else {
  2377. base = part0.substring(0, index);
  2378. var part01 = part0.substring(index + 2, part0.length);
  2379. // combo first
  2380. // notice use match better than test
  2381. if (part01.match(baseTestReg)) {
  2382. base += part01.replace(baseReg, '$1');
  2383. }
  2384. // combo after first
  2385. else {
  2386. S.each(parts, function (part) {
  2387. if (part.match(baseTestReg)) {
  2388. base += part.replace(baseReg, '$1');
  2389. return false;
  2390. }
  2391. });
  2392. }
  2393. }
  2394. return base;
  2395. }
  2396. /**
  2397. * Initializes loader.
  2398. */
  2399. S.__initLoader = function () {
  2400. var self = this;
  2401. self.Env.mods = self.Env.mods || {}; // all added mods
  2402. };
  2403. S.Env._loadQueue = {}; // information for loading and loaded mods
  2404. S.__initLoader();
  2405. (function () {
  2406. // get base from current script file path
  2407. var scripts = document.getElementsByTagName('script'),
  2408. currentScript = scripts[scripts.length - 1],
  2409. base = getBaseUrl(currentScript);
  2410. S.Config.base = utils.normalBasePath(base);
  2411. // the default timeout for getScript
  2412. S.Config.timeout = 10;
  2413. })();
  2414. S.mix(S.configs, {
  2415. base:function (base) {
  2416. S.Config.base = utils.normalBasePath(base);
  2417. },
  2418. timeout:function (v) {
  2419. S.Config.timeout = v;
  2420. },
  2421. debug:function (v) {
  2422. S.Config.debug = v;
  2423. }
  2424. });
  2425. // for S.app working properly
  2426. S.each(loader, function (v, k) {
  2427. S.__APP_MEMBERS.push(k);
  2428. });
  2429. S.__APP_INIT_METHODS.push('__initLoader');
  2430. })(KISSY, KISSY.__loader, KISSY.__loaderUtils);/**
  2431. * @module web.js
  2432. * @author lifesinger@gmail.com,yiminghe@gmail.com
  2433. * @description this code can only run at browser environment
  2434. */
  2435. (function(S, undefined) {
  2436. var win = S.__HOST,
  2437. doc = win['document'],
  2438. docElem = doc.documentElement,
  2439. EMPTY = '',
  2440. // Is the DOM ready to be used? Set to true once it occurs.
  2441. isReady = false,
  2442. // The functions to execute on DOM ready.
  2443. readyList = [],
  2444. // The number of poll times.
  2445. POLL_RETRYS = 500,
  2446. // The poll interval in milliseconds.
  2447. POLL_INTERVAL = 40,
  2448. // #id or id
  2449. RE_IDSTR = /^#?([\w-]+)$/,
  2450. RE_NOT_WHITE = /\S/;
  2451. S.mix(S, {
  2452. /**
  2453. * A crude way of determining if an object is a window
  2454. */
  2455. isWindow: function(o) {
  2456. return S.type(o) === 'object'
  2457. && 'setInterval' in o
  2458. && 'document' in o
  2459. && o.document.nodeType == 9;
  2460. },
  2461. parseXML: function(data) {
  2462. var xml;
  2463. try {
  2464. // Standard
  2465. if (window.DOMParser) {
  2466. xml = new DOMParser().parseFromString(data, "text/xml");
  2467. } else { // IE
  2468. xml = new ActiveXObject("Microsoft.XMLDOM");
  2469. xml.async = "false";
  2470. xml.loadXML(data);
  2471. }
  2472. } catch(e) {
  2473. S.log("parseXML error : ");
  2474. S.log(e);
  2475. xml = undefined;
  2476. }
  2477. if (!xml || !xml.documentElement || xml.getElementsByTagName("parsererror").length) {
  2478. S.error("Invalid XML: " + data);
  2479. }
  2480. return xml;
  2481. },
  2482. /**
  2483. * Evalulates a script in a global context.
  2484. */
  2485. globalEval: function(data) {
  2486. if (data && RE_NOT_WHITE.test(data)) {
  2487. // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
  2488. ( window.execScript || function(data) {
  2489. window[ "eval" ].call(window, data);
  2490. } )(data);
  2491. }
  2492. },
  2493. /**
  2494. * Specify a function to execute when the DOM is fully loaded.
  2495. * @param fn {Function} A function to execute after the DOM is ready
  2496. * <code>
  2497. * KISSY.ready(function(S){ });
  2498. * </code>
  2499. * @return {KISSY}
  2500. */
  2501. ready: function(fn) {
  2502. // If the DOM is already ready
  2503. if (isReady) {
  2504. // Execute the function immediately
  2505. fn.call(win, this);
  2506. } else {
  2507. // Remember the function for later
  2508. readyList.push(fn);
  2509. }
  2510. return this;
  2511. },
  2512. /**
  2513. * Executes the supplied callback when the item with the supplied id is found.
  2514. * @param id <String> The id of the element, or an array of ids to look for.
  2515. * @param fn <Function> What to execute when the element is found.
  2516. */
  2517. available: function(id, fn) {
  2518. id = (id + EMPTY).match(RE_IDSTR)[1];
  2519. if (!id || !S.isFunction(fn)) {
  2520. return;
  2521. }
  2522. var retryCount = 1,
  2523. node,
  2524. timer = S.later(function() {
  2525. if ((node = doc.getElementById(id)) && (fn(node) || 1) ||
  2526. ++retryCount > POLL_RETRYS) {
  2527. timer.cancel();
  2528. }
  2529. }, POLL_INTERVAL, true);
  2530. }
  2531. });
  2532. /**
  2533. * Binds ready events.
  2534. */
  2535. function _bindReady() {
  2536. var doScroll = docElem.doScroll,
  2537. eventType = doScroll ? 'onreadystatechange' : 'DOMContentLoaded',
  2538. COMPLETE = 'complete',
  2539. fire = function() {
  2540. _fireReady();
  2541. };
  2542. // Catch cases where ready() is called after the
  2543. // browser event has already occurred.
  2544. if (doc.readyState === COMPLETE) {
  2545. return fire();
  2546. }
  2547. // w3c mode
  2548. if (doc.addEventListener) {
  2549. function domReady() {
  2550. doc.removeEventListener(eventType, domReady, false);
  2551. fire();
  2552. }
  2553. doc.addEventListener(eventType, domReady, false);
  2554. // A fallback to window.onload, that will always work
  2555. win.addEventListener('load', fire, false);
  2556. }
  2557. // IE event model is used
  2558. else {
  2559. function stateChange() {
  2560. if (doc.readyState === COMPLETE) {
  2561. doc.detachEvent(eventType, stateChange);
  2562. fire();
  2563. }
  2564. }
  2565. // ensure firing before onload, maybe late but safe also for iframes
  2566. doc.attachEvent(eventType, stateChange);
  2567. // A fallback to window.onload, that will always work.
  2568. win.attachEvent('onload', fire);
  2569. // If IE and not a frame
  2570. // continually check to see if the document is ready
  2571. var notframe = false;
  2572. try {
  2573. notframe = (win['frameElement'] === null);
  2574. } catch(e) {
  2575. S.log("frameElement error : ");
  2576. S.log(e);
  2577. }
  2578. if (doScroll && notframe) {
  2579. function readyScroll() {
  2580. try {
  2581. // Ref: http://javascript.nwbox.com/IEContentLoaded/
  2582. doScroll('left');
  2583. fire();
  2584. } catch(ex) {
  2585. //S.log("detect document ready : " + ex);
  2586. setTimeout(readyScroll, POLL_INTERVAL);
  2587. }
  2588. }
  2589. readyScroll();
  2590. }
  2591. }
  2592. return 0;
  2593. }
  2594. /**
  2595. * Executes functions bound to ready event.
  2596. */
  2597. function _fireReady() {
  2598. if (isReady) {
  2599. return;
  2600. }
  2601. // Remember that the DOM is ready
  2602. isReady = true;
  2603. // If there are functions bound, to execute
  2604. if (readyList) {
  2605. // Execute all of them
  2606. var fn, i = 0;
  2607. while (fn = readyList[i++]) {
  2608. fn.call(win, S);
  2609. }
  2610. // Reset the list of functions
  2611. readyList = null;
  2612. }
  2613. }
  2614. // If url contains '?ks-debug', debug mode will turn on automatically.
  2615. if (location && (location.search || EMPTY).indexOf('ks-debug') !== -1) {
  2616. S.Config.debug = true;
  2617. }
  2618. /**
  2619. * bind on start
  2620. * in case when you bind but the DOMContentLoaded has triggered
  2621. * then you has to wait onload
  2622. * worst case no callback at all
  2623. */
  2624. _bindReady();
  2625. })(KISSY, undefined);
  2626. /**
  2627. * 声明 kissy 核心中所包含的模块,动态加载时将直接从 core.js 中加载核心模块
  2628. * @description: 为了和 1.1.7 及以前版本保持兼容,务实与创新,兼容与革新 !
  2629. * @author yiminghe@gmail.com
  2630. */
  2631. (function (S) {
  2632. S.config({
  2633. 'combines':{
  2634. 'core':['dom', 'ua', 'event', 'node', 'json', 'ajax', 'anim', 'base', 'cookie']
  2635. }
  2636. });
  2637. })(KISSY);
  2638. /**
  2639. combined files :
  2640. D:\code\kissy_git\kissy1.2\src\ua\base.js
  2641. D:\code\kissy_git\kissy1.2\src\ua\extra.js
  2642. D:\code\kissy_git\kissy1.2\src\ua.js
  2643. D:\code\kissy_git\kissy1.2\src\dom\base.js
  2644. D:\code\kissy_git\kissy1.2\src\dom\attr.js
  2645. D:\code\kissy_git\kissy1.2\src\dom\class.js
  2646. D:\code\kissy_git\kissy1.2\src\dom\create.js
  2647. D:\code\kissy_git\kissy1.2\src\dom\data.js
  2648. D:\code\kissy_git\kissy1.2\src\dom\insertion.js
  2649. D:\code\kissy_git\kissy1.2\src\dom\offset.js
  2650. D:\code\kissy_git\kissy1.2\src\dom\style.js
  2651. D:\code\kissy_git\kissy1.2\src\dom\selector.js
  2652. D:\code\kissy_git\kissy1.2\src\dom\style-ie.js
  2653. D:\code\kissy_git\kissy1.2\src\dom\traversal.js
  2654. D:\code\kissy_git\kissy1.2\src\dom.js
  2655. D:\code\kissy_git\kissy1.2\src\event\keycodes.js
  2656. D:\code\kissy_git\kissy1.2\src\event\object.js
  2657. D:\code\kissy_git\kissy1.2\src\event\utils.js
  2658. D:\code\kissy_git\kissy1.2\src\event\base.js
  2659. D:\code\kissy_git\kissy1.2\src\event\target.js
  2660. D:\code\kissy_git\kissy1.2\src\event\focusin.js
  2661. D:\code\kissy_git\kissy1.2\src\event\hashchange.js
  2662. D:\code\kissy_git\kissy1.2\src\event\valuechange.js
  2663. D:\code\kissy_git\kissy1.2\src\event\delegate.js
  2664. D:\code\kissy_git\kissy1.2\src\event\mouseenter.js
  2665. D:\code\kissy_git\kissy1.2\src\event\submit.js
  2666. D:\code\kissy_git\kissy1.2\src\event\change.js
  2667. D:\code\kissy_git\kissy1.2\src\event\mousewheel.js
  2668. D:\code\kissy_git\kissy1.2\src\event.js
  2669. D:\code\kissy_git\kissy1.2\src\node\base.js
  2670. D:\code\kissy_git\kissy1.2\src\node\attach.js
  2671. D:\code\kissy_git\kissy1.2\src\node\override.js
  2672. D:\code\kissy_git\kissy1.2\src\anim\easing.js
  2673. D:\code\kissy_git\kissy1.2\src\anim\manager.js
  2674. D:\code\kissy_git\kissy1.2\src\anim\fx.js
  2675. D:\code\kissy_git\kissy1.2\src\anim\queue.js
  2676. D:\code\kissy_git\kissy1.2\src\anim\base.js
  2677. D:\code\kissy_git\kissy1.2\src\anim\color.js
  2678. D:\code\kissy_git\kissy1.2\src\anim.js
  2679. D:\code\kissy_git\kissy1.2\src\node\anim.js
  2680. D:\code\kissy_git\kissy1.2\src\node.js
  2681. D:\code\kissy_git\kissy1.2\src\json\json2.js
  2682. D:\code\kissy_git\kissy1.2\src\json.js
  2683. D:\code\kissy_git\kissy1.2\src\ajax\form-serializer.js
  2684. D:\code\kissy_git\kissy1.2\src\ajax\xhrobject.js
  2685. D:\code\kissy_git\kissy1.2\src\ajax\base.js
  2686. D:\code\kissy_git\kissy1.2\src\ajax\xhrbase.js
  2687. D:\code\kissy_git\kissy1.2\src\ajax\subdomain.js
  2688. D:\code\kissy_git\kissy1.2\src\ajax\xdr.js
  2689. D:\code\kissy_git\kissy1.2\src\ajax\xhr.js
  2690. D:\code\kissy_git\kissy1.2\src\ajax\script.js
  2691. D:\code\kissy_git\kissy1.2\src\ajax\jsonp.js
  2692. D:\code\kissy_git\kissy1.2\src\ajax\form.js
  2693. D:\code\kissy_git\kissy1.2\src\ajax\iframe-upload.js
  2694. D:\code\kissy_git\kissy1.2\src\ajax.js
  2695. D:\code\kissy_git\kissy1.2\src\base\attribute.js
  2696. D:\code\kissy_git\kissy1.2\src\base\base.js
  2697. D:\code\kissy_git\kissy1.2\src\base.js
  2698. D:\code\kissy_git\kissy1.2\src\cookie\base.js
  2699. D:\code\kissy_git\kissy1.2\src\cookie.js
  2700. D:\code\kissy_git\kissy1.2\src\core.js
  2701. **/
  2702. /**
  2703. * @module ua
  2704. * @author lifesinger@gmail.com
  2705. */
  2706. KISSY.add('ua/base', function() {
  2707. var ua = navigator.userAgent,
  2708. EMPTY = '', MOBILE = 'mobile',
  2709. core = EMPTY, shell = EMPTY, m,
  2710. IE_DETECT_RANGE = [6, 9], v, end,
  2711. VERSION_PLACEHOLDER = '{{version}}',
  2712. IE_DETECT_TPL = '<!--[if IE ' + VERSION_PLACEHOLDER + ']><s></s><![endif]-->',
  2713. div = document.createElement('div'), s,
  2714. o = {
  2715. // browser core type
  2716. //webkit: 0,
  2717. //trident: 0,
  2718. //gecko: 0,
  2719. //presto: 0,
  2720. // browser type
  2721. //chrome: 0,
  2722. //safari: 0,
  2723. //firefox: 0,
  2724. //ie: 0,
  2725. //opera: 0
  2726. //mobile: '',
  2727. //core: '',
  2728. //shell: ''
  2729. },
  2730. numberify = function(s) {
  2731. var c = 0;
  2732. // convert '1.2.3.4' to 1.234
  2733. return parseFloat(s.replace(/\./g, function() {
  2734. return (c++ === 0) ? '.' : '';
  2735. }));
  2736. };
  2737. // try to use IE-Conditional-Comment detect IE more accurately
  2738. // IE10 doesn't support this method, @ref: http://blogs.msdn.com/b/ie/archive/2011/07/06/html5-parsing-in-ie10.aspx
  2739. div.innerHTML = IE_DETECT_TPL.replace(VERSION_PLACEHOLDER, '');
  2740. s = div.getElementsByTagName('s');
  2741. if (s.length > 0) {
  2742. shell = 'ie';
  2743. o[core = 'trident'] = 0.1; // Trident detected, look for revision
  2744. // Get the Trident's accurate version
  2745. if ((m = ua.match(/Trident\/([\d.]*)/)) && m[1]) {
  2746. o[core] = numberify(m[1]);
  2747. }
  2748. // Detect the accurate version
  2749. // 注意:
  2750. // o.shell = ie, 表示外壳是 ie
  2751. // 但 o.ie = 7, 并不代表外壳是 ie7, 还有可能是 ie8 的兼容模式
  2752. // 对于 ie8 的兼容模式,还要通过 documentMode 去判断。但此处不能让 o.ie = 8, 否则
  2753. // 很多脚本判断会失误。因为 ie8 的兼容模式表现行为和 ie7 相同,而不是和 ie8 相同
  2754. for (v = IE_DETECT_RANGE[0],end = IE_DETECT_RANGE[1]; v <= end; v++) {
  2755. div.innerHTML = IE_DETECT_TPL.replace(VERSION_PLACEHOLDER, v);
  2756. if (s.length > 0) {
  2757. o[shell] = v;
  2758. break;
  2759. }
  2760. }
  2761. } else {
  2762. // WebKit
  2763. if ((m = ua.match(/AppleWebKit\/([\d.]*)/)) && m[1]) {
  2764. o[core = 'webkit'] = numberify(m[1]);
  2765. // Chrome
  2766. if ((m = ua.match(/Chrome\/([\d.]*)/)) && m[1]) {
  2767. o[shell = 'chrome'] = numberify(m[1]);
  2768. }
  2769. // Safari
  2770. else if ((m = ua.match(/\/([\d.]*) Safari/)) && m[1]) {
  2771. o[shell = 'safari'] = numberify(m[1]);
  2772. }
  2773. // Apple Mobile
  2774. if (/ Mobile\//.test(ua)) {
  2775. o[MOBILE] = 'apple'; // iPad, iPhone or iPod Touch
  2776. }
  2777. // Other WebKit Mobile Browsers
  2778. else if ((m = ua.match(/NokiaN[^\/]*|Android \d\.\d|webOS\/\d\.\d/))) {
  2779. o[MOBILE] = m[0].toLowerCase(); // Nokia N-series, Android, webOS, ex: NokiaN95
  2780. }
  2781. }
  2782. // NOT WebKit
  2783. else {
  2784. // Presto
  2785. // ref: http://www.useragentstring.com/pages/useragentstring.php
  2786. if ((m = ua.match(/Presto\/([\d.]*)/)) && m[1]) {
  2787. o[core = 'presto'] = numberify(m[1]);
  2788. // Opera
  2789. if ((m = ua.match(/Opera\/([\d.]*)/)) && m[1]) {
  2790. o[shell = 'opera'] = numberify(m[1]); // Opera detected, look for revision
  2791. if ((m = ua.match(/Opera\/.* Version\/([\d.]*)/)) && m[1]) {
  2792. o[shell] = numberify(m[1]);
  2793. }
  2794. // Opera Mini
  2795. if ((m = ua.match(/Opera Mini[^;]*/)) && m) {
  2796. o[MOBILE] = m[0].toLowerCase(); // ex: Opera Mini/2.0.4509/1316
  2797. }
  2798. // Opera Mobile
  2799. // ex: Opera/9.80 (Windows NT 6.1; Opera Mobi/49; U; en) Presto/2.4.18 Version/10.00
  2800. // issue: 由于 Opera Mobile 有 Version/ 字段,可能会与 Opera 混淆,同时对于 Opera Mobile 的版本号也比较混乱
  2801. else if ((m = ua.match(/Opera Mobi[^;]*/)) && m) {
  2802. o[MOBILE] = m[0];
  2803. }
  2804. }
  2805. // NOT WebKit or Presto
  2806. } else {
  2807. // MSIE
  2808. // 由于最开始已经使用了 IE 条件注释判断,因此落到这里的唯一可能性只有 IE10+
  2809. if ((m = ua.match(/MSIE\s([^;]*)/)) && m[1]) {
  2810. o[core = 'trident'] = 0.1; // Trident detected, look for revision
  2811. o[shell = 'ie'] = numberify(m[1]);
  2812. // Get the Trident's accurate version
  2813. if ((m = ua.match(/Trident\/([\d.]*)/)) && m[1]) {
  2814. o[core] = numberify(m[1]);
  2815. }
  2816. // NOT WebKit, Presto or IE
  2817. } else {
  2818. // Gecko
  2819. if ((m = ua.match(/Gecko/))) {
  2820. o[core = 'gecko'] = 0.1; // Gecko detected, look for revision
  2821. if ((m = ua.match(/rv:([\d.]*)/)) && m[1]) {
  2822. o[core] = numberify(m[1]);
  2823. }
  2824. // Firefox
  2825. if ((m = ua.match(/Firefox\/([\d.]*)/)) && m[1]) {
  2826. o[shell = 'firefox'] = numberify(m[1]);
  2827. }
  2828. }
  2829. }
  2830. }
  2831. }
  2832. }
  2833. o.core = core;
  2834. o.shell = shell;
  2835. o._numberify = numberify;
  2836. return o;
  2837. });
  2838. /**
  2839. * NOTES:
  2840. *
  2841. * 2011.11.08
  2842. * - ie < 10 使用条件注释判断内核,更精确 by gonghaocn@gmail.com
  2843. *
  2844. * 2010.03
  2845. * - jQuery, YUI 等类库都推荐用特性探测替代浏览器嗅探。特性探测的好处是能自动适应未来设备和未知设备,比如
  2846. * if(document.addEventListener) 假设 IE9 支持标准事件,则代码不用修改,就自适应了“未来浏览器”。
  2847. * 对于未知浏览器也是如此。但是,这并不意味着浏览器嗅探就得彻底抛弃。当代码很明确就是针对已知特定浏览器的,
  2848. * 同时并非是某个特性探测可以解决时,用浏览器嗅探反而能带来代码的简洁,同时也也不会有什么后患。总之,一切
  2849. * 皆权衡。
  2850. * - UA.ie && UA.ie < 8 并不意味着浏览器就不是 IE8, 有可能是 IE8 的兼容模式。进一步的判断需要使用 documentMode.
  2851. *
  2852. * TODO:
  2853. * - test mobile
  2854. * - 3Q 大战后,360 去掉了 UA 信息中的 360 信息,需采用 res 方法去判断
  2855. *
  2856. */
  2857. /**
  2858. * @module ua-extra
  2859. * @author gonghao<gonghao@ghsky.com>
  2860. */
  2861. KISSY.add('ua/extra', function(S, UA) {
  2862. var ua = navigator.userAgent,
  2863. m, external, shell,
  2864. o = { },
  2865. numberify = UA._numberify;
  2866. /**
  2867. * 说明:
  2868. * @子涯总结的各国产浏览器的判断依据: http://spreadsheets0.google.com/ccc?key=tluod2VGe60_ceDrAaMrfMw&hl=zh_CN#gid=0
  2869. * 根据 CNZZ 2009 年度浏览器占用率报告,优化了判断顺序:http://www.tanmi360.com/post/230.htm
  2870. * 如果检测出浏览器,但是具体版本号未知用 0.1 作为标识
  2871. * 世界之窗 & 360 浏览器,在 3.x 以下的版本都无法通过 UA 或者特性检测进行判断,所以目前只要检测到 UA 关键字就认为起版本号为 3
  2872. */
  2873. // 360Browser
  2874. if (m = ua.match(/360SE/)) {
  2875. o[shell = 'se360'] = 3; // issue: 360Browser 2.x cannot be recognised, so if recognised default set verstion number to 3
  2876. }
  2877. // Maxthon
  2878. else if ((m = ua.match(/Maxthon/)) && (external = window.external)) {
  2879. // issue: Maxthon 3.x in IE-Core cannot be recognised and it doesn't have exact version number
  2880. // but other maxthon versions all have exact version number
  2881. shell = 'maxthon';
  2882. try {
  2883. o[shell] = numberify(external['max_version']);
  2884. } catch(ex) {
  2885. o[shell] = 0.1;
  2886. }
  2887. }
  2888. // TT
  2889. else if (m = ua.match(/TencentTraveler\s([\d.]*)/)) {
  2890. o[shell = 'tt'] = m[1] ? numberify(m[1]) : 0.1;
  2891. }
  2892. // TheWorld
  2893. else if (m = ua.match(/TheWorld/)) {
  2894. o[shell = 'theworld'] = 3; // issue: TheWorld 2.x cannot be recognised, so if recognised default set verstion number to 3
  2895. }
  2896. // Sougou
  2897. else if (m = ua.match(/SE\s([\d.]*)/)) {
  2898. o[shell = 'sougou'] = m[1] ? numberify(m[1]) : 0.1;
  2899. }
  2900. // If the browser has shell(no matter IE-core or Webkit-core or others), set the shell key
  2901. shell && (o.shell = shell);
  2902. S.mix(UA, o);
  2903. return UA;
  2904. }, {
  2905. requires:["ua/base"]
  2906. });
  2907. KISSY.add("ua", function(S,UA) {
  2908. return UA;
  2909. }, {
  2910. requires:["ua/extra"]
  2911. });
  2912. /**
  2913. * @module dom
  2914. * @author yiminghe@gmail.com,lifesinger@gmail.com
  2915. */
  2916. KISSY.add('dom/base', function(S, UA, undefined) {
  2917. function nodeTypeIs(node, val) {
  2918. return node && node.nodeType === val;
  2919. }
  2920. var NODE_TYPE = {
  2921. /**
  2922. * enumeration of dom node type
  2923. * @type Number
  2924. */
  2925. ELEMENT_NODE : 1,
  2926. "ATTRIBUTE_NODE" : 2,
  2927. TEXT_NODE:3,
  2928. "CDATA_SECTION_NODE" : 4,
  2929. "ENTITY_REFERENCE_NODE": 5,
  2930. "ENTITY_NODE" : 6,
  2931. "PROCESSING_INSTRUCTION_NODE" :7,
  2932. COMMENT_NODE : 8,
  2933. DOCUMENT_NODE : 9,
  2934. "DOCUMENT_TYPE_NODE" : 10,
  2935. DOCUMENT_FRAGMENT_NODE : 11,
  2936. "NOTATION_NODE" : 12
  2937. };
  2938. var DOM = {
  2939. _isCustomDomain :function (win) {
  2940. win = win || window;
  2941. var domain = win.document.domain,
  2942. hostname = win.location.hostname;
  2943. return domain != hostname &&
  2944. domain != ( '[' + hostname + ']' ); // IPv6 IP support
  2945. },
  2946. _genEmptyIframeSrc:function(win) {
  2947. win = win || window;
  2948. if (UA['ie'] && DOM._isCustomDomain(win)) {
  2949. return 'javascript:void(function(){' + encodeURIComponent("" +
  2950. "document.open();" +
  2951. "document.domain='" +
  2952. win.document.domain
  2953. + "';" +
  2954. "document.close();") + "}())";
  2955. }
  2956. },
  2957. _NODE_TYPE:NODE_TYPE,
  2958. /**
  2959. * 是不是 element node
  2960. */
  2961. _isElementNode: function(elem) {
  2962. return nodeTypeIs(elem, DOM.ELEMENT_NODE);
  2963. },
  2964. /**
  2965. * elem 为 window 时,直接返回
  2966. * elem 为 document 时,返回关联的 window
  2967. * elem 为 undefined 时,返回当前 window
  2968. * 其它值,返回 false
  2969. */
  2970. _getWin: function(elem) {
  2971. return (elem && ('scrollTo' in elem) && elem['document']) ?
  2972. elem :
  2973. nodeTypeIs(elem, DOM.DOCUMENT_NODE) ?
  2974. elem.defaultView || elem.parentWindow :
  2975. (elem === undefined || elem === null) ?
  2976. window : false;
  2977. },
  2978. _nodeTypeIs: nodeTypeIs,
  2979. // Ref: http://lifesinger.github.com/lab/2010/nodelist.html
  2980. _isNodeList:function(o) {
  2981. // 注1:ie 下,有 window.item, typeof node.item 在 ie 不同版本下,返回值不同
  2982. // 注2:select 等元素也有 item, 要用 !node.nodeType 排除掉
  2983. // 注3:通过 namedItem 来判断不可靠
  2984. // 注4:getElementsByTagName 和 querySelectorAll 返回的集合不同
  2985. // 注5: 考虑 iframe.contentWindow
  2986. return o && !o.nodeType && o.item && !o.setTimeout;
  2987. },
  2988. _nodeName:function(e, name) {
  2989. return e && e.nodeName.toLowerCase() === name.toLowerCase();
  2990. }
  2991. };
  2992. S.mix(DOM, NODE_TYPE);
  2993. return DOM;
  2994. }, {
  2995. requires:['ua']
  2996. });
  2997. /**
  2998. * 2011-08
  2999. * - 添加键盘枚举值,方便依赖程序清晰
  3000. */
  3001. /**
  3002. * @module dom-attr
  3003. * @author yiminghe@gmail.com,lifesinger@gmail.com
  3004. */
  3005. KISSY.add('dom/attr', function(S, DOM, UA, undefined) {
  3006. var doc = document,
  3007. docElement = doc.documentElement,
  3008. oldIE = !docElement.hasAttribute,
  3009. TEXT = docElement.textContent === undefined ?
  3010. 'innerText' : 'textContent',
  3011. EMPTY = '',
  3012. nodeName = DOM._nodeName,
  3013. isElementNode = DOM._isElementNode,
  3014. rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
  3015. rfocusable = /^(?:button|input|object|select|textarea)$/i,
  3016. rclickable = /^a(?:rea)?$/i,
  3017. rinvalidChar = /:|^on/,
  3018. rreturn = /\r/g,
  3019. attrFix = {
  3020. },
  3021. attrFn = {
  3022. val: 1,
  3023. css: 1,
  3024. html: 1,
  3025. text: 1,
  3026. data: 1,
  3027. width: 1,
  3028. height: 1,
  3029. offset: 1,
  3030. scrollTop:1,
  3031. scrollLeft:1
  3032. },
  3033. attrHooks = {
  3034. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  3035. tabindex:{
  3036. get:function(el) {
  3037. // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  3038. var attributeNode = el.getAttributeNode("tabindex");
  3039. return attributeNode && attributeNode.specified ?
  3040. parseInt(attributeNode.value, 10) :
  3041. rfocusable.test(el.nodeName) || rclickable.test(el.nodeName) && el.href ?
  3042. 0 :
  3043. undefined;
  3044. }
  3045. },
  3046. // 在标准浏览器下,用 getAttribute 获取 style 值
  3047. // IE7- 下,需要用 cssText 来获取
  3048. // 统一使用 cssText
  3049. style:{
  3050. get:function(el) {
  3051. return el.style.cssText;
  3052. },
  3053. set:function(el, val) {
  3054. el.style.cssText = val;
  3055. }
  3056. }
  3057. },
  3058. propFix = {
  3059. tabindex: "tabIndex",
  3060. readonly: "readOnly",
  3061. "for": "htmlFor",
  3062. "class": "className",
  3063. maxlength: "maxLength",
  3064. cellspacing: "cellSpacing",
  3065. "cellpadding": "cellPadding",
  3066. rowspan: "rowSpan",
  3067. colspan: "colSpan",
  3068. usemap: "useMap",
  3069. frameborder: "frameBorder",
  3070. "contenteditable": "contentEditable"
  3071. },
  3072. // Hook for boolean attributes
  3073. // if bool is false
  3074. // - standard browser returns null
  3075. // - ie<8 return false
  3076. // - so norm to undefined
  3077. boolHook = {
  3078. get: function(elem, name) {
  3079. // 转发到 prop 方法
  3080. return DOM.prop(elem, name) ?
  3081. // 根据 w3c attribute , true 时返回属性名字符串
  3082. name.toLowerCase() :
  3083. undefined;
  3084. },
  3085. set: function(elem, value, name) {
  3086. var propName;
  3087. if (value === false) {
  3088. // Remove boolean attributes when set to false
  3089. DOM.removeAttr(elem, name);
  3090. } else {
  3091. // 直接设置 true,因为这是 bool 类属性
  3092. propName = propFix[ name ] || name;
  3093. if (propName in elem) {
  3094. // Only set the IDL specifically if it already exists on the element
  3095. elem[ propName ] = true;
  3096. }
  3097. elem.setAttribute(name, name.toLowerCase());
  3098. }
  3099. return name;
  3100. }
  3101. },
  3102. propHooks = {},
  3103. // get attribute value from attribute node , only for ie
  3104. attrNodeHook = {
  3105. },
  3106. valHooks = {
  3107. option: {
  3108. get: function(elem) {
  3109. // 当没有设定 value 时,标准浏览器 option.value === option.text
  3110. // ie7- 下,没有设定 value 时,option.value === '', 需要用 el.attributes.value 来判断是否有设定 value
  3111. var val = elem.attributes.value;
  3112. return !val || val.specified ? elem.value : elem.text;
  3113. }
  3114. },
  3115. select: {
  3116. // 对于 select, 特别是 multiple type, 存在很严重的兼容性问题
  3117. get: function(elem) {
  3118. var index = elem.selectedIndex,
  3119. options = elem.options,
  3120. one = elem.type === "select-one";
  3121. // Nothing was selected
  3122. if (index < 0) {
  3123. return null;
  3124. } else if (one) {
  3125. return DOM.val(options[index]);
  3126. }
  3127. // Loop through all the selected options
  3128. var ret = [], i = 0, len = options.length;
  3129. for (; i < len; ++i) {
  3130. if (options[i].selected) {
  3131. ret.push(DOM.val(options[i]));
  3132. }
  3133. }
  3134. // Multi-Selects return an array
  3135. return ret;
  3136. },
  3137. set: function(elem, value) {
  3138. var values = S.makeArray(value),
  3139. opts = elem.options;
  3140. S.each(opts, function(opt) {
  3141. opt.selected = S.inArray(DOM.val(opt), values);
  3142. });
  3143. if (!values.length) {
  3144. elem.selectedIndex = -1;
  3145. }
  3146. return values;
  3147. }
  3148. }};
  3149. function isTextNode(elem) {
  3150. return DOM._nodeTypeIs(elem, DOM.TEXT_NODE);
  3151. }
  3152. if (oldIE) {
  3153. // get attribute value from attribute node for ie
  3154. attrNodeHook = {
  3155. get: function(elem, name) {
  3156. var ret;
  3157. ret = elem.getAttributeNode(name);
  3158. // Return undefined if nodeValue is empty string
  3159. return ret && ret.nodeValue !== "" ?
  3160. ret.nodeValue :
  3161. undefined;
  3162. },
  3163. set: function(elem, value, name) {
  3164. // Check form objects in IE (multiple bugs related)
  3165. // Only use nodeValue if the attribute node exists on the form
  3166. var ret = elem.getAttributeNode(name);
  3167. if (ret) {
  3168. ret.nodeValue = value;
  3169. } else {
  3170. try {
  3171. var attr = elem.ownerDocument.createAttribute(name);
  3172. attr.value = value;
  3173. elem.setAttributeNode(attr);
  3174. }
  3175. catch (e) {
  3176. // It's a real failure only if setAttribute also fails.
  3177. return elem.setAttribute(name, value, 0);
  3178. }
  3179. }
  3180. }
  3181. };
  3182. // ie6,7 不区分 attribute 与 property
  3183. attrFix = propFix;
  3184. // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  3185. attrHooks.tabIndex = attrHooks.tabindex;
  3186. // fix ie bugs
  3187. // 不光是 href, src, 还有 rowspan 等非 mapping 属性,也需要用第 2 个参数来获取原始值
  3188. // 注意 colSpan rowSpan 已经由 propFix 转为大写
  3189. S.each([ "href", "src", "width", "height","colSpan","rowSpan" ], function(name) {
  3190. attrHooks[ name ] = {
  3191. get: function(elem) {
  3192. var ret = elem.getAttribute(name, 2);
  3193. return ret === null ? undefined : ret;
  3194. }
  3195. };
  3196. });
  3197. // button 元素的 value 属性和其内容冲突
  3198. // <button value='xx'>zzz</button>
  3199. valHooks.button = attrHooks.value = attrNodeHook;
  3200. }
  3201. // Radios and checkboxes getter/setter
  3202. S.each([ "radio", "checkbox" ], function(r) {
  3203. valHooks[ r ] = {
  3204. get: function(elem) {
  3205. // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
  3206. return elem.getAttribute("value") === null ? "on" : elem.value;
  3207. },
  3208. set: function(elem, value) {
  3209. if (S.isArray(value)) {
  3210. return elem.checked = S.inArray(DOM.val(elem), value);
  3211. }
  3212. }
  3213. };
  3214. });
  3215. function getProp(elem, name) {
  3216. name = propFix[ name ] || name;
  3217. var hook = propHooks[ name ];
  3218. if (hook && hook.get) {
  3219. return hook.get(elem, name);
  3220. } else {
  3221. return elem[ name ];
  3222. }
  3223. }
  3224. S.mix(DOM, {
  3225. /**
  3226. * 自定义属性不推荐使用,使用 .data
  3227. * @param selector
  3228. * @param name
  3229. * @param value
  3230. */
  3231. prop: function(selector, name, value) {
  3232. // suports hash
  3233. if (S.isPlainObject(name)) {
  3234. for (var k in name) {
  3235. DOM.prop(selector, k, name[k]);
  3236. }
  3237. return;
  3238. }
  3239. var elems = DOM.query(selector);
  3240. // Try to normalize/fix the name
  3241. name = propFix[ name ] || name;
  3242. var hook = propHooks[ name ];
  3243. if (value !== undefined) {
  3244. elems.each(function(elem) {
  3245. if (hook && hook.set) {
  3246. hook.set(elem, value, name);
  3247. } else {
  3248. elem[ name ] = value;
  3249. }
  3250. });
  3251. } else {
  3252. if (elems.length) {
  3253. return getProp(elems[0], name);
  3254. }
  3255. }
  3256. },
  3257. /**
  3258. * 是否其中一个元素包含指定 property
  3259. * @param selector
  3260. * @param name
  3261. */
  3262. hasProp:function(selector, name) {
  3263. var elems = DOM.query(selector);
  3264. for (var i = 0; i < elems.length; i++) {
  3265. var el = elems[i];
  3266. if (getProp(el, name) !== undefined) {
  3267. return true;
  3268. }
  3269. }
  3270. return false;
  3271. },
  3272. /**
  3273. * 不推荐使用,使用 .data .removeData
  3274. * @param selector
  3275. * @param name
  3276. */
  3277. removeProp:function(selector, name) {
  3278. name = propFix[ name ] || name;
  3279. DOM.query(selector).each(function(el) {
  3280. try {
  3281. el[ name ] = undefined;
  3282. delete el[ name ];
  3283. } catch(e) {
  3284. S.log("delete el property error : ");
  3285. S.log(e);
  3286. }
  3287. });
  3288. },
  3289. /**
  3290. * Gets the value of an attribute for the first element in the set of matched elements or
  3291. * Sets an attribute for the set of matched elements.
  3292. */
  3293. attr:function(selector, name, val, pass) {
  3294. /*
  3295. Hazards From Caja Note:
  3296. - In IE[67], el.setAttribute doesn't work for attributes like
  3297. 'class' or 'for'. IE[67] expects you to set 'className' or
  3298. 'htmlFor'. Caja use setAttributeNode solves this problem.
  3299. - In IE[67], <input> elements can shadow attributes. If el is a
  3300. form that contains an <input> named x, then el.setAttribute(x, y)
  3301. will set x's value rather than setting el's attribute. Using
  3302. setAttributeNode solves this problem.
  3303. - In IE[67], the style attribute can only be modified by setting
  3304. el.style.cssText. Neither setAttribute nor setAttributeNode will
  3305. work. el.style.cssText isn't bullet-proof, since it can be
  3306. shadowed by <input> elements.
  3307. - In IE[67], you can never change the type of an <button> element.
  3308. setAttribute('type') silently fails, but setAttributeNode
  3309. throws an exception. caja : the silent failure. KISSY throws error.
  3310. - In IE[67], you can never change the type of an <input> element.
  3311. setAttribute('type') throws an exception. We want the exception.
  3312. - In IE[67], setAttribute is case-sensitive, unless you pass 0 as a
  3313. 3rd argument. setAttributeNode is case-insensitive.
  3314. - Trying to set an invalid name like ":" is supposed to throw an
  3315. error. In IE[678] and Opera 10, it fails without an error.
  3316. */
  3317. // suports hash
  3318. if (S.isPlainObject(name)) {
  3319. pass = val;
  3320. for (var k in name) {
  3321. DOM.attr(selector, k, name[k], pass);
  3322. }
  3323. return;
  3324. }
  3325. if (!(name = S.trim(name))) {
  3326. return;
  3327. }
  3328. // attr functions
  3329. if (pass && attrFn[name]) {
  3330. return DOM[name](selector, val);
  3331. }
  3332. // scrollLeft
  3333. name = name.toLowerCase();
  3334. if (pass && attrFn[name]) {
  3335. return DOM[name](selector, val);
  3336. }
  3337. var els = DOM.query(selector);
  3338. if (val === undefined) {
  3339. return DOM.__attr(els[0], name);
  3340. } else {
  3341. els.each(function(el) {
  3342. DOM.__attr(el, name, val);
  3343. });
  3344. }
  3345. },
  3346. __attr:function(el, name, val) {
  3347. if (!isElementNode(el)) {
  3348. return;
  3349. }
  3350. // custom attrs
  3351. name = attrFix[name] || name;
  3352. var attrNormalizer,
  3353. ret;
  3354. // browsers index elements by id/name on forms, give priority to attributes.
  3355. if (nodeName(el, "form")) {
  3356. attrNormalizer = attrNodeHook;
  3357. }
  3358. else if (rboolean.test(name)) {
  3359. attrNormalizer = boolHook;
  3360. }
  3361. // only old ie?
  3362. else if (rinvalidChar.test(name)) {
  3363. attrNormalizer = attrNodeHook;
  3364. } else {
  3365. attrNormalizer = attrHooks[name];
  3366. }
  3367. // getter
  3368. if (val === undefined) {
  3369. if (attrNormalizer && attrNormalizer.get) {
  3370. return attrNormalizer.get(el, name);
  3371. }
  3372. ret = el.getAttribute(name);
  3373. // standard browser non-existing attribute return null
  3374. // ie<8 will return undefined , because it return property
  3375. // so norm to undefined
  3376. return ret === null ? undefined : ret;
  3377. } else {
  3378. if (attrNormalizer && attrNormalizer.set) {
  3379. attrNormalizer.set(el, val, name);
  3380. } else {
  3381. // convert the value to a string (all browsers do this but IE)
  3382. el.setAttribute(name, EMPTY + val);
  3383. }
  3384. }
  3385. },
  3386. /**
  3387. * Removes the attribute of the matched elements.
  3388. */
  3389. removeAttr: function(selector, name) {
  3390. name = name.toLowerCase();
  3391. name = attrFix[name] || name;
  3392. DOM.query(selector).each(function(el) {
  3393. if (isElementNode(el)) {
  3394. var propName;
  3395. el.removeAttribute(name);
  3396. // Set corresponding property to false for boolean attributes
  3397. if (rboolean.test(name) && (propName = propFix[ name ] || name) in el) {
  3398. el[ propName ] = false;
  3399. }
  3400. }
  3401. });
  3402. },
  3403. /**
  3404. * 是否其中一个元素包含指定属性
  3405. */
  3406. hasAttr: oldIE ?
  3407. function(selector, name) {
  3408. name = name.toLowerCase();
  3409. var elems = DOM.query(selector);
  3410. // from ppk :http://www.quirksmode.org/dom/w3c_core.html
  3411. // IE5-7 doesn't return the value of a style attribute.
  3412. // var $attr = el.attributes[name];
  3413. for (var i = 0; i < elems.length; i++) {
  3414. var el = elems[i];
  3415. var $attr = el.getAttributeNode(name);
  3416. if ($attr && $attr.specified) {
  3417. return true;
  3418. }
  3419. }
  3420. return false;
  3421. }
  3422. :
  3423. function(selector, name) {
  3424. var elems = DOM.query(selector);
  3425. for (var i = 0; i < elems.length; i++) {
  3426. var el = elems[i];
  3427. //使用原生实现
  3428. if (el.hasAttribute(name)) {
  3429. return true;
  3430. }
  3431. }
  3432. return false;
  3433. },
  3434. /**
  3435. * Gets the current value of the first element in the set of matched or
  3436. * Sets the value of each element in the set of matched elements.
  3437. */
  3438. val : function(selector, value) {
  3439. var hook, ret;
  3440. //getter
  3441. if (value === undefined) {
  3442. var elem = DOM.get(selector);
  3443. if (elem) {
  3444. hook = valHooks[ elem.nodeName.toLowerCase() ] || valHooks[ elem.type ];
  3445. if (hook && "get" in hook && (ret = hook.get(elem, "value")) !== undefined) {
  3446. return ret;
  3447. }
  3448. ret = elem.value;
  3449. return typeof ret === "string" ?
  3450. // handle most common string cases
  3451. ret.replace(rreturn, "") :
  3452. // handle cases where value is null/undefined or number
  3453. S.isNullOrUndefined(ret) ? "" : ret;
  3454. }
  3455. return;
  3456. }
  3457. DOM.query(selector).each(function(elem) {
  3458. if (elem.nodeType !== 1) {
  3459. return;
  3460. }
  3461. var val = value;
  3462. // Treat null/undefined as ""; convert numbers to string
  3463. if (S.isNullOrUndefined(val)) {
  3464. val = "";
  3465. } else if (typeof val === "number") {
  3466. val += "";
  3467. } else if (S.isArray(val)) {
  3468. val = S.map(val, function (value) {
  3469. return S.isNullOrUndefined(val) ? "" : value + "";
  3470. });
  3471. }
  3472. hook = valHooks[ elem.nodeName.toLowerCase() ] || valHooks[ elem.type ];
  3473. // If set returns undefined, fall back to normal setting
  3474. if (!hook || !("set" in hook) || hook.set(elem, val, "value") === undefined) {
  3475. elem.value = val;
  3476. }
  3477. });
  3478. },
  3479. /**
  3480. * Gets the text context of the first element in the set of matched elements or
  3481. * Sets the text content of the matched elements.
  3482. */
  3483. text: function(selector, val) {
  3484. // getter
  3485. if (val === undefined) {
  3486. // supports css selector/Node/NodeList
  3487. var el = DOM.get(selector);
  3488. // only gets value on supported nodes
  3489. if (isElementNode(el)) {
  3490. return el[TEXT] || EMPTY;
  3491. }
  3492. else if (isTextNode(el)) {
  3493. return el.nodeValue;
  3494. }
  3495. return undefined;
  3496. }
  3497. // setter
  3498. else {
  3499. DOM.query(selector).each(function(el) {
  3500. if (isElementNode(el)) {
  3501. el[TEXT] = val;
  3502. }
  3503. else if (isTextNode(el)) {
  3504. el.nodeValue = val;
  3505. }
  3506. });
  3507. }
  3508. }
  3509. });
  3510. return DOM;
  3511. }, {
  3512. requires:["./base","ua"]
  3513. }
  3514. );
  3515. /**
  3516. * NOTES:
  3517. * 承玉:2011-06-03
  3518. * - 借鉴 jquery 1.6,理清 attribute 与 property
  3519. *
  3520. * 承玉:2011-01-28
  3521. * - 处理 tabindex,顺便重构
  3522. *
  3523. * 2010.03
  3524. * - 在 jquery/support.js 中,special attrs 里还有 maxlength, cellspacing,
  3525. * rowspan, colspan, useap, frameboder, 但测试发现,在 Grade-A 级浏览器中
  3526. * 并无兼容性问题。
  3527. * - 当 colspan/rowspan 属性值设置有误时,ie7- 会自动纠正,和 href 一样,需要传递
  3528. * 第 2 个参数来解决。jQuery 未考虑,存在兼容性 bug.
  3529. * - jQuery 考虑了未显式设定 tabindex 时引发的兼容问题,kissy 里忽略(太不常用了)
  3530. * - jquery/attributes.js: Safari mis-reports the default selected
  3531. * property of an option 在 Safari 4 中已修复。
  3532. *
  3533. */
  3534. /**
  3535. * @module dom-class
  3536. * @author lifesinger@gmail.com
  3537. */
  3538. KISSY.add('dom/class', function(S, DOM, undefined) {
  3539. var SPACE = ' ',
  3540. REG_SPLIT = /[\.\s]\s*\.?/,
  3541. REG_CLASS = /[\n\t]/g;
  3542. function norm(elemClass) {
  3543. return (SPACE + elemClass + SPACE).replace(REG_CLASS, SPACE);
  3544. }
  3545. S.mix(DOM, {
  3546. __hasClass:function(el, cls) {
  3547. var className = el.className;
  3548. if (className) {
  3549. className = norm(className);
  3550. return className.indexOf(SPACE + cls + SPACE) > -1;
  3551. } else {
  3552. return false;
  3553. }
  3554. },
  3555. /**
  3556. * Determine whether any of the matched elements are assigned the given class.
  3557. */
  3558. hasClass: function(selector, value) {
  3559. return batch(selector, value, function(elem, classNames, cl) {
  3560. var elemClass = elem.className;
  3561. if (elemClass) {
  3562. var className = norm(elemClass),
  3563. j = 0,
  3564. ret = true;
  3565. for (; j < cl; j++) {
  3566. if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
  3567. ret = false;
  3568. break;
  3569. }
  3570. }
  3571. if (ret) {
  3572. return true;
  3573. }
  3574. }
  3575. }, true);
  3576. },
  3577. /**
  3578. * Adds the specified class(es) to each of the set of matched elements.
  3579. */
  3580. addClass: function(selector, value) {
  3581. batch(selector, value, function(elem, classNames, cl) {
  3582. var elemClass = elem.className;
  3583. if (!elemClass) {
  3584. elem.className = value;
  3585. } else {
  3586. var className = norm(elemClass),
  3587. setClass = elemClass,
  3588. j = 0;
  3589. for (; j < cl; j++) {
  3590. if (className.indexOf(SPACE + classNames[j] + SPACE) < 0) {
  3591. setClass += SPACE + classNames[j];
  3592. }
  3593. }
  3594. elem.className = S.trim(setClass);
  3595. }
  3596. }, undefined);
  3597. },
  3598. /**
  3599. * Remove a single class, multiple classes, or all classes from each element in the set of matched elements.
  3600. */
  3601. removeClass: function(selector, value) {
  3602. batch(selector, value, function(elem, classNames, cl) {
  3603. var elemClass = elem.className;
  3604. if (elemClass) {
  3605. if (!cl) {
  3606. elem.className = '';
  3607. } else {
  3608. var className = norm(elemClass),
  3609. j = 0,
  3610. needle;
  3611. for (; j < cl; j++) {
  3612. needle = SPACE + classNames[j] + SPACE;
  3613. // 一个 cls 有可能多次出现:'link link2 link link3 link'
  3614. while (className.indexOf(needle) >= 0) {
  3615. className = className.replace(needle, SPACE);
  3616. }
  3617. }
  3618. elem.className = S.trim(className);
  3619. }
  3620. }
  3621. }, undefined);
  3622. },
  3623. /**
  3624. * Replace a class with another class for matched elements.
  3625. * If no oldClassName is present, the newClassName is simply added.
  3626. */
  3627. replaceClass: function(selector, oldClassName, newClassName) {
  3628. DOM.removeClass(selector, oldClassName);
  3629. DOM.addClass(selector, newClassName);
  3630. },
  3631. /**
  3632. * Add or remove one or more classes from each element in the set of
  3633. * matched elements, depending on either the class's presence or the
  3634. * value of the switch argument.
  3635. * @param state {Boolean} optional boolean to indicate whether class
  3636. * should be added or removed regardless of current state.
  3637. */
  3638. toggleClass: function(selector, value, state) {
  3639. var isBool = S.isBoolean(state), has;
  3640. batch(selector, value, function(elem, classNames, cl) {
  3641. var j = 0, className;
  3642. for (; j < cl; j++) {
  3643. className = classNames[j];
  3644. has = isBool ? !state : DOM.hasClass(elem, className);
  3645. DOM[has ? 'removeClass' : 'addClass'](elem, className);
  3646. }
  3647. }, undefined);
  3648. }
  3649. });
  3650. function batch(selector, value, fn, resultIsBool) {
  3651. if (!(value = S.trim(value))) {
  3652. return resultIsBool ? false : undefined;
  3653. }
  3654. var elems = DOM.query(selector),
  3655. len = elems.length,
  3656. tmp = value.split(REG_SPLIT),
  3657. elem,
  3658. ret;
  3659. var classNames = [];
  3660. for (var i = 0; i < tmp.length; i++) {
  3661. var t = S.trim(tmp[i]);
  3662. if (t) {
  3663. classNames.push(t);
  3664. }
  3665. }
  3666. for (i = 0; i < len; i++) {
  3667. elem = elems[i];
  3668. if (DOM._isElementNode(elem)) {
  3669. ret = fn(elem, classNames, classNames.length);
  3670. if (ret !== undefined) {
  3671. return ret;
  3672. }
  3673. }
  3674. }
  3675. if (resultIsBool) {
  3676. return false;
  3677. }
  3678. return undefined;
  3679. }
  3680. return DOM;
  3681. }, {
  3682. requires:["dom/base"]
  3683. });
  3684. /**
  3685. * NOTES:
  3686. * - hasClass/addClass/removeClass 的逻辑和 jQuery 保持一致
  3687. * - toggleClass 不支持 value 为 undefined 的情形(jQuery 支持)
  3688. */
  3689. /**
  3690. * @module dom-create
  3691. * @author lifesinger@gmail.com,yiminghe@gmail.com
  3692. */
  3693. KISSY.add('dom/create', function(S, DOM, UA, undefined) {
  3694. var doc = document,
  3695. ie = UA['ie'],
  3696. nodeTypeIs = DOM._nodeTypeIs,
  3697. isElementNode = DOM._isElementNode,
  3698. isString = S.isString,
  3699. DIV = 'div',
  3700. PARENT_NODE = 'parentNode',
  3701. DEFAULT_DIV = doc.createElement(DIV),
  3702. rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
  3703. RE_TAG = /<([\w:]+)/,
  3704. rleadingWhitespace = /^\s+/,
  3705. lostLeadingWhitespace = ie && ie < 9,
  3706. rhtml = /<|&#?\w+;/,
  3707. RE_SIMPLE_TAG = /^<(\w+)\s*\/?>(?:<\/\1>)?$/;
  3708. // help compression
  3709. function getElementsByTagName(el, tag) {
  3710. return el.getElementsByTagName(tag);
  3711. }
  3712. function cleanData(els) {
  3713. var Event = S.require("event");
  3714. if (Event) {
  3715. Event.detach(els);
  3716. }
  3717. DOM.removeData(els);
  3718. }
  3719. S.mix(DOM, {
  3720. /**
  3721. * Creates a new HTMLElement using the provided html string.
  3722. */
  3723. create: function(html, props, ownerDoc, _trim/*internal*/) {
  3724. if (isElementNode(html)
  3725. || nodeTypeIs(html, DOM.TEXT_NODE)) {
  3726. return DOM.clone(html);
  3727. }
  3728. var ret = null;
  3729. if (!isString(html)) {
  3730. return ret;
  3731. }
  3732. if (_trim === undefined) {
  3733. _trim = true;
  3734. }
  3735. if (_trim) {
  3736. html = S.trim(html);
  3737. }
  3738. if (!html) {
  3739. return ret;
  3740. }
  3741. var creators = DOM._creators,
  3742. holder,
  3743. whitespaceMatch,
  3744. context = ownerDoc || doc,
  3745. m,
  3746. tag = DIV,
  3747. k,
  3748. nodes;
  3749. if (!rhtml.test(html)) {
  3750. ret = context.createTextNode(html);
  3751. }
  3752. // 简单 tag, 比如 DOM.create('<p>')
  3753. else if ((m = RE_SIMPLE_TAG.exec(html))) {
  3754. ret = context.createElement(m[1]);
  3755. }
  3756. // 复杂情况,比如 DOM.create('<img src="sprite.png" />')
  3757. else {
  3758. // Fix "XHTML"-style tags in all browsers
  3759. html = html.replace(rxhtmlTag, "<$1><" + "/$2>");
  3760. if ((m = RE_TAG.exec(html)) && (k = m[1])) {
  3761. tag = k.toLowerCase();
  3762. }
  3763. holder = (creators[tag] || creators[DIV])(html, context);
  3764. // ie 把前缀空白吃掉了
  3765. if (lostLeadingWhitespace && (whitespaceMatch = html.match(rleadingWhitespace))) {
  3766. holder.insertBefore(context.createTextNode(whitespaceMatch[0]), holder.firstChild);
  3767. }
  3768. nodes = holder.childNodes;
  3769. if (nodes.length === 1) {
  3770. // return single node, breaking parentNode ref from "fragment"
  3771. ret = nodes[0][PARENT_NODE].removeChild(nodes[0]);
  3772. }
  3773. else if (nodes.length) {
  3774. // return multiple nodes as a fragment
  3775. ret = nl2frag(nodes, context);
  3776. } else {
  3777. S.error(html + " : create node error");
  3778. }
  3779. }
  3780. return attachProps(ret, props);
  3781. },
  3782. _creators: {
  3783. div: function(html, ownerDoc) {
  3784. var frag = ownerDoc && ownerDoc != doc ? ownerDoc.createElement(DIV) : DEFAULT_DIV;
  3785. // html 为 <style></style> 时不行,必须有其他元素?
  3786. frag['innerHTML'] = "m<div>" + html + "<" + "/div>";
  3787. return frag.lastChild;
  3788. }
  3789. },
  3790. /**
  3791. * Gets/Sets the HTML contents of the HTMLElement.
  3792. * @param {Boolean} loadScripts (optional) True to look for and process scripts (defaults to false).
  3793. * @param {Function} callback (optional) For async script loading you can be notified when the update completes.
  3794. */
  3795. html: function(selector, val, loadScripts, callback) {
  3796. // supports css selector/Node/NodeList
  3797. var els = DOM.query(selector),el = els[0];
  3798. if (!el) {
  3799. return
  3800. }
  3801. // getter
  3802. if (val === undefined) {
  3803. // only gets value on the first of element nodes
  3804. if (isElementNode(el)) {
  3805. return el['innerHTML'];
  3806. } else {
  3807. return null;
  3808. }
  3809. }
  3810. // setter
  3811. else {
  3812. var success = false;
  3813. val += "";
  3814. // faster
  3815. if (! val.match(/<(?:script|style)/i) &&
  3816. (!lostLeadingWhitespace || !val.match(rleadingWhitespace)) &&
  3817. !creatorsMap[ (val.match(RE_TAG) || ["",""])[1].toLowerCase() ]) {
  3818. try {
  3819. els.each(function(elem) {
  3820. if (isElementNode(elem)) {
  3821. cleanData(getElementsByTagName(elem, "*"));
  3822. elem.innerHTML = val;
  3823. }
  3824. });
  3825. success = true;
  3826. } catch(e) {
  3827. // a <= "<a>"
  3828. // a.innerHTML='<p>1</p>';
  3829. }
  3830. }
  3831. if (!success) {
  3832. val = DOM.create(val, 0, el.ownerDocument, false);
  3833. els.each(function(elem) {
  3834. if (isElementNode(elem)) {
  3835. DOM.empty(elem);
  3836. DOM.append(val, elem, loadScripts);
  3837. }
  3838. });
  3839. }
  3840. callback && callback();
  3841. }
  3842. },
  3843. /**
  3844. * Remove the set of matched elements from the DOM.
  3845. * 不要使用 innerHTML='' 来清除元素,可能会造成内存泄露,要使用 DOM.remove()
  3846. * @param selector 选择器或元素集合
  3847. * @param {Boolean} keepData 删除元素时是否保留其上的数据,用于离线操作,提高性能
  3848. */
  3849. remove: function(selector, keepData) {
  3850. DOM.query(selector).each(function(el) {
  3851. if (!keepData && isElementNode(el)) {
  3852. // 清楚数据
  3853. var elChildren = getElementsByTagName(el, "*");
  3854. cleanData(elChildren);
  3855. cleanData(el);
  3856. }
  3857. if (el.parentNode) {
  3858. el.parentNode.removeChild(el);
  3859. }
  3860. });
  3861. },
  3862. /**
  3863. * clone node across browsers for the first node in selector
  3864. * @param selector 选择器或单个元素
  3865. * @param {Boolean} withDataAndEvent 复制节点是否包括和源节点同样的数据和事件
  3866. * @param {Boolean} deepWithDataAndEvent 复制节点的子孙节点是否包括和源节点子孙节点同样的数据和事件
  3867. * @refer https://developer.mozilla.org/En/DOM/Node.cloneNode
  3868. * @returns 复制后的节点
  3869. */
  3870. clone:function(selector, deep, withDataAndEvent, deepWithDataAndEvent) {
  3871. var elem = DOM.get(selector);
  3872. if (!elem) {
  3873. return null;
  3874. }
  3875. // TODO
  3876. // ie bug :
  3877. // 1. ie<9 <script>xx</script> => <script></script>
  3878. // 2. ie will execute external script
  3879. var clone = elem.cloneNode(deep);
  3880. if (isElementNode(elem) ||
  3881. nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  3882. // IE copies events bound via attachEvent when using cloneNode.
  3883. // Calling detachEvent on the clone will also remove the events
  3884. // from the original. In order to get around this, we use some
  3885. // proprietary methods to clear the events. Thanks to MooTools
  3886. // guys for this hotness.
  3887. if (isElementNode(elem)) {
  3888. fixAttributes(elem, clone);
  3889. }
  3890. if (deep) {
  3891. processAll(fixAttributes, elem, clone);
  3892. }
  3893. }
  3894. // runtime 获得事件模块
  3895. if (withDataAndEvent) {
  3896. cloneWidthDataAndEvent(elem, clone);
  3897. if (deep && deepWithDataAndEvent) {
  3898. processAll(cloneWidthDataAndEvent, elem, clone);
  3899. }
  3900. }
  3901. return clone;
  3902. },
  3903. empty:function(selector) {
  3904. DOM.query(selector).each(function(el) {
  3905. DOM.remove(el.childNodes);
  3906. });
  3907. },
  3908. _nl2frag:nl2frag
  3909. });
  3910. function processAll(fn, elem, clone) {
  3911. if (nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  3912. var eCs = elem.childNodes,
  3913. cloneCs = clone.childNodes,
  3914. fIndex = 0;
  3915. while (eCs[fIndex]) {
  3916. if (cloneCs[fIndex]) {
  3917. processAll(fn, eCs[fIndex], cloneCs[fIndex]);
  3918. }
  3919. fIndex++;
  3920. }
  3921. } else if (isElementNode(elem)) {
  3922. var elemChildren = getElementsByTagName(elem, "*"),
  3923. cloneChildren = getElementsByTagName(clone, "*"),
  3924. cIndex = 0;
  3925. while (elemChildren[cIndex]) {
  3926. if (cloneChildren[cIndex]) {
  3927. fn(elemChildren[cIndex], cloneChildren[cIndex]);
  3928. }
  3929. cIndex++;
  3930. }
  3931. }
  3932. }
  3933. // 克隆除了事件的 data
  3934. function cloneWidthDataAndEvent(src, dest) {
  3935. var Event = S.require('event');
  3936. if (isElementNode(dest) && !DOM.hasData(src)) {
  3937. return;
  3938. }
  3939. var srcData = DOM.data(src);
  3940. // 浅克隆,data 也放在克隆节点上
  3941. for (var d in srcData) {
  3942. DOM.data(dest, d, srcData[d]);
  3943. }
  3944. // 事件要特殊点
  3945. if (Event) {
  3946. // _removeData 不需要?刚克隆出来本来就没
  3947. Event._removeData(dest);
  3948. Event._clone(src, dest);
  3949. }
  3950. }
  3951. // wierd ie cloneNode fix from jq
  3952. function fixAttributes(src, dest) {
  3953. // clearAttributes removes the attributes, which we don't want,
  3954. // but also removes the attachEvent events, which we *do* want
  3955. if (dest.clearAttributes) {
  3956. dest.clearAttributes();
  3957. }
  3958. // mergeAttributes, in contrast, only merges back on the
  3959. // original attributes, not the events
  3960. if (dest.mergeAttributes) {
  3961. dest.mergeAttributes(src);
  3962. }
  3963. var nodeName = dest.nodeName.toLowerCase(),
  3964. srcChilds = src.childNodes;
  3965. // IE6-8 fail to clone children inside object elements that use
  3966. // the proprietary classid attribute value (rather than the type
  3967. // attribute) to identify the type of content to display
  3968. if (nodeName === "object" && !dest.childNodes.length) {
  3969. for (var i = 0; i < srcChilds.length; i++) {
  3970. dest.appendChild(srcChilds[i].cloneNode(true));
  3971. }
  3972. // dest.outerHTML = src.outerHTML;
  3973. } else if (nodeName === "input" && (src.type === "checkbox" || src.type === "radio")) {
  3974. // IE6-8 fails to persist the checked state of a cloned checkbox
  3975. // or radio button. Worse, IE6-7 fail to give the cloned element
  3976. // a checked appearance if the defaultChecked value isn't also set
  3977. if (src.checked) {
  3978. dest['defaultChecked'] = dest.checked = src.checked;
  3979. }
  3980. // IE6-7 get confused and end up setting the value of a cloned
  3981. // checkbox/radio button to an empty string instead of "on"
  3982. if (dest.value !== src.value) {
  3983. dest.value = src.value;
  3984. }
  3985. // IE6-8 fails to return the selected option to the default selected
  3986. // state when cloning options
  3987. } else if (nodeName === "option") {
  3988. dest.selected = src.defaultSelected;
  3989. // IE6-8 fails to set the defaultValue to the correct value when
  3990. // cloning other types of input fields
  3991. } else if (nodeName === "input" || nodeName === "textarea") {
  3992. dest.defaultValue = src.defaultValue;
  3993. }
  3994. // Event data gets referenced instead of copied if the expando
  3995. // gets copied too
  3996. // 自定义 data 根据参数特殊处理,expando 只是个用于引用的属性
  3997. dest.removeAttribute(DOM.__EXPANDO);
  3998. }
  3999. // 添加成员到元素中
  4000. function attachProps(elem, props) {
  4001. if (S.isPlainObject(props)) {
  4002. if (isElementNode(elem)) {
  4003. DOM.attr(elem, props, true);
  4004. }
  4005. // document fragment
  4006. else if (nodeTypeIs(elem, DOM.DOCUMENT_FRAGMENT_NODE)) {
  4007. DOM.attr(elem.childNodes, props, true);
  4008. }
  4009. }
  4010. return elem;
  4011. }
  4012. // 将 nodeList 转换为 fragment
  4013. function nl2frag(nodes, ownerDoc) {
  4014. var ret = null, i, len;
  4015. if (nodes
  4016. && (nodes.push || nodes.item)
  4017. && nodes[0]) {
  4018. ownerDoc = ownerDoc || nodes[0].ownerDocument;
  4019. ret = ownerDoc.createDocumentFragment();
  4020. nodes = S.makeArray(nodes);
  4021. for (i = 0,len = nodes.length; i < len; i++) {
  4022. ret.appendChild(nodes[i]);
  4023. }
  4024. }
  4025. else {
  4026. S.log('Unable to convert ' + nodes + ' to fragment.');
  4027. }
  4028. return ret;
  4029. }
  4030. // only for gecko and ie
  4031. // 2010-10-22: 发现 chrome 也与 gecko 的处理一致了
  4032. //if (ie || UA['gecko'] || UA['webkit']) {
  4033. // 定义 creators, 处理浏览器兼容
  4034. var creators = DOM._creators,
  4035. create = DOM.create,
  4036. TABLE_OPEN = '<table>',
  4037. TABLE_CLOSE = '<' + '/table>',
  4038. RE_TBODY = /(?:\/(?:thead|tfoot|caption|col|colgroup)>)+\s*<tbody/,
  4039. creatorsMap = {
  4040. option: 'select',
  4041. optgroup:'select',
  4042. area:'map',
  4043. thead:'table',
  4044. td: 'tr',
  4045. th:'tr',
  4046. tr: 'tbody',
  4047. tbody: 'table',
  4048. tfoot:'table',
  4049. caption:'table',
  4050. colgroup:'table',
  4051. col: 'colgroup',
  4052. legend: 'fieldset' // ie 支持,但 gecko 不支持
  4053. };
  4054. for (var p in creatorsMap) {
  4055. (function(tag) {
  4056. creators[p] = function(html, ownerDoc) {
  4057. return create('<' + tag + '>' + html + '<' + '/' + tag + '>', null, ownerDoc);
  4058. }
  4059. })(creatorsMap[p]);
  4060. }
  4061. // IE7- adds TBODY when creating thead/tfoot/caption/col/colgroup elements
  4062. if (ie < 8) {
  4063. creators.tbody = function(html, ownerDoc) {
  4064. var frag = create(TABLE_OPEN + html + TABLE_CLOSE, null, ownerDoc),
  4065. tbody = frag.children['tags']('tbody')[0];
  4066. if (frag.children.length > 1 && tbody && !RE_TBODY.test(html)) {
  4067. tbody[PARENT_NODE].removeChild(tbody); // strip extraneous tbody
  4068. }
  4069. return frag;
  4070. };
  4071. }
  4072. // fix table elements
  4073. S.mix(creators, {
  4074. thead: creators.tbody,
  4075. tfoot: creators.tbody,
  4076. caption: creators.tbody,
  4077. colgroup: creators.tbody
  4078. });
  4079. //}
  4080. return DOM;
  4081. },
  4082. {
  4083. requires:["./base","ua"]
  4084. });
  4085. /**
  4086. * 2011-10-13
  4087. * empty , html refactor
  4088. *
  4089. * 2011-08-22
  4090. * clone 实现,参考 jq
  4091. *
  4092. * 2011-08
  4093. * remove 需要对子孙节点以及自身清除事件以及自定义 data
  4094. * create 修改,支持 <style></style> ie 下直接创建
  4095. * TODO: jquery clone ,clean 实现
  4096. *
  4097. * TODO:
  4098. * - 研究 jQuery 的 buildFragment 和 clean
  4099. * - 增加 cache, 完善 test cases
  4100. * - 支持更多 props
  4101. * - remove 时,是否需要移除事件,以避免内存泄漏?需要详细的测试。
  4102. */
  4103. /**
  4104. * @fileOverview dom-data
  4105. * @author lifesinger@gmail.com,yiminghe@gmail.com
  4106. */
  4107. KISSY.add('dom/data', function (S, DOM, undefined) {
  4108. var win = window,
  4109. EXPANDO = '_ks_data_' + S.now(), // 让每一份 kissy 的 expando 都不同
  4110. dataCache = { }, // 存储 node 节点的 data
  4111. winDataCache = { }; // 避免污染全局
  4112. // The following elements throw uncatchable exceptions if you
  4113. // attempt to add expando properties to them.
  4114. var noData = {
  4115. };
  4116. noData['applet'] = 1;
  4117. noData['object'] = 1;
  4118. noData['embed'] = 1;
  4119. var commonOps = {
  4120. hasData:function (cache, name) {
  4121. if (cache) {
  4122. if (name !== undefined) {
  4123. if (name in cache) {
  4124. return true;
  4125. }
  4126. } else if (!S.isEmptyObject(cache)) {
  4127. return true;
  4128. }
  4129. }
  4130. return false;
  4131. }
  4132. };
  4133. var objectOps = {
  4134. hasData:function (ob, name) {
  4135. // 只判断当前窗口,iframe 窗口内数据直接放入全局变量
  4136. if (ob == win) {
  4137. return objectOps.hasData(winDataCache, name);
  4138. }
  4139. // 直接建立在对象内
  4140. var thisCache = ob[EXPANDO];
  4141. return commonOps.hasData(thisCache, name);
  4142. },
  4143. data:function (ob, name, value) {
  4144. if (ob == win) {
  4145. return objectOps.data(winDataCache, name, value);
  4146. }
  4147. var cache = ob[EXPANDO];
  4148. if (value !== undefined) {
  4149. cache = ob[EXPANDO] = ob[EXPANDO] || {};
  4150. cache[name] = value;
  4151. } else {
  4152. if (name !== undefined) {
  4153. return cache && cache[name];
  4154. } else {
  4155. cache = ob[EXPANDO] = ob[EXPANDO] || {};
  4156. return cache;
  4157. }
  4158. }
  4159. },
  4160. removeData:function (ob, name) {
  4161. if (ob == win) {
  4162. return objectOps.removeData(winDataCache, name);
  4163. }
  4164. var cache = ob[EXPANDO];
  4165. if (name !== undefined) {
  4166. delete cache[name];
  4167. if (S.isEmptyObject(cache)) {
  4168. objectOps.removeData(ob);
  4169. }
  4170. } else {
  4171. try {
  4172. // ob maybe window in iframe
  4173. // ie will throw error
  4174. delete ob[EXPANDO];
  4175. } catch (e) {
  4176. ob[EXPANDO] = undefined;
  4177. }
  4178. }
  4179. }
  4180. };
  4181. var domOps = {
  4182. hasData:function (elem, name) {
  4183. var key = elem[EXPANDO];
  4184. if (!key) {
  4185. return false;
  4186. }
  4187. var thisCache = dataCache[key];
  4188. return commonOps.hasData(thisCache, name);
  4189. },
  4190. data:function (elem, name, value) {
  4191. if (noData[elem.nodeName.toLowerCase()]) {
  4192. return undefined;
  4193. }
  4194. var key = elem[EXPANDO], cache;
  4195. if (!key) {
  4196. // 根本不用附加属性
  4197. if (name !== undefined &&
  4198. value === undefined) {
  4199. return undefined;
  4200. }
  4201. // 节点上关联键值也可以
  4202. key = elem[EXPANDO] = S.guid();
  4203. }
  4204. cache = dataCache[key];
  4205. if (value !== undefined) {
  4206. // 需要新建
  4207. cache = dataCache[key] = dataCache[key] || {};
  4208. cache[name] = value;
  4209. } else {
  4210. if (name !== undefined) {
  4211. return cache && cache[name];
  4212. } else {
  4213. // 需要新建
  4214. cache = dataCache[key] = dataCache[key] || {};
  4215. return cache;
  4216. }
  4217. }
  4218. },
  4219. removeData:function (elem, name) {
  4220. var key = elem[EXPANDO], cache;
  4221. if (!key) {
  4222. return;
  4223. }
  4224. cache = dataCache[key];
  4225. if (name !== undefined) {
  4226. delete cache[name];
  4227. if (S.isEmptyObject(cache)) {
  4228. domOps.removeData(elem);
  4229. }
  4230. } else {
  4231. delete dataCache[key];
  4232. try {
  4233. delete elem[EXPANDO];
  4234. } catch (e) {
  4235. elem[EXPANDO] = undefined;
  4236. //S.log("delete expando error : ");
  4237. //S.log(e);
  4238. }
  4239. if (elem.removeAttribute) {
  4240. elem.removeAttribute(EXPANDO);
  4241. }
  4242. }
  4243. }
  4244. };
  4245. S.mix(DOM,
  4246. /**
  4247. * @lends DOM
  4248. */
  4249. {
  4250. __EXPANDO:EXPANDO,
  4251. /**
  4252. * whether any node has data
  4253. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4254. * @param {String} name 数据键名
  4255. * @returns {boolean} 节点是否有关联数据键名的值
  4256. */
  4257. hasData:function (selector, name) {
  4258. var ret = false, elems = DOM.query(selector);
  4259. for (var i = 0; i < elems.length; i++) {
  4260. var elem = elems[i];
  4261. if (checkIsNode(elem)) {
  4262. ret = domOps.hasData(elem, name);
  4263. } else {
  4264. ret = objectOps.hasData(elem, name);
  4265. }
  4266. if (ret) {
  4267. return ret;
  4268. }
  4269. }
  4270. return ret;
  4271. },
  4272. /**
  4273. * Store arbitrary data associated with the matched elements.
  4274. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4275. * @param {String} [name] 数据键名
  4276. * @param {String} [data] 数据键值
  4277. * @returns 当不设置 data,设置 name 那么返回: 节点是否有关联数据键名的值
  4278. * 当不设置 data, name 那么返回: 节点的存储空间对象
  4279. * 当设置 data, name 那么进行设置操作,返回 undefined
  4280. */
  4281. data:function (selector, name, data) {
  4282. // suports hash
  4283. if (S.isPlainObject(name)) {
  4284. for (var k in name) {
  4285. DOM.data(selector, k, name[k]);
  4286. }
  4287. return undefined;
  4288. }
  4289. // getter
  4290. if (data === undefined) {
  4291. var elem = DOM.get(selector);
  4292. if (checkIsNode(elem)) {
  4293. return domOps.data(elem, name, data);
  4294. } else if (elem) {
  4295. return objectOps.data(elem, name, data);
  4296. }
  4297. }
  4298. // setter
  4299. else {
  4300. DOM.query(selector).each(function (elem) {
  4301. if (checkIsNode(elem)) {
  4302. domOps.data(elem, name, data);
  4303. } else {
  4304. objectOps.data(elem, name, data);
  4305. }
  4306. });
  4307. }
  4308. return undefined;
  4309. },
  4310. /**
  4311. * Remove a previously-stored piece of data.
  4312. * @param {HTMLElement[]|String} selector 选择器或节点数组
  4313. * @param {String} [name] 数据键名,不设置时删除关联节点的所有键值对
  4314. */
  4315. removeData:function (selector, name) {
  4316. DOM.query(selector).each(function (elem) {
  4317. if (checkIsNode(elem)) {
  4318. domOps.removeData(elem, name);
  4319. } else {
  4320. objectOps.removeData(elem, name);
  4321. }
  4322. });
  4323. }
  4324. });
  4325. function checkIsNode(elem) {
  4326. // note : 普通对象不要定义 nodeType 这种特殊属性!
  4327. return elem && elem.nodeType;
  4328. }
  4329. return DOM;
  4330. }, {
  4331. requires:["./base"]
  4332. });
  4333. /**
  4334. * 承玉:2011-05-31
  4335. * - 分层 ,节点和普通对象分开处理
  4336. **/
  4337. /**
  4338. * @module dom-insertion
  4339. * @author yiminghe@gmail.com,lifesinger@gmail.com
  4340. */
  4341. KISSY.add('dom/insertion', function(S, UA, DOM) {
  4342. var PARENT_NODE = 'parentNode',
  4343. rformEls = /^(?:button|input|object|select|textarea)$/i,
  4344. nodeName = DOM._nodeName,
  4345. makeArray = S.makeArray,
  4346. _isElementNode = DOM._isElementNode,
  4347. NEXT_SIBLING = 'nextSibling';
  4348. /**
  4349. ie 6,7 lose checked status when append to dom
  4350. var c=S.all("<input />");
  4351. c.attr("type","radio");
  4352. c.attr("checked",true);
  4353. S.all("#t").append(c);
  4354. alert(c[0].checked);
  4355. */
  4356. function fixChecked(ret) {
  4357. for (var i = 0; i < ret.length; i++) {
  4358. var el = ret[i];
  4359. if (el.nodeType == DOM.DOCUMENT_FRAGMENT_NODE) {
  4360. fixChecked(el.childNodes);
  4361. } else if (nodeName(el, "input")) {
  4362. fixCheckedInternal(el);
  4363. } else if (_isElementNode(el)) {
  4364. var cs = el.getElementsByTagName("input");
  4365. for (var j = 0; j < cs.length; j++) {
  4366. fixChecked(cs[j]);
  4367. }
  4368. }
  4369. }
  4370. }
  4371. function fixCheckedInternal(el) {
  4372. if (el.type === "checkbox" || el.type === "radio") {
  4373. // after insert , in ie6/7 checked is decided by defaultChecked !
  4374. el.defaultChecked = el.checked;
  4375. }
  4376. }
  4377. var rscriptType = /\/(java|ecma)script/i;
  4378. function isJs(el) {
  4379. return !el.type || rscriptType.test(el.type);
  4380. }
  4381. // extract script nodes and execute alone later
  4382. function filterScripts(nodes, scripts) {
  4383. var ret = [],i,el,nodeName;
  4384. for (i = 0; nodes[i]; i++) {
  4385. el = nodes[i];
  4386. nodeName = el.nodeName.toLowerCase();
  4387. if (el.nodeType == DOM.DOCUMENT_FRAGMENT_NODE) {
  4388. ret.push.apply(ret, filterScripts(makeArray(el.childNodes), scripts));
  4389. } else if (nodeName === "script" && isJs(el)) {
  4390. // remove script to make sure ie9 does not invoke when append
  4391. if (el.parentNode) {
  4392. el.parentNode.removeChild(el)
  4393. }
  4394. if (scripts) {
  4395. scripts.push(el);
  4396. }
  4397. } else {
  4398. if (_isElementNode(el) &&
  4399. // ie checkbox getElementsByTagName 后造成 checked 丢失
  4400. !rformEls.test(nodeName)) {
  4401. var tmp = [],
  4402. s,
  4403. j,
  4404. ss = el.getElementsByTagName("script");
  4405. for (j = 0; j < ss.length; j++) {
  4406. s = ss[j];
  4407. if (isJs(s)) {
  4408. tmp.push(s);
  4409. }
  4410. }
  4411. nodes.splice.apply(nodes, [i + 1,0].concat(tmp));
  4412. }
  4413. ret.push(el);
  4414. }
  4415. }
  4416. return ret;
  4417. }
  4418. // execute script
  4419. function evalScript(el) {
  4420. if (el.src) {
  4421. S.getScript(el.src);
  4422. } else {
  4423. var code = S.trim(el.text || el.textContent || el.innerHTML || "");
  4424. if (code) {
  4425. S.globalEval(code);
  4426. }
  4427. }
  4428. }
  4429. // fragment is easier than nodelist
  4430. function insertion(newNodes, refNodes, fn, scripts) {
  4431. newNodes = DOM.query(newNodes);
  4432. if (scripts) {
  4433. scripts = [];
  4434. }
  4435. // filter script nodes ,process script separately if needed
  4436. newNodes = filterScripts(newNodes, scripts);
  4437. // Resets defaultChecked for any radios and checkboxes
  4438. // about to be appended to the DOM in IE 6/7
  4439. if (UA['ie'] < 8) {
  4440. fixChecked(newNodes);
  4441. }
  4442. refNodes = DOM.query(refNodes);
  4443. var newNodesLength = newNodes.length,
  4444. refNodesLength = refNodes.length;
  4445. if ((!newNodesLength &&
  4446. (!scripts || !scripts.length)) ||
  4447. !refNodesLength) {
  4448. return;
  4449. }
  4450. // fragment 插入速度快点
  4451. var newNode = DOM._nl2frag(newNodes),
  4452. clonedNode;
  4453. //fragment 一旦插入里面就空了,先复制下
  4454. if (refNodesLength > 1) {
  4455. clonedNode = DOM.clone(newNode, true);
  4456. }
  4457. for (var i = 0; i < refNodesLength; i++) {
  4458. var refNode = refNodes[i];
  4459. if (newNodesLength) {
  4460. //refNodes 超过一个,clone
  4461. var node = i > 0 ? DOM.clone(clonedNode, true) : newNode;
  4462. fn(node, refNode);
  4463. }
  4464. if (scripts && scripts.length) {
  4465. S.each(scripts, evalScript);
  4466. }
  4467. }
  4468. }
  4469. // loadScripts default to false to prevent xss
  4470. S.mix(DOM, {
  4471. /**
  4472. * Inserts the new node as the previous sibling of the reference node.
  4473. */
  4474. insertBefore: function(newNodes, refNodes, loadScripts) {
  4475. insertion(newNodes, refNodes, function(newNode, refNode) {
  4476. if (refNode[PARENT_NODE]) {
  4477. refNode[PARENT_NODE].insertBefore(newNode, refNode);
  4478. }
  4479. }, loadScripts);
  4480. },
  4481. /**
  4482. * Inserts the new node as the next sibling of the reference node.
  4483. */
  4484. insertAfter: function(newNodes, refNodes, loadScripts) {
  4485. insertion(newNodes, refNodes, function(newNode, refNode) {
  4486. if (refNode[PARENT_NODE]) {
  4487. refNode[PARENT_NODE].insertBefore(newNode, refNode[NEXT_SIBLING]);
  4488. }
  4489. }, loadScripts);
  4490. },
  4491. /**
  4492. * Inserts the new node as the last child.
  4493. */
  4494. appendTo: function(newNodes, parents, loadScripts) {
  4495. insertion(newNodes, parents, function(newNode, parent) {
  4496. parent.appendChild(newNode);
  4497. }, loadScripts);
  4498. },
  4499. /**
  4500. * Inserts the new node as the first child.
  4501. */
  4502. prependTo:function(newNodes, parents, loadScripts) {
  4503. insertion(newNodes, parents, function(newNode, parent) {
  4504. parent.insertBefore(newNode, parent.firstChild);
  4505. }, loadScripts);
  4506. }
  4507. });
  4508. var alias = {
  4509. "prepend":"prependTo",
  4510. "append":"appendTo",
  4511. "before":"insertBefore",
  4512. "after":"insertAfter"
  4513. };
  4514. for (var a in alias) {
  4515. DOM[a] = DOM[alias[a]];
  4516. }
  4517. return DOM;
  4518. }, {
  4519. requires:["ua","./create"]
  4520. });
  4521. /**
  4522. * 2011-05-25
  4523. * - 承玉:参考 jquery 处理多对多的情形 :http://api.jquery.com/append/
  4524. * DOM.append(".multi1",".multi2");
  4525. *
  4526. */
  4527. /**
  4528. * @module dom-offset
  4529. * @author lifesinger@gmail.com,yiminghe@gmail.com
  4530. */
  4531. KISSY.add('dom/offset', function(S, DOM, UA, undefined) {
  4532. var win = window,
  4533. doc = document,
  4534. isIE = UA['ie'],
  4535. docElem = doc.documentElement,
  4536. isElementNode = DOM._isElementNode,
  4537. nodeTypeIs = DOM._nodeTypeIs,
  4538. getWin = DOM._getWin,
  4539. CSS1Compat = "CSS1Compat",
  4540. compatMode = "compatMode",
  4541. isStrict = doc[compatMode] === CSS1Compat,
  4542. MAX = Math.max,
  4543. PARSEINT = parseInt,
  4544. POSITION = 'position',
  4545. RELATIVE = 'relative',
  4546. DOCUMENT = 'document',
  4547. BODY = 'body',
  4548. DOC_ELEMENT = 'documentElement',
  4549. OWNER_DOCUMENT = 'ownerDocument',
  4550. VIEWPORT = 'viewport',
  4551. SCROLL = 'scroll',
  4552. CLIENT = 'client',
  4553. LEFT = 'left',
  4554. TOP = 'top',
  4555. isNumber = S.isNumber,
  4556. SCROLL_LEFT = SCROLL + 'Left',
  4557. SCROLL_TOP = SCROLL + 'Top',
  4558. GET_BOUNDING_CLIENT_RECT = 'getBoundingClientRect';
  4559. // ownerDocument 的判断不保证 elem 没有游离在 document 之外(比如 fragment)
  4560. // function inDocument(elem) {
  4561. // if (!elem) {
  4562. // return 0;
  4563. // }
  4564. // var doc = elem.ownerDocument;
  4565. // if (!doc) {
  4566. // return 0;
  4567. // }
  4568. // var html = doc.documentElement;
  4569. // if (html === elem) {
  4570. // return true;
  4571. // }
  4572. // else if (DOM.__contains(html, elem)) {
  4573. // return true;
  4574. // }
  4575. // return false;
  4576. // }
  4577. S.mix(DOM, {
  4578. /**
  4579. * Gets the current coordinates of the element, relative to the document.
  4580. * @param relativeWin The window to measure relative to. If relativeWin
  4581. * is not in the ancestor frame chain of the element, we measure relative to
  4582. * the top-most window.
  4583. */
  4584. offset: function(selector, val, relativeWin) {
  4585. // getter
  4586. if (val === undefined) {
  4587. var elem = DOM.get(selector),ret;
  4588. if (elem) {
  4589. ret = getOffset(elem, relativeWin);
  4590. }
  4591. return ret;
  4592. }
  4593. // setter
  4594. DOM.query(selector).each(function(elem) {
  4595. setOffset(elem, val);
  4596. });
  4597. },
  4598. /**
  4599. * Makes elem visible in the container
  4600. * @param elem
  4601. * @param container
  4602. * @param top
  4603. * @param hscroll
  4604. * @param {Boolean} auto whether adjust element automatically
  4605. * (it only scrollIntoView when element is out of view)
  4606. * @refer http://www.w3.org/TR/2009/WD-html5-20090423/editing.html#scrollIntoView
  4607. * http://www.sencha.com/deploy/dev/docs/source/Element.scroll-more.html#scrollIntoView
  4608. * http://yiminghe.javaeye.com/blog/390732
  4609. */
  4610. scrollIntoView: function(elem, container, top, hscroll, auto) {
  4611. if (!(elem = DOM.get(elem))) {
  4612. return;
  4613. }
  4614. if (container) {
  4615. container = DOM.get(container);
  4616. }
  4617. if (!container) {
  4618. container = elem.ownerDocument;
  4619. }
  4620. if (auto !== true) {
  4621. hscroll = hscroll === undefined ? true : !!hscroll;
  4622. top = top === undefined ? true : !!top;
  4623. }
  4624. // document 归一化到 window
  4625. if (nodeTypeIs(container, DOM.DOCUMENT_NODE)) {
  4626. container = getWin(container);
  4627. }
  4628. var isWin = !!getWin(container),
  4629. elemOffset = DOM.offset(elem),
  4630. eh = DOM.outerHeight(elem),
  4631. ew = DOM.outerWidth(elem),
  4632. containerOffset,
  4633. ch,
  4634. cw,
  4635. containerScroll,
  4636. diffTop,
  4637. diffBottom,
  4638. win,
  4639. winScroll,
  4640. ww,
  4641. wh;
  4642. if (isWin) {
  4643. win = container;
  4644. wh = DOM.height(win);
  4645. ww = DOM.width(win);
  4646. winScroll = {
  4647. left:DOM.scrollLeft(win),
  4648. top:DOM.scrollTop(win)
  4649. };
  4650. // elem 相对 container 可视视窗的距离
  4651. diffTop = {
  4652. left: elemOffset[LEFT] - winScroll[LEFT],
  4653. top: elemOffset[TOP] - winScroll[TOP]
  4654. };
  4655. diffBottom = {
  4656. left: elemOffset[LEFT] + ew - (winScroll[LEFT] + ww),
  4657. top:elemOffset[TOP] + eh - (winScroll[TOP] + wh)
  4658. };
  4659. containerScroll = winScroll;
  4660. }
  4661. else {
  4662. containerOffset = DOM.offset(container);
  4663. ch = container.clientHeight;
  4664. cw = container.clientWidth;
  4665. containerScroll = {
  4666. left:DOM.scrollLeft(container),
  4667. top:DOM.scrollTop(container)
  4668. };
  4669. // elem 相对 container 可视视窗的距离
  4670. // 注意边框 , offset 是边框到根节点
  4671. diffTop = {
  4672. left: elemOffset[LEFT] - containerOffset[LEFT] -
  4673. (PARSEINT(DOM.css(container, 'borderLeftWidth')) || 0),
  4674. top: elemOffset[TOP] - containerOffset[TOP] -
  4675. (PARSEINT(DOM.css(container, 'borderTopWidth')) || 0)
  4676. };
  4677. diffBottom = {
  4678. left: elemOffset[LEFT] + ew -
  4679. (containerOffset[LEFT] + cw +
  4680. (PARSEINT(DOM.css(container, 'borderRightWidth')) || 0)) ,
  4681. top:elemOffset[TOP] + eh -
  4682. (containerOffset[TOP] + ch +
  4683. (PARSEINT(DOM.css(container, 'borderBottomWidth')) || 0))
  4684. };
  4685. }
  4686. if (diffTop.top < 0 || diffBottom.top > 0) {
  4687. // 强制向上
  4688. if (top === true) {
  4689. DOM.scrollTop(container, containerScroll.top + diffTop.top);
  4690. } else if (top === false) {
  4691. DOM.scrollTop(container, containerScroll.top + diffBottom.top);
  4692. } else {
  4693. // 自动调整
  4694. if (diffTop.top < 0) {
  4695. DOM.scrollTop(container, containerScroll.top + diffTop.top);
  4696. } else {
  4697. DOM.scrollTop(container, containerScroll.top + diffBottom.top);
  4698. }
  4699. }
  4700. }
  4701. if (hscroll) {
  4702. if (diffTop.left < 0 || diffBottom.left > 0) {
  4703. // 强制向上
  4704. if (top === true) {
  4705. DOM.scrollLeft(container, containerScroll.left + diffTop.left);
  4706. } else if (top === false) {
  4707. DOM.scrollLeft(container, containerScroll.left + diffBottom.left);
  4708. } else {
  4709. // 自动调整
  4710. if (diffTop.left < 0) {
  4711. DOM.scrollLeft(container, containerScroll.left + diffTop.left);
  4712. } else {
  4713. DOM.scrollLeft(container, containerScroll.left + diffBottom.left);
  4714. }
  4715. }
  4716. }
  4717. }
  4718. },
  4719. /**
  4720. * for idea autocomplete
  4721. */
  4722. docWidth:0,
  4723. docHeight:0,
  4724. viewportHeight:0,
  4725. viewportWidth:0
  4726. });
  4727. // http://old.jr.pl/www.quirksmode.org/viewport/compatibility.html
  4728. // http://www.quirksmode.org/dom/w3c_cssom.html
  4729. // add ScrollLeft/ScrollTop getter/setter methods
  4730. S.each(['Left', 'Top'], function(name, i) {
  4731. var method = SCROLL + name;
  4732. DOM[method] = function(elem, v) {
  4733. if (isNumber(elem)) {
  4734. return arguments.callee(win, elem);
  4735. }
  4736. elem = DOM.get(elem);
  4737. var ret,
  4738. w = getWin(elem),
  4739. d;
  4740. if (w) {
  4741. if (v !== undefined) {
  4742. v = parseFloat(v);
  4743. // 注意多 windw 情况,不能简单取 win
  4744. var left = name == "Left" ? v : DOM.scrollLeft(w),
  4745. top = name == "Top" ? v : DOM.scrollTop(w);
  4746. w['scrollTo'](left, top);
  4747. } else {
  4748. //标准
  4749. //chrome == body.scrollTop
  4750. //firefox/ie9 == documentElement.scrollTop
  4751. ret = w[ 'page' + (i ? 'Y' : 'X') + 'Offset'];
  4752. if (!isNumber(ret)) {
  4753. d = w[DOCUMENT];
  4754. //ie6,7,8 standard mode
  4755. ret = d[DOC_ELEMENT][method];
  4756. if (!isNumber(ret)) {
  4757. //quirks mode
  4758. ret = d[BODY][method];
  4759. }
  4760. }
  4761. }
  4762. } else if (isElementNode(elem)) {
  4763. if (v !== undefined) {
  4764. elem[method] = parseFloat(v)
  4765. } else {
  4766. ret = elem[method];
  4767. }
  4768. }
  4769. return ret;
  4770. }
  4771. });
  4772. // add docWidth/Height, viewportWidth/Height getter methods
  4773. S.each(['Width', 'Height'], function(name) {
  4774. DOM['doc' + name] = function(refWin) {
  4775. refWin = DOM.get(refWin);
  4776. var w = getWin(refWin),
  4777. d = w[DOCUMENT];
  4778. return MAX(
  4779. //firefox chrome documentElement.scrollHeight< body.scrollHeight
  4780. //ie standard mode : documentElement.scrollHeight> body.scrollHeight
  4781. d[DOC_ELEMENT][SCROLL + name],
  4782. //quirks : documentElement.scrollHeight 最大等于可视窗口多一点?
  4783. d[BODY][SCROLL + name],
  4784. DOM[VIEWPORT + name](d));
  4785. };
  4786. DOM[VIEWPORT + name] = function(refWin) {
  4787. refWin = DOM.get(refWin);
  4788. var prop = CLIENT + name,
  4789. win = getWin(refWin),
  4790. doc = win[DOCUMENT],
  4791. body = doc[BODY],
  4792. documentElement = doc[DOC_ELEMENT],
  4793. documentElementProp = documentElement[prop];
  4794. // 标准模式取 documentElement
  4795. // backcompat 取 body
  4796. return doc[compatMode] === CSS1Compat
  4797. && documentElementProp ||
  4798. body && body[ prop ] || documentElementProp;
  4799. // return (prop in w) ?
  4800. // // 标准 = documentElement.clientHeight
  4801. // w[prop] :
  4802. // // ie 标准 documentElement.clientHeight , 在 documentElement.clientHeight 上滚动?
  4803. // // ie quirks body.clientHeight: 在 body 上?
  4804. // (isStrict ? d[DOC_ELEMENT][CLIENT + name] : d[BODY][CLIENT + name]);
  4805. }
  4806. });
  4807. function getClientPosition(elem) {
  4808. var box, x = 0, y = 0,
  4809. body = doc.body,
  4810. w = getWin(elem[OWNER_DOCUMENT]);
  4811. // 根据 GBS 最新数据,A-Grade Browsers 都已支持 getBoundingClientRect 方法,不用再考虑传统的实现方式
  4812. if (elem[GET_BOUNDING_CLIENT_RECT]) {
  4813. box = elem[GET_BOUNDING_CLIENT_RECT]();
  4814. // 注:jQuery 还考虑减去 docElem.clientLeft/clientTop
  4815. // 但测试发现,这样反而会导致当 html 和 body 有边距/边框样式时,获取的值不正确
  4816. // 此外,ie6 会忽略 html 的 margin 值,幸运地是没有谁会去设置 html 的 margin
  4817. x = box[LEFT];
  4818. y = box[TOP];
  4819. // ie 下应该减去窗口的边框吧,毕竟默认 absolute 都是相对窗口定位的
  4820. // 窗口边框标准是设 documentElement ,quirks 时设置 body
  4821. // 最好禁止在 body 和 html 上边框 ,但 ie < 9 html 默认有 2px ,减去
  4822. // 但是非 ie 不可能设置窗口边框,body html 也不是窗口 ,ie 可以通过 html,body 设置
  4823. // 标准 ie 下 docElem.clientTop 就是 border-top
  4824. // ie7 html 即窗口边框改变不了。永远为 2
  4825. // 但标准 firefox/chrome/ie9 下 docElem.clientTop 是窗口边框,即使设了 border-top 也为 0
  4826. var clientTop = isIE && doc['documentMode'] != 9
  4827. && (isStrict ? docElem.clientTop : body.clientTop)
  4828. || 0,
  4829. clientLeft = isIE && doc['documentMode'] != 9
  4830. && (isStrict ? docElem.clientLeft : body.clientLeft)
  4831. || 0;
  4832. if (1 > 2) {
  4833. }
  4834. x -= clientLeft;
  4835. y -= clientTop;
  4836. // iphone/ipad/itouch 下的 Safari 获取 getBoundingClientRect 时,已经加入 scrollTop
  4837. if (UA.mobile == 'apple') {
  4838. x -= DOM[SCROLL_LEFT](w);
  4839. y -= DOM[SCROLL_TOP](w);
  4840. }
  4841. }
  4842. return { left: x, top: y };
  4843. }
  4844. function getPageOffset(el) {
  4845. var pos = getClientPosition(el);
  4846. var w = getWin(el[OWNER_DOCUMENT]);
  4847. pos.left += DOM[SCROLL_LEFT](w);
  4848. pos.top += DOM[SCROLL_TOP](w);
  4849. return pos;
  4850. }
  4851. // 获取 elem 相对 elem.ownerDocument 的坐标
  4852. function getOffset(el, relativeWin) {
  4853. var position = {left:0,top:0};
  4854. // Iterate up the ancestor frame chain, keeping track of the current window
  4855. // and the current element in that window.
  4856. var currentWin = getWin(el[OWNER_DOCUMENT]);
  4857. var currentEl = el;
  4858. relativeWin = relativeWin || currentWin;
  4859. do {
  4860. // if we're at the top window, we want to get the page offset.
  4861. // if we're at an inner frame, we only want to get the window position
  4862. // so that we can determine the actual page offset in the context of
  4863. // the outer window.
  4864. var offset = currentWin == relativeWin ?
  4865. getPageOffset(currentEl) :
  4866. getClientPosition(currentEl);
  4867. position.left += offset.left;
  4868. position.top += offset.top;
  4869. } while (currentWin && currentWin != relativeWin &&
  4870. (currentEl = currentWin['frameElement']) &&
  4871. (currentWin = currentWin.parent));
  4872. return position;
  4873. }
  4874. // 设置 elem 相对 elem.ownerDocument 的坐标
  4875. function setOffset(elem, offset) {
  4876. // set position first, in-case top/left are set even on static elem
  4877. if (DOM.css(elem, POSITION) === 'static') {
  4878. elem.style[POSITION] = RELATIVE;
  4879. }
  4880. var old = getOffset(elem), ret = { }, current, key;
  4881. for (key in offset) {
  4882. current = PARSEINT(DOM.css(elem, key), 10) || 0;
  4883. ret[key] = current + offset[key] - old[key];
  4884. }
  4885. DOM.css(elem, ret);
  4886. }
  4887. return DOM;
  4888. }, {
  4889. requires:["./base","ua"]
  4890. });
  4891. /**
  4892. * 2011-05-24
  4893. * - 承玉:
  4894. * - 调整 docWidth , docHeight ,
  4895. * viewportHeight , viewportWidth ,scrollLeft,scrollTop 参数,
  4896. * 便于放置到 Node 中去,可以完全摆脱 DOM,完全使用 Node
  4897. *
  4898. *
  4899. *
  4900. * TODO:
  4901. * - 考虑是否实现 jQuery 的 position, offsetParent 等功能
  4902. * - 更详细的测试用例(比如:测试 position 为 fixed 的情况)
  4903. */
  4904. /**
  4905. * @module dom
  4906. * @author yiminghe@gmail.com,lifesinger@gmail.com
  4907. */
  4908. KISSY.add('dom/style', function(S, DOM, UA, undefined) {
  4909. var doc = document,
  4910. docElem = doc.documentElement,
  4911. isIE = UA['ie'],
  4912. STYLE = 'style',
  4913. FLOAT = 'float',
  4914. CSS_FLOAT = 'cssFloat',
  4915. STYLE_FLOAT = 'styleFloat',
  4916. WIDTH = 'width',
  4917. HEIGHT = 'height',
  4918. AUTO = 'auto',
  4919. DISPLAY = 'display',
  4920. OLD_DISPLAY = DISPLAY + S.now(),
  4921. NONE = 'none',
  4922. PARSEINT = parseInt,
  4923. RE_NUMPX = /^-?\d+(?:px)?$/i,
  4924. cssNumber = {
  4925. "fillOpacity": 1,
  4926. "fontWeight": 1,
  4927. "lineHeight": 1,
  4928. "opacity": 1,
  4929. "orphans": 1,
  4930. "widows": 1,
  4931. "zIndex": 1,
  4932. "zoom": 1
  4933. },
  4934. RE_DASH = /-([a-z])/ig,
  4935. CAMELCASE_FN = function(all, letter) {
  4936. return letter.toUpperCase();
  4937. },
  4938. // 考虑 ie9 ...
  4939. rupper = /([A-Z]|^ms)/g,
  4940. EMPTY = '',
  4941. DEFAULT_UNIT = 'px',
  4942. CUSTOM_STYLES = {},
  4943. cssProps = {},
  4944. defaultDisplay = {};
  4945. // normalize reserved word float alternatives ("cssFloat" or "styleFloat")
  4946. if (docElem[STYLE][CSS_FLOAT] !== undefined) {
  4947. cssProps[FLOAT] = CSS_FLOAT;
  4948. }
  4949. else if (docElem[STYLE][STYLE_FLOAT] !== undefined) {
  4950. cssProps[FLOAT] = STYLE_FLOAT;
  4951. }
  4952. function camelCase(name) {
  4953. return name.replace(RE_DASH, CAMELCASE_FN);
  4954. }
  4955. var defaultDisplayDetectIframe,
  4956. defaultDisplayDetectIframeDoc;
  4957. // modified from jquery : bullet-proof method of getting default display
  4958. // fix domain problem in ie>6 , ie6 still access denied
  4959. function getDefaultDisplay(tagName) {
  4960. var body,
  4961. elem;
  4962. if (!defaultDisplay[ tagName ]) {
  4963. body = doc.body || doc.documentElement;
  4964. elem = doc.createElement(tagName);
  4965. DOM.prepend(elem, body);
  4966. var oldDisplay = DOM.css(elem, "display");
  4967. body.removeChild(elem);
  4968. // If the simple way fails,
  4969. // get element's real default display by attaching it to a temp iframe
  4970. if (oldDisplay === "none" || oldDisplay === "") {
  4971. // No iframe to use yet, so create it
  4972. if (!defaultDisplayDetectIframe) {
  4973. defaultDisplayDetectIframe = doc.createElement("iframe");
  4974. defaultDisplayDetectIframe.frameBorder =
  4975. defaultDisplayDetectIframe.width =
  4976. defaultDisplayDetectIframe.height = 0;
  4977. DOM.prepend(defaultDisplayDetectIframe, body);
  4978. var iframeSrc;
  4979. if (iframeSrc = DOM._genEmptyIframeSrc()) {
  4980. defaultDisplayDetectIframe.src = iframeSrc;
  4981. }
  4982. } else {
  4983. DOM.prepend(defaultDisplayDetectIframe, body);
  4984. }
  4985. // Create a cacheable copy of the iframe document on first call.
  4986. // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
  4987. // document to it; WebKit & Firefox won't allow reusing the iframe document.
  4988. if (!defaultDisplayDetectIframeDoc || !defaultDisplayDetectIframe.createElement) {
  4989. try {
  4990. defaultDisplayDetectIframeDoc = defaultDisplayDetectIframe.contentWindow.document;
  4991. defaultDisplayDetectIframeDoc.write(( doc.compatMode === "CSS1Compat" ? "<!doctype html>" : "" )
  4992. + "<html><head>" +
  4993. (UA['ie'] && DOM._isCustomDomain() ?
  4994. "<script>document.domain = '" +
  4995. doc.domain
  4996. + "';</script>" : "")
  4997. +
  4998. "</head><body>");
  4999. defaultDisplayDetectIframeDoc.close();
  5000. } catch(e) {
  5001. // ie6 need a breath , such as alert(8) or setTimeout;
  5002. // 同时需要同步,所以无解,勉强返回
  5003. return "block";
  5004. }
  5005. }
  5006. elem = defaultDisplayDetectIframeDoc.createElement(tagName);
  5007. defaultDisplayDetectIframeDoc.body.appendChild(elem);
  5008. oldDisplay = DOM.css(elem, "display");
  5009. body.removeChild(defaultDisplayDetectIframe);
  5010. }
  5011. // Store the correct default display
  5012. defaultDisplay[ tagName ] = oldDisplay;
  5013. }
  5014. return defaultDisplay[ tagName ];
  5015. }
  5016. S.mix(DOM, {
  5017. _camelCase:camelCase,
  5018. _cssNumber:cssNumber,
  5019. _CUSTOM_STYLES: CUSTOM_STYLES,
  5020. _cssProps:cssProps,
  5021. _getComputedStyle: function(elem, name) {
  5022. var val = "",
  5023. computedStyle = {},
  5024. d = elem.ownerDocument;
  5025. name = name.replace(rupper, "-$1").toLowerCase();
  5026. // https://github.com/kissyteam/kissy/issues/61
  5027. if (computedStyle = d.defaultView.getComputedStyle(elem, null)) {
  5028. val = computedStyle.getPropertyValue(name) || computedStyle[name];
  5029. }
  5030. // 还没有加入到 document,就取行内
  5031. if (val == "" && !DOM.__contains(d.documentElement, elem)) {
  5032. name = cssProps[name] || name;
  5033. val = elem[STYLE][name];
  5034. }
  5035. return val;
  5036. },
  5037. /**
  5038. * Get and set the style property on a DOM Node
  5039. */
  5040. style:function(selector, name, val) {
  5041. // suports hash
  5042. if (S.isPlainObject(name)) {
  5043. for (var k in name) {
  5044. DOM.style(selector, k, name[k]);
  5045. }
  5046. return;
  5047. }
  5048. if (val === undefined) {
  5049. var elem = DOM.get(selector),ret = '';
  5050. if (elem) {
  5051. ret = style(elem, name, val);
  5052. }
  5053. return ret;
  5054. } else {
  5055. DOM.query(selector).each(function(elem) {
  5056. style(elem, name, val);
  5057. });
  5058. }
  5059. },
  5060. /**
  5061. * (Gets computed style) or (sets styles) on the matches elements.
  5062. */
  5063. css: function(selector, name, val) {
  5064. // suports hash
  5065. if (S.isPlainObject(name)) {
  5066. for (var k in name) {
  5067. DOM.css(selector, k, name[k]);
  5068. }
  5069. return;
  5070. }
  5071. name = camelCase(name);
  5072. var hook = CUSTOM_STYLES[name];
  5073. // getter
  5074. if (val === undefined) {
  5075. // supports css selector/Node/NodeList
  5076. var elem = DOM.get(selector), ret = '';
  5077. if (elem) {
  5078. // If a hook was provided get the computed value from there
  5079. if (hook && "get" in hook && (ret = hook.get(elem, true)) !== undefined) {
  5080. } else {
  5081. ret = DOM._getComputedStyle(elem, name);
  5082. }
  5083. }
  5084. return ret === undefined ? '' : ret;
  5085. }
  5086. // setter
  5087. else {
  5088. DOM.style(selector, name, val);
  5089. }
  5090. },
  5091. /**
  5092. * Show the matched elements.
  5093. */
  5094. show: function(selector) {
  5095. DOM.query(selector).each(function(elem) {
  5096. elem[STYLE][DISPLAY] = DOM.data(elem, OLD_DISPLAY) || EMPTY;
  5097. // 可能元素还处于隐藏状态,比如 css 里设置了 display: none
  5098. if (DOM.css(elem, DISPLAY) === NONE) {
  5099. var tagName = elem.tagName.toLowerCase(),
  5100. old = getDefaultDisplay(tagName);
  5101. DOM.data(elem, OLD_DISPLAY, old);
  5102. elem[STYLE][DISPLAY] = old;
  5103. }
  5104. });
  5105. },
  5106. /**
  5107. * Hide the matched elements.
  5108. */
  5109. hide: function(selector) {
  5110. DOM.query(selector).each(function(elem) {
  5111. var style = elem[STYLE], old = style[DISPLAY];
  5112. if (old !== NONE) {
  5113. if (old) {
  5114. DOM.data(elem, OLD_DISPLAY, old);
  5115. }
  5116. style[DISPLAY] = NONE;
  5117. }
  5118. });
  5119. },
  5120. /**
  5121. * Display or hide the matched elements.
  5122. */
  5123. toggle: function(selector) {
  5124. DOM.query(selector).each(function(elem) {
  5125. if (DOM.css(elem, DISPLAY) === NONE) {
  5126. DOM.show(elem);
  5127. } else {
  5128. DOM.hide(elem);
  5129. }
  5130. });
  5131. },
  5132. /**
  5133. * Creates a stylesheet from a text blob of rules.
  5134. * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
  5135. * @param {String} cssText The text containing the css rules
  5136. * @param {String} id An id to add to the stylesheet for later removal
  5137. */
  5138. addStyleSheet: function(refWin, cssText, id) {
  5139. if (S.isString(refWin)) {
  5140. id = cssText;
  5141. cssText = refWin;
  5142. refWin = window;
  5143. }
  5144. refWin = DOM.get(refWin);
  5145. var win = DOM._getWin(refWin),doc = win.document;
  5146. var elem;
  5147. if (id && (id = id.replace('#', EMPTY))) {
  5148. elem = DOM.get('#' + id, doc);
  5149. }
  5150. // 仅添加一次,不重复添加
  5151. if (elem) {
  5152. return;
  5153. }
  5154. elem = DOM.create('<style>', { id: id }, doc);
  5155. // 先添加到 DOM 树中,再给 cssText 赋值,否则 css hack 会失效
  5156. DOM.get('head', doc).appendChild(elem);
  5157. if (elem.styleSheet) { // IE
  5158. elem.styleSheet.cssText = cssText;
  5159. } else { // W3C
  5160. elem.appendChild(doc.createTextNode(cssText));
  5161. }
  5162. },
  5163. unselectable:function(selector) {
  5164. DOM.query(selector).each(function(elem) {
  5165. if (UA['gecko']) {
  5166. elem[STYLE]['MozUserSelect'] = 'none';
  5167. }
  5168. else if (UA['webkit']) {
  5169. elem[STYLE]['KhtmlUserSelect'] = 'none';
  5170. } else {
  5171. if (UA['ie'] || UA['opera']) {
  5172. var e,i = 0,
  5173. els = elem.getElementsByTagName("*");
  5174. elem.setAttribute("unselectable", 'on');
  5175. while (( e = els[ i++ ] )) {
  5176. switch (e.tagName.toLowerCase()) {
  5177. case 'iframe' :
  5178. case 'textarea' :
  5179. case 'input' :
  5180. case 'select' :
  5181. /* Ignore the above tags */
  5182. break;
  5183. default :
  5184. e.setAttribute("unselectable", 'on');
  5185. }
  5186. }
  5187. }
  5188. }
  5189. });
  5190. },
  5191. innerWidth:0,
  5192. innerHeight:0,
  5193. outerWidth:0,
  5194. outerHeight:0,
  5195. width:0,
  5196. height:0
  5197. });
  5198. function capital(str) {
  5199. return str.charAt(0).toUpperCase() + str.substring(1);
  5200. }
  5201. S.each([WIDTH,HEIGHT], function(name) {
  5202. DOM["inner" + capital(name)] = function(selector) {
  5203. var el = DOM.get(selector);
  5204. if (el) {
  5205. return getWH(el, name, "padding");
  5206. } else {
  5207. return null;
  5208. }
  5209. };
  5210. DOM["outer" + capital(name)] = function(selector, includeMargin) {
  5211. var el = DOM.get(selector);
  5212. if (el) {
  5213. return getWH(el, name, includeMargin ? "margin" : "border");
  5214. } else {
  5215. return null;
  5216. }
  5217. };
  5218. DOM[name] = function(selector, val) {
  5219. var ret = DOM.css(selector, name, val);
  5220. if (ret) {
  5221. ret = parseFloat(ret);
  5222. }
  5223. return ret;
  5224. };
  5225. });
  5226. var cssShow = { position: "absolute", visibility: "hidden", display: "block" };
  5227. /**
  5228. * css height,width 永远都是计算值
  5229. */
  5230. S.each(["height", "width"], function(name) {
  5231. CUSTOM_STYLES[ name ] = {
  5232. get: function(elem, computed) {
  5233. var val;
  5234. if (computed) {
  5235. if (elem.offsetWidth !== 0) {
  5236. val = getWH(elem, name);
  5237. } else {
  5238. swap(elem, cssShow, function() {
  5239. val = getWH(elem, name);
  5240. });
  5241. }
  5242. return val + "px";
  5243. }
  5244. },
  5245. set: function(elem, value) {
  5246. if (RE_NUMPX.test(value)) {
  5247. value = parseFloat(value);
  5248. if (value >= 0) {
  5249. return value + "px";
  5250. }
  5251. } else {
  5252. return value;
  5253. }
  5254. }
  5255. };
  5256. });
  5257. S.each(["left", "top"], function(name) {
  5258. CUSTOM_STYLES[ name ] = {
  5259. get: function(elem, computed) {
  5260. if (computed) {
  5261. var val = DOM._getComputedStyle(elem, name),offset;
  5262. // 1. 当没有设置 style.left 时,getComputedStyle 在不同浏览器下,返回值不同
  5263. // 比如:firefox 返回 0, webkit/ie 返回 auto
  5264. // 2. style.left 设置为百分比时,返回值为百分比
  5265. // 对于第一种情况,如果是 relative 元素,值为 0. 如果是 absolute 元素,值为 offsetLeft - marginLeft
  5266. // 对于第二种情况,大部分类库都未做处理,属于“明之而不 fix”的保留 bug
  5267. if (val === AUTO) {
  5268. val = 0;
  5269. if (S.inArray(DOM.css(elem, 'position'), ['absolute','fixed'])) {
  5270. offset = elem[name === 'left' ? 'offsetLeft' : 'offsetTop'];
  5271. // old-ie 下,elem.offsetLeft 包含 offsetParent 的 border 宽度,需要减掉
  5272. if (isIE && document['documentMode'] != 9 || UA['opera']) {
  5273. // 类似 offset ie 下的边框处理
  5274. // 如果 offsetParent 为 html ,需要减去默认 2 px == documentElement.clientTop
  5275. // 否则减去 borderTop 其实也是 clientTop
  5276. // http://msdn.microsoft.com/en-us/library/aa752288%28v=vs.85%29.aspx
  5277. // ie<9 注意有时候 elem.offsetParent 为 null ...
  5278. // 比如 DOM.append(DOM.create("<div class='position:absolute'></div>"),document.body)
  5279. offset -= elem.offsetParent && elem.offsetParent['client' + (name == 'left' ? 'Left' : 'Top')]
  5280. || 0;
  5281. }
  5282. val = offset - (PARSEINT(DOM.css(elem, 'margin-' + name)) || 0);
  5283. }
  5284. val += "px";
  5285. }
  5286. return val;
  5287. }
  5288. }
  5289. };
  5290. });
  5291. function swap(elem, options, callback) {
  5292. var old = {};
  5293. // Remember the old values, and insert the new ones
  5294. for (var name in options) {
  5295. old[ name ] = elem[STYLE][ name ];
  5296. elem[STYLE][ name ] = options[ name ];
  5297. }
  5298. callback.call(elem);
  5299. // Revert the old values
  5300. for (name in options) {
  5301. elem[STYLE][ name ] = old[ name ];
  5302. }
  5303. }
  5304. function style(elem, name, val) {
  5305. var style;
  5306. if (elem.nodeType === 3 || elem.nodeType === 8 || !(style = elem[STYLE])) {
  5307. return undefined;
  5308. }
  5309. name = camelCase(name);
  5310. var ret,hook = CUSTOM_STYLES[name];
  5311. name = cssProps[name] || name;
  5312. // setter
  5313. if (val !== undefined) {
  5314. // normalize unsetting
  5315. if (val === null || val === EMPTY) {
  5316. val = EMPTY;
  5317. }
  5318. // number values may need a unit
  5319. else if (!isNaN(Number(val)) && !cssNumber[name]) {
  5320. val += DEFAULT_UNIT;
  5321. }
  5322. if (hook && hook.set) {
  5323. val = hook.set(elem, val);
  5324. }
  5325. if (val !== undefined) {
  5326. // ie 无效值报错
  5327. try {
  5328. elem[STYLE][name] = val;
  5329. } catch(e) {
  5330. S.log("css set error :" + e);
  5331. }
  5332. }
  5333. return undefined;
  5334. }
  5335. //getter
  5336. else {
  5337. // If a hook was provided get the non-computed value from there
  5338. if (hook && "get" in hook && (ret = hook.get(elem, false)) !== undefined) {
  5339. } else {
  5340. // Otherwise just get the value from the style object
  5341. ret = style[ name ];
  5342. }
  5343. return ret === undefined ? "" : ret;
  5344. }
  5345. }
  5346. /**
  5347. * 得到元素的大小信息
  5348. * @param elem
  5349. * @param name
  5350. * @param {String} extra "padding" : (css width) + padding
  5351. * "border" : (css width) + padding + border
  5352. * "margin" : (css width) + padding + border + margin
  5353. */
  5354. function getWH(elem, name, extra) {
  5355. if (S.isWindow(elem)) {
  5356. return name == WIDTH ? DOM.viewportWidth(elem) : DOM.viewportHeight(elem);
  5357. } else if (elem.nodeType == 9) {
  5358. return name == WIDTH ? DOM.docWidth(elem) : DOM.docHeight(elem);
  5359. }
  5360. var which = name === WIDTH ? ['Left', 'Right'] : ['Top', 'Bottom'],
  5361. val = name === WIDTH ? elem.offsetWidth : elem.offsetHeight;
  5362. if (val > 0) {
  5363. if (extra !== "border") {
  5364. S.each(which, function(w) {
  5365. if (!extra) {
  5366. val -= parseFloat(DOM.css(elem, "padding" + w)) || 0;
  5367. }
  5368. if (extra === "margin") {
  5369. val += parseFloat(DOM.css(elem, extra + w)) || 0;
  5370. } else {
  5371. val -= parseFloat(DOM.css(elem, "border" + w + "Width")) || 0;
  5372. }
  5373. });
  5374. }
  5375. return val
  5376. }
  5377. // Fall back to computed then uncomputed css if necessary
  5378. val = DOM._getComputedStyle(elem, name);
  5379. if (val < 0 || S.isNullOrUndefined(val)) {
  5380. val = elem.style[ name ] || 0;
  5381. }
  5382. // Normalize "", auto, and prepare for extra
  5383. val = parseFloat(val) || 0;
  5384. // Add padding, border, margin
  5385. if (extra) {
  5386. S.each(which, function(w) {
  5387. val += parseFloat(DOM.css(elem, "padding" + w)) || 0;
  5388. if (extra !== "padding") {
  5389. val += parseFloat(DOM.css(elem, "border" + w + "Width")) || 0;
  5390. }
  5391. if (extra === "margin") {
  5392. val += parseFloat(DOM.css(elem, extra + w)) || 0;
  5393. }
  5394. });
  5395. }
  5396. return val;
  5397. }
  5398. return DOM;
  5399. }, {
  5400. requires:["dom/base","ua"]
  5401. });
  5402. /**
  5403. *
  5404. * 2011-08-19
  5405. * - 调整结构,减少耦合
  5406. * - fix css("height") == auto
  5407. *
  5408. * NOTES:
  5409. * - Opera 下,color 默认返回 #XXYYZZ, 非 rgb(). 目前 jQuery 等类库均忽略此差异,KISSY 也忽略。
  5410. * - Safari 低版本,transparent 会返回为 rgba(0, 0, 0, 0), 考虑低版本才有此 bug, 亦忽略。
  5411. *
  5412. *
  5413. * - getComputedStyle 在 webkit 下,会舍弃小数部分,ie 下会四舍五入,gecko 下直接输出 float 值。
  5414. *
  5415. * - color: blue 继承值,getComputedStyle, 在 ie 下返回 blue, opera 返回 #0000ff, 其它浏览器
  5416. * 返回 rgb(0, 0, 255)
  5417. *
  5418. * - 总之:要使得返回值完全一致是不大可能的,jQuery/ExtJS/KISSY 未“追求完美”。YUI3 做了部分完美处理,但
  5419. * 依旧存在浏览器差异。
  5420. */
  5421. /**
  5422. * @module selector
  5423. * @author lifesinger@gmail.com , yiminghe@gmail.com
  5424. */
  5425. KISSY.add('dom/selector', function(S, DOM, undefined) {
  5426. var doc = document,
  5427. filter = S.filter,
  5428. require = function(selector) {
  5429. return S.require(selector);
  5430. },
  5431. isArray = S.isArray,
  5432. makeArray = S.makeArray,
  5433. isNodeList = DOM._isNodeList,
  5434. nodeName = DOM._nodeName,
  5435. push = Array.prototype.push,
  5436. SPACE = ' ',
  5437. COMMA = ',',
  5438. trim = S.trim,
  5439. ANY = '*',
  5440. REG_ID = /^#[\w-]+$/,
  5441. REG_QUERY = /^(?:#([\w-]+))?\s*([\w-]+|\*)?\.?([\w-]+)?$/;
  5442. /**
  5443. * Retrieves an Array of HTMLElement based on the given CSS selector.
  5444. * @param {String|Array} selector
  5445. * @param {String|Array<HTMLElement>|NodeList} context find elements matching selector under context
  5446. * @return {Array} The array of found HTMLElement
  5447. */
  5448. function query(selector, context) {
  5449. var ret,
  5450. i,
  5451. isSelectorString = typeof selector === 'string',
  5452. // optimize common usage
  5453. contexts = context === undefined ? [doc] : tuneContext(context);
  5454. if (isSelectorString) {
  5455. selector = trim(selector);
  5456. if (contexts.length == 1 && selector) {
  5457. ret = quickFindBySelectorStr(selector, contexts[0]);
  5458. }
  5459. }
  5460. if (!ret) {
  5461. ret = [];
  5462. if (selector) {
  5463. for (i = 0; i < contexts.length; i++) {
  5464. push.apply(ret, queryByContexts(selector, contexts[i]));
  5465. }
  5466. //必要时去重排序
  5467. if (ret.length > 1 &&
  5468. // multiple contexts
  5469. (contexts.length > 1 ||
  5470. (isSelectorString &&
  5471. // multiple selector
  5472. selector.indexOf(COMMA) > -1))) {
  5473. unique(ret);
  5474. }
  5475. }
  5476. }
  5477. // attach each method
  5478. ret.each = function(f) {
  5479. var self = this,el,i;
  5480. for (i = 0; i < self.length; i++) {
  5481. el = self[i];
  5482. if (f(el, i) === false) {
  5483. break;
  5484. }
  5485. }
  5486. };
  5487. return ret;
  5488. }
  5489. function queryByContexts(selector, context) {
  5490. var ret = [],
  5491. isSelectorString = typeof selector === 'string';
  5492. if (isSelectorString && selector.match(REG_QUERY) ||
  5493. !isSelectorString) {
  5494. // 简单选择器自己处理
  5495. ret = queryBySimple(selector, context);
  5496. }
  5497. // 如果选择器有 , 分开递归一部分一部分来
  5498. else if (isSelectorString && selector.indexOf(COMMA) > -1) {
  5499. ret = queryBySelectors(selector, context);
  5500. }
  5501. else {
  5502. // 复杂了,交给 sizzle
  5503. ret = queryBySizzle(selector, context);
  5504. }
  5505. return ret;
  5506. }
  5507. // 交给 sizzle 模块处理
  5508. function queryBySizzle(selector, context) {
  5509. var ret = [],
  5510. sizzle = require("sizzle");
  5511. if (sizzle) {
  5512. sizzle(selector, context, ret);
  5513. } else {
  5514. // 原生不支持
  5515. error(selector);
  5516. }
  5517. return ret;
  5518. }
  5519. // 处理 selector 的每个部分
  5520. function queryBySelectors(selector, context) {
  5521. var ret = [],
  5522. i,
  5523. selectors = selector.split(/\s*,\s*/);
  5524. for (i = 0; i < selectors.length; i++) {
  5525. push.apply(ret, queryByContexts(selectors[i], context));
  5526. }
  5527. // 多部分选择器可能得到重复结果
  5528. return ret;
  5529. }
  5530. function quickFindBySelectorStr(selector, context) {
  5531. var ret,t,match,id,tag,cls;
  5532. // selector 为 #id 是最常见的情况,特殊优化处理
  5533. if (REG_ID.test(selector)) {
  5534. t = getElementById(selector.slice(1), context);
  5535. if (t) {
  5536. // #id 无效时,返回空数组
  5537. ret = [t];
  5538. } else {
  5539. ret = [];
  5540. }
  5541. }
  5542. // selector 为支持列表中的其它 6 种
  5543. else {
  5544. match = REG_QUERY.exec(selector);
  5545. if (match) {
  5546. // 获取匹配出的信息
  5547. id = match[1];
  5548. tag = match[2];
  5549. cls = match[3];
  5550. // 空白前只能有 id ,取出来作为 context
  5551. context = (id ? getElementById(id, context) : context);
  5552. if (context) {
  5553. // #id .cls | #id tag.cls | .cls | tag.cls | #id.cls
  5554. if (cls) {
  5555. if (!id || selector.indexOf(SPACE) != -1) { // 排除 #id.cls
  5556. ret = [].concat(getElementsByClassName(cls, tag, context));
  5557. }
  5558. // 处理 #id.cls
  5559. else {
  5560. t = getElementById(id, context);
  5561. if (t && hasClass(t, cls)) {
  5562. ret = [t];
  5563. }
  5564. }
  5565. }
  5566. // #id tag | tag
  5567. else if (tag) { // 排除空白字符串
  5568. ret = getElementsByTagName(tag, context);
  5569. }
  5570. }
  5571. ret = ret || [];
  5572. }
  5573. }
  5574. return ret;
  5575. }
  5576. // 最简单情况了,单个选择器部分,单个上下文
  5577. function queryBySimple(selector, context) {
  5578. var ret,
  5579. isSelectorString = typeof selector === 'string';
  5580. if (isSelectorString) {
  5581. ret = quickFindBySelectorStr(selector, context) || [];
  5582. }
  5583. // 传入的 selector 是 NodeList 或已是 Array
  5584. else if (selector && (isArray(selector) || isNodeList(selector))) {
  5585. // 只能包含在 context 里面
  5586. ret = filter(selector, function(s) {
  5587. return testByContext(s, context);
  5588. });
  5589. }
  5590. // 传入的 selector 是 HTMLNode 查看约束
  5591. // 否则 window/document,原样返回
  5592. else if (selector && testByContext(selector, context)) {
  5593. ret = [selector];
  5594. }
  5595. return ret;
  5596. }
  5597. function testByContext(element, context) {
  5598. if (!element) {
  5599. return false;
  5600. }
  5601. // 防止 element 节点还没添加到 document ,但是也可以获取到 query(element) => [element]
  5602. // document 的上下文一律放行
  5603. // context == doc 意味着没有提供第二个参数,到这里只是想单纯包装原生节点,则不检测
  5604. if (context == doc) {
  5605. return true;
  5606. }
  5607. // 节点受上下文约束
  5608. return DOM.__contains(context, element);
  5609. }
  5610. var unique;
  5611. (function() {
  5612. var sortOrder,
  5613. t,
  5614. hasDuplicate,
  5615. baseHasDuplicate = true;
  5616. // Here we check if the JavaScript engine is using some sort of
  5617. // optimization where it does not always call our comparision
  5618. // function. If that is the case, discard the hasDuplicate value.
  5619. // Thus far that includes Google Chrome.
  5620. [0, 0].sort(function() {
  5621. baseHasDuplicate = false;
  5622. return 0;
  5623. });
  5624. // 排序去重
  5625. unique = function (elements) {
  5626. if (sortOrder) {
  5627. hasDuplicate = baseHasDuplicate;
  5628. elements.sort(sortOrder);
  5629. if (hasDuplicate) {
  5630. var i = 1,len = elements.length;
  5631. while (i < len) {
  5632. if (elements[i] === elements[ i - 1 ]) {
  5633. elements.splice(i, 1);
  5634. } else {
  5635. i++;
  5636. }
  5637. }
  5638. }
  5639. }
  5640. return elements;
  5641. };
  5642. // 貌似除了 ie 都有了...
  5643. if (doc.documentElement.compareDocumentPosition) {
  5644. sortOrder = t = function(a, b) {
  5645. if (a == b) {
  5646. hasDuplicate = true;
  5647. return 0;
  5648. }
  5649. if (!a.compareDocumentPosition || !b.compareDocumentPosition) {
  5650. return a.compareDocumentPosition ? -1 : 1;
  5651. }
  5652. return a.compareDocumentPosition(b) & 4 ? -1 : 1;
  5653. };
  5654. } else {
  5655. sortOrder = t = function(a, b) {
  5656. // The nodes are identical, we can exit early
  5657. if (a == b) {
  5658. hasDuplicate = true;
  5659. return 0;
  5660. // Fallback to using sourceIndex (in IE) if it's available on both nodes
  5661. } else if (a.sourceIndex && b.sourceIndex) {
  5662. return a.sourceIndex - b.sourceIndex;
  5663. }
  5664. };
  5665. }
  5666. })();
  5667. // 调整 context 为合理值
  5668. function tuneContext(context) {
  5669. // context 为 undefined 是最常见的情况,优先考虑
  5670. if (context === undefined) {
  5671. return [doc];
  5672. }
  5673. // 其他直接使用 query
  5674. return query(context, undefined);
  5675. }
  5676. // query #id
  5677. function getElementById(id, context) {
  5678. var doc = context,
  5679. el;
  5680. if (context.nodeType !== DOM.DOCUMENT_NODE) {
  5681. doc = context.ownerDocument;
  5682. }
  5683. el = doc.getElementById(id);
  5684. if (el && el.id === id) {
  5685. // optimize for common usage
  5686. }
  5687. else if (el && el.parentNode) {
  5688. // ie opera confuse name with id
  5689. // https://github.com/kissyteam/kissy/issues/67
  5690. // 不能直接 el.id ,否则 input shadow form attribute
  5691. if (DOM.__attr(el, "id") !== id) {
  5692. // 直接在 context 下的所有节点找
  5693. el = DOM.filter(ANY, "#" + id, context)[0] || null;
  5694. }
  5695. // ie 特殊情况下以及指明在 context 下找了,不需要再判断
  5696. // 如果指定了 context node , 还要判断 id 是否处于 context 内
  5697. else if (!testByContext(el, context)) {
  5698. el = null;
  5699. }
  5700. } else {
  5701. el = null;
  5702. }
  5703. return el;
  5704. }
  5705. // query tag
  5706. function getElementsByTagName(tag, context) {
  5707. return context && makeArray(context.getElementsByTagName(tag)) || [];
  5708. }
  5709. (function() {
  5710. // Check to see if the browser returns only elements
  5711. // when doing getElementsByTagName('*')
  5712. // Create a fake element
  5713. var div = doc.createElement('div');
  5714. div.appendChild(doc.createComment(''));
  5715. // Make sure no comments are found
  5716. if (div.getElementsByTagName(ANY).length > 0) {
  5717. getElementsByTagName = function(tag, context) {
  5718. var ret = makeArray(context.getElementsByTagName(tag));
  5719. if (tag === ANY) {
  5720. var t = [], i = 0,node;
  5721. while ((node = ret[i++])) {
  5722. // Filter out possible comments
  5723. if (node.nodeType === 1) {
  5724. t.push(node);
  5725. }
  5726. }
  5727. ret = t;
  5728. }
  5729. return ret;
  5730. };
  5731. }
  5732. })();
  5733. // query .cls
  5734. var getElementsByClassName = doc.getElementsByClassName ? function(cls, tag, context) {
  5735. // query("#id1 xx","#id2")
  5736. // #id2 内没有 #id1 , context 为 null , 这里防御下
  5737. if (!context) {
  5738. return [];
  5739. }
  5740. var els = context.getElementsByClassName(cls),
  5741. ret,
  5742. i = 0,
  5743. len = els.length,
  5744. el;
  5745. if (tag && tag !== ANY) {
  5746. ret = [];
  5747. for (; i < len; ++i) {
  5748. el = els[i];
  5749. if (nodeName(el, tag)) {
  5750. ret.push(el);
  5751. }
  5752. }
  5753. } else {
  5754. ret = makeArray(els);
  5755. }
  5756. return ret;
  5757. } : ( doc.querySelectorAll ? function(cls, tag, context) {
  5758. // ie8 return staticNodeList 对象,[].concat 会形成 [ staticNodeList ] ,手动转化为普通数组
  5759. return context && makeArray(context.querySelectorAll((tag ? tag : '') + '.' + cls)) || [];
  5760. } : function(cls, tag, context) {
  5761. if (!context) {
  5762. return [];
  5763. }
  5764. var els = context.getElementsByTagName(tag || ANY),
  5765. ret = [],
  5766. i = 0,
  5767. len = els.length,
  5768. el;
  5769. for (; i < len; ++i) {
  5770. el = els[i];
  5771. if (hasClass(el, cls)) {
  5772. ret.push(el);
  5773. }
  5774. }
  5775. return ret;
  5776. });
  5777. function hasClass(el, cls) {
  5778. return DOM.__hasClass(el, cls);
  5779. }
  5780. // throw exception
  5781. function error(msg) {
  5782. S.error('Unsupported selector: ' + msg);
  5783. }
  5784. S.mix(DOM, {
  5785. query: query,
  5786. get: function(selector, context) {
  5787. return query(selector, context)[0] || null;
  5788. },
  5789. unique:unique,
  5790. /**
  5791. * Filters an array of elements to only include matches of a filter.
  5792. * @param filter selector or fn
  5793. */
  5794. filter: function(selector, filter, context) {
  5795. var elems = query(selector, context),
  5796. sizzle = require("sizzle"),
  5797. match,
  5798. tag,
  5799. id,
  5800. cls,
  5801. ret = [];
  5802. // 默认仅支持最简单的 tag.cls 或 #id 形式
  5803. if (typeof filter === 'string' &&
  5804. (filter = trim(filter)) &&
  5805. (match = REG_QUERY.exec(filter))) {
  5806. id = match[1];
  5807. tag = match[2];
  5808. cls = match[3];
  5809. if (!id) {
  5810. filter = function(elem) {
  5811. var tagRe = true,clsRe = true;
  5812. // 指定 tag 才进行判断
  5813. if (tag) {
  5814. tagRe = nodeName(elem, tag);
  5815. }
  5816. // 指定 cls 才进行判断
  5817. if (cls) {
  5818. clsRe = hasClass(elem, cls);
  5819. }
  5820. return clsRe && tagRe;
  5821. }
  5822. } else if (id && !tag && !cls) {
  5823. filter = function(elem) {
  5824. return DOM.__attr(elem, "id") === id;
  5825. };
  5826. }
  5827. }
  5828. if (S.isFunction(filter)) {
  5829. ret = S.filter(elems, filter);
  5830. }
  5831. // 其它复杂 filter, 采用外部选择器
  5832. else if (filter && sizzle) {
  5833. ret = sizzle.matches(filter, elems);
  5834. }
  5835. // filter 为空或不支持的 selector
  5836. else {
  5837. error(filter);
  5838. }
  5839. return ret;
  5840. },
  5841. /**
  5842. * Returns true if the passed element(s) match the passed filter
  5843. */
  5844. test: function(selector, filter, context) {
  5845. var elements = query(selector, context);
  5846. return elements.length && (DOM.filter(elements, filter, context).length === elements.length);
  5847. }
  5848. });
  5849. return DOM;
  5850. }, {
  5851. requires:["./base"]
  5852. });
  5853. /**
  5854. * NOTES:
  5855. *
  5856. * 2011.08.02
  5857. * - 利用 sizzle 重构选择器
  5858. * - 1.1.6 修正,原来 context 只支持 #id 以及 document
  5859. * 1.2 context 支持任意,和 selector 格式一致
  5860. * - 简单选择器也和 jquery 保持一致 DOM.query("xx","yy") 支持
  5861. * - context 不提供则为当前 document ,否则通过 query 递归取得
  5862. * - 保证选择出来的节点(除了 document window)都是位于 context 范围内
  5863. *
  5864. *
  5865. * 2010.01
  5866. * - 对 reg exec 的结果(id, tag, className)做 cache, 发现对性能影响很小,去掉。
  5867. * - getElementById 使用频率最高,使用直达通道优化。
  5868. * - getElementsByClassName 性能优于 querySelectorAll, 但 IE 系列不支持。
  5869. * - instanceof 对性能有影响。
  5870. * - 内部方法的参数,比如 cls, context 等的异常情况,已经在 query 方法中有保证,无需冗余“防卫”。
  5871. * - query 方法中的条件判断考虑了“频率优先”原则。最有可能出现的情况放在前面。
  5872. * - Array 的 push 方法可以用 j++ 来替代,性能有提升。
  5873. * - 返回值策略和 Sizzle 一致,正常时,返回数组;其它所有情况,返回空数组。
  5874. *
  5875. * - 从压缩角度考虑,还可以将 getElmentsByTagName 和 getElementsByClassName 定义为常量,
  5876. * 不过感觉这样做太“压缩控”,还是保留不替换的好。
  5877. *
  5878. * - 调整 getElementsByClassName 的降级写法,性能最差的放最后。
  5879. *
  5880. * 2010.02
  5881. * - 添加对分组选择器的支持(主要参考 Sizzle 的代码,代去除了对非 Grade A 级浏览器的支持)
  5882. *
  5883. * 2010.03
  5884. * - 基于原生 dom 的两个 api: S.query 返回数组; S.get 返回第一个。
  5885. * 基于 Node 的 api: S.one, 在 Node 中实现。
  5886. * 基于 NodeList 的 api: S.all, 在 NodeList 中实现。
  5887. * 通过 api 的分层,同时满足初级用户和高级用户的需求。
  5888. *
  5889. * 2010.05
  5890. * - 去掉给 S.query 返回值默认添加的 each 方法,保持纯净。
  5891. * - 对于不支持的 selector, 采用外部耦合进来的 Selector.
  5892. *
  5893. * 2010.06
  5894. * - 增加 filter 和 test 方法
  5895. *
  5896. * 2010.07
  5897. * - 取消对 , 分组的支持,group 直接用 Sizzle
  5898. *
  5899. * 2010.08
  5900. * - 给 S.query 的结果 attach each 方法
  5901. *
  5902. * 2011.05
  5903. * - 承玉:恢复对简单分组支持
  5904. *
  5905. * Ref: http://ejohn.org/blog/selectors-that-people-actually-use/
  5906. * 考虑 2/8 原则,仅支持以下选择器:
  5907. * #id
  5908. * tag
  5909. * .cls
  5910. * #id tag
  5911. * #id .cls
  5912. * tag.cls
  5913. * #id tag.cls
  5914. * 注 1:REG_QUERY 还会匹配 #id.cls
  5915. * 注 2:tag 可以为 * 字符
  5916. * 注 3: 支持 , 号分组
  5917. *
  5918. *
  5919. * Bugs:
  5920. * - S.query('#test-data *') 等带 * 号的选择器,在 IE6 下返回的值不对。jQuery 等类库也有此 bug, 诡异。
  5921. *
  5922. * References:
  5923. * - http://ejohn.org/blog/selectors-that-people-actually-use/
  5924. * - http://ejohn.org/blog/thoughts-on-queryselectorall/
  5925. * - MDC: querySelector, querySelectorAll, getElementsByClassName
  5926. * - Sizzle: http://github.com/jeresig/sizzle
  5927. * - MINI: http://james.padolsey.com/javascript/mini/
  5928. * - Peppy: http://jamesdonaghue.com/?p=40
  5929. * - Sly: http://github.com/digitarald/sly
  5930. * - XPath, TreeWalker:http://www.cnblogs.com/rubylouvre/archive/2009/07/24/1529640.html
  5931. *
  5932. * - http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html
  5933. * - http://www.quirksmode.org/dom/getElementsByTagNames.html
  5934. * - http://ejohn.org/blog/comparing-document-position/
  5935. * - http://github.com/jeresig/sizzle/blob/master/sizzle.js
  5936. */
  5937. /**
  5938. * @module dom
  5939. * @author lifesinger@gmail.com,yiminghe@gmail.com
  5940. */
  5941. KISSY.add('dom/style-ie', function(S, DOM, UA, Style) {
  5942. var HUNDRED = 100;
  5943. // only for ie
  5944. if (!UA['ie']) {
  5945. return DOM;
  5946. }
  5947. var doc = document,
  5948. docElem = doc.documentElement,
  5949. OPACITY = 'opacity',
  5950. STYLE = 'style',
  5951. FILTER = "filter",
  5952. CURRENT_STYLE = 'currentStyle',
  5953. RUNTIME_STYLE = 'runtimeStyle',
  5954. LEFT = 'left',
  5955. PX = 'px',
  5956. CUSTOM_STYLES = Style._CUSTOM_STYLES,
  5957. RE_NUMPX = /^-?\d+(?:px)?$/i,
  5958. RE_NUM = /^-?\d/,
  5959. ropacity = /opacity=([^)]*)/,
  5960. ralpha = /alpha\([^)]*\)/i;
  5961. // use alpha filter for IE opacity
  5962. try {
  5963. if (S.isNullOrUndefined(docElem.style[OPACITY])) {
  5964. CUSTOM_STYLES[OPACITY] = {
  5965. get: function(elem, computed) {
  5966. // 没有设置过 opacity 时会报错,这时返回 1 即可
  5967. // 如果该节点没有添加到 dom ,取不到 filters 结构
  5968. // val = elem[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
  5969. return ropacity.test((
  5970. computed && elem[CURRENT_STYLE] ?
  5971. elem[CURRENT_STYLE][FILTER] :
  5972. elem[STYLE][FILTER]) || "") ?
  5973. ( parseFloat(RegExp.$1) / HUNDRED ) + "" :
  5974. computed ? "1" : "";
  5975. },
  5976. set: function(elem, val) {
  5977. val = parseFloat(val);
  5978. var style = elem[STYLE],
  5979. currentStyle = elem[CURRENT_STYLE],
  5980. opacity = isNaN(val) ? "" : "alpha(" + OPACITY + "=" + val * HUNDRED + ")",
  5981. filter = S.trim(currentStyle && currentStyle[FILTER] || style[FILTER] || "");
  5982. // ie has layout
  5983. style.zoom = 1;
  5984. // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute
  5985. if (val >= 1 && S.trim(filter.replace(ralpha, "")) === "") {
  5986. // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
  5987. // if "filter:" is present at all, clearType is disabled, we want to avoid this
  5988. // style.removeAttribute is IE Only, but so apparently is this code path...
  5989. style.removeAttribute(FILTER);
  5990. // if there there is no filter style applied in a css rule, we are done
  5991. if (currentStyle && !currentStyle[FILTER]) {
  5992. return;
  5993. }
  5994. }
  5995. // otherwise, set new filter values
  5996. // 如果 >=1 就不设,就不能覆盖外部样式表定义的样式,一定要设
  5997. style.filter = ralpha.test(filter) ?
  5998. filter.replace(ralpha, opacity) :
  5999. filter + (filter ? ", " : "") + opacity;
  6000. }
  6001. };
  6002. }
  6003. }
  6004. catch(ex) {
  6005. S.log('IE filters ActiveX is disabled. ex = ' + ex);
  6006. }
  6007. /**
  6008. * border fix
  6009. * ie 不设置数值,则 computed style 不返回数值,只返回 thick? medium ...
  6010. * (default is "medium")
  6011. */
  6012. var IE8 = UA['ie'] == 8,
  6013. BORDER_MAP = {
  6014. },
  6015. BORDERS = ["","Top","Left","Right","Bottom"];
  6016. BORDER_MAP['thin'] = IE8 ? '1px' : '2px';
  6017. BORDER_MAP['medium'] = IE8 ? '3px' : '4px';
  6018. BORDER_MAP['thick'] = IE8 ? '5px' : '6px';
  6019. S.each(BORDERS, function(b) {
  6020. var name = "border" + b + "Width",
  6021. styleName = "border" + b + "Style";
  6022. CUSTOM_STYLES[name] = {
  6023. get: function(elem, computed) {
  6024. // 只有需要计算样式的时候才转换,否则取原值
  6025. var currentStyle = computed ? elem[CURRENT_STYLE] : 0,
  6026. current = currentStyle && String(currentStyle[name]) || undefined;
  6027. // look up keywords if a border exists
  6028. if (current && current.indexOf("px") < 0) {
  6029. // 边框没有隐藏
  6030. if (BORDER_MAP[current] && currentStyle[styleName] !== "none") {
  6031. current = BORDER_MAP[current];
  6032. } else {
  6033. // otherwise no border
  6034. current = 0;
  6035. }
  6036. }
  6037. return current;
  6038. }
  6039. };
  6040. });
  6041. // getComputedStyle for IE
  6042. if (!(doc.defaultView || { }).getComputedStyle && docElem[CURRENT_STYLE]) {
  6043. DOM._getComputedStyle = function(elem, name) {
  6044. name = DOM._cssProps[name] || name;
  6045. var ret = elem[CURRENT_STYLE] && elem[CURRENT_STYLE][name];
  6046. // 当 width/height 设置为百分比时,通过 pixelLeft 方式转换的 width/height 值
  6047. // 一开始就处理了! CUSTOM_STYLE["height"],CUSTOM_STYLE["width"] ,cssHook 解决@2011-08-19
  6048. // 在 ie 下不对,需要直接用 offset 方式
  6049. // borderWidth 等值也有问题,但考虑到 borderWidth 设为百分比的概率很小,这里就不考虑了
  6050. // From the awesome hack by Dean Edwards
  6051. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  6052. // If we're not dealing with a regular pixel number
  6053. // but a number that has a weird ending, we need to convert it to pixels
  6054. if ((!RE_NUMPX.test(ret) && RE_NUM.test(ret))) {
  6055. // Remember the original values
  6056. var style = elem[STYLE],
  6057. left = style[LEFT],
  6058. rsLeft = elem[RUNTIME_STYLE] && elem[RUNTIME_STYLE][LEFT];
  6059. // Put in the new values to get a computed value out
  6060. if (rsLeft) {
  6061. elem[RUNTIME_STYLE][LEFT] = elem[CURRENT_STYLE][LEFT];
  6062. }
  6063. style[LEFT] = name === 'fontSize' ? '1em' : (ret || 0);
  6064. ret = style['pixelLeft'] + PX;
  6065. // Revert the changed values
  6066. style[LEFT] = left;
  6067. if (rsLeft) {
  6068. elem[RUNTIME_STYLE][LEFT] = rsLeft;
  6069. }
  6070. }
  6071. return ret === "" ? "auto" : ret;
  6072. };
  6073. }
  6074. return DOM;
  6075. },
  6076. {
  6077. requires:["./base","ua","./style"]
  6078. }
  6079. );
  6080. /**
  6081. * NOTES:
  6082. * 承玉: 2011.05.19 opacity in ie
  6083. * - 如果节点是动态创建,设置opacity,没有加到 dom 前,取不到 opacity 值
  6084. * - 兼容:border-width 值,ie 下有可能返回 medium/thin/thick 等值,其它浏览器返回 px 值。
  6085. *
  6086. * - opacity 的实现,参考自 jquery
  6087. *
  6088. */
  6089. /**
  6090. * @module dom-traversal
  6091. * @author lifesinger@gmail.com,yiminghe@gmail.com
  6092. */
  6093. KISSY.add('dom/traversal', function(S, DOM, undefined) {
  6094. var isElementNode = DOM._isElementNode,
  6095. CONTAIN_MASK = 16;
  6096. S.mix(DOM, {
  6097. closest:function(selector, filter, context) {
  6098. return nth(selector, filter, 'parentNode', function(elem) {
  6099. return elem.nodeType != DOM.DOCUMENT_FRAGMENT_NODE;
  6100. }, context, true);
  6101. },
  6102. /**
  6103. * Gets the parent node of the first matched element.
  6104. */
  6105. parent: function(selector, filter, context) {
  6106. return nth(selector, filter, 'parentNode', function(elem) {
  6107. return elem.nodeType != DOM.DOCUMENT_FRAGMENT_NODE;
  6108. }, context);
  6109. },
  6110. first:function(selector, filter) {
  6111. var elem = DOM.get(selector);
  6112. return nth(elem && elem.firstChild, filter, 'nextSibling',
  6113. undefined, undefined, true);
  6114. },
  6115. last:function(selector, filter) {
  6116. var elem = DOM.get(selector);
  6117. return nth(elem && elem.lastChild, filter, 'previousSibling',
  6118. undefined, undefined, true);
  6119. },
  6120. /**
  6121. * Gets the following sibling of the first matched element.
  6122. */
  6123. next: function(selector, filter) {
  6124. return nth(selector, filter, 'nextSibling', undefined);
  6125. },
  6126. /**
  6127. * Gets the preceding sibling of the first matched element.
  6128. */
  6129. prev: function(selector, filter) {
  6130. return nth(selector, filter, 'previousSibling', undefined);
  6131. },
  6132. /**
  6133. * Gets the siblings of the first matched element.
  6134. */
  6135. siblings: function(selector, filter) {
  6136. return getSiblings(selector, filter, true);
  6137. },
  6138. /**
  6139. * Gets the children of the first matched element.
  6140. */
  6141. children: function(selector, filter) {
  6142. return getSiblings(selector, filter, undefined);
  6143. },
  6144. __contains:document.documentElement.contains ?
  6145. function(a, b) {
  6146. if (a.nodeType == DOM.TEXT_NODE) {
  6147. return false;
  6148. }
  6149. var precondition;
  6150. if (b.nodeType == DOM.TEXT_NODE) {
  6151. b = b.parentNode;
  6152. // a 和 b父亲相等也就是返回 true
  6153. precondition = true;
  6154. } else if (b.nodeType == DOM.DOCUMENT_NODE) {
  6155. // b === document
  6156. // 没有任何元素能包含 document
  6157. return false;
  6158. } else {
  6159. // a 和 b 相等返回 false
  6160. precondition = a !== b;
  6161. }
  6162. // !a.contains => a===document
  6163. // 注意原生 contains 判断时 a===b 也返回 true
  6164. return precondition && (a.contains ? a.contains(b) : true);
  6165. } : (
  6166. document.documentElement.compareDocumentPosition ?
  6167. function(a, b) {
  6168. return !!(a.compareDocumentPosition(b) & CONTAIN_MASK);
  6169. } :
  6170. // it can not be true , pathetic browser
  6171. 0
  6172. ),
  6173. /**
  6174. * Check to see if a DOM node is within another DOM node.
  6175. */
  6176. contains:
  6177. function(a, b) {
  6178. a = DOM.get(a);
  6179. b = DOM.get(b);
  6180. if (a && b) {
  6181. return DOM.__contains(a, b);
  6182. }
  6183. },
  6184. equals:function(n1, n2) {
  6185. n1 = DOM.query(n1);
  6186. n2 = DOM.query(n2);
  6187. if (n1.length != n2.length) {
  6188. return false;
  6189. }
  6190. for (var i = n1.length; i >= 0; i--) {
  6191. if (n1[i] != n2[i]) {
  6192. return false;
  6193. }
  6194. }
  6195. return true;
  6196. }
  6197. });
  6198. // 获取元素 elem 在 direction 方向上满足 filter 的第一个元素
  6199. // filter 可为 number, selector, fn array ,为数组时返回多个
  6200. // direction 可为 parentNode, nextSibling, previousSibling
  6201. // context : 到某个阶段不再查找直接返回
  6202. function nth(elem, filter, direction, extraFilter, context, includeSef) {
  6203. if (!(elem = DOM.get(elem))) {
  6204. return null;
  6205. }
  6206. if (filter === 0) {
  6207. return elem;
  6208. }
  6209. if (!includeSef) {
  6210. elem = elem[direction];
  6211. }
  6212. if (!elem) {
  6213. return null;
  6214. }
  6215. context = (context && DOM.get(context)) || null;
  6216. if (filter === undefined) {
  6217. // 默认取 1
  6218. filter = 1;
  6219. }
  6220. var ret = [],
  6221. isArray = S.isArray(filter),
  6222. fi,
  6223. flen;
  6224. if (S.isNumber(filter)) {
  6225. fi = 0;
  6226. flen = filter;
  6227. filter = function() {
  6228. return ++fi === flen;
  6229. };
  6230. }
  6231. // 概念统一,都是 context 上下文,只过滤子孙节点,自己不管
  6232. while (elem && elem != context) {
  6233. if (isElementNode(elem)
  6234. && testFilter(elem, filter)
  6235. && (!extraFilter || extraFilter(elem))) {
  6236. ret.push(elem);
  6237. if (!isArray) {
  6238. break;
  6239. }
  6240. }
  6241. elem = elem[direction];
  6242. }
  6243. return isArray ? ret : ret[0] || null;
  6244. }
  6245. function testFilter(elem, filter) {
  6246. if (!filter) {
  6247. return true;
  6248. }
  6249. if (S.isArray(filter)) {
  6250. for (var i = 0; i < filter.length; i++) {
  6251. if (DOM.test(elem, filter[i])) {
  6252. return true;
  6253. }
  6254. }
  6255. } else if (DOM.test(elem, filter)) {
  6256. return true;
  6257. }
  6258. return false;
  6259. }
  6260. // 获取元素 elem 的 siblings, 不包括自身
  6261. function getSiblings(selector, filter, parent) {
  6262. var ret = [],
  6263. elem = DOM.get(selector),
  6264. j,
  6265. parentNode = elem,
  6266. next;
  6267. if (elem && parent) {
  6268. parentNode = elem.parentNode;
  6269. }
  6270. if (parentNode) {
  6271. for (j = 0,next = parentNode.firstChild;
  6272. next;
  6273. next = next.nextSibling) {
  6274. if (isElementNode(next)
  6275. && next !== elem
  6276. && (!filter || DOM.test(next, filter))) {
  6277. ret[j++] = next;
  6278. }
  6279. }
  6280. }
  6281. return ret;
  6282. }
  6283. return DOM;
  6284. }, {
  6285. requires:["./base"]
  6286. });
  6287. /**
  6288. * 2011-08
  6289. * - 添加 closest , first ,last 完全摆脱原生属性
  6290. *
  6291. * NOTES:
  6292. * - jquery does not return null ,it only returns empty array , but kissy does.
  6293. *
  6294. * - api 的设计上,没有跟随 jQuery. 一是为了和其他 api 一致,保持 first-all 原则。二是
  6295. * 遵循 8/2 原则,用尽可能少的代码满足用户最常用的功能。
  6296. *
  6297. */
  6298. KISSY.add("dom", function(S,DOM) {
  6299. return DOM;
  6300. }, {
  6301. requires:["dom/attr",
  6302. "dom/class",
  6303. "dom/create",
  6304. "dom/data",
  6305. "dom/insertion",
  6306. "dom/offset",
  6307. "dom/style",
  6308. "dom/selector",
  6309. "dom/style-ie",
  6310. "dom/traversal"]
  6311. });
  6312. /**
  6313. * @fileOverview some keycodes definition and utils from closure-library
  6314. * @author yiminghe@gmail.com
  6315. */
  6316. KISSY.add("event/keycodes", function() {
  6317. var KeyCodes = {
  6318. MAC_ENTER: 3,
  6319. BACKSPACE: 8,
  6320. TAB: 9,
  6321. NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac
  6322. ENTER: 13,
  6323. SHIFT: 16,
  6324. CTRL: 17,
  6325. ALT: 18,
  6326. PAUSE: 19,
  6327. CAPS_LOCK: 20,
  6328. ESC: 27,
  6329. SPACE: 32,
  6330. PAGE_UP: 33, // also NUM_NORTH_EAST
  6331. PAGE_DOWN: 34, // also NUM_SOUTH_EAST
  6332. END: 35, // also NUM_SOUTH_WEST
  6333. HOME: 36, // also NUM_NORTH_WEST
  6334. LEFT: 37, // also NUM_WEST
  6335. UP: 38, // also NUM_NORTH
  6336. RIGHT: 39, // also NUM_EAST
  6337. DOWN: 40, // also NUM_SOUTH
  6338. PRINT_SCREEN: 44,
  6339. INSERT: 45, // also NUM_INSERT
  6340. DELETE: 46, // also NUM_DELETE
  6341. ZERO: 48,
  6342. ONE: 49,
  6343. TWO: 50,
  6344. THREE: 51,
  6345. FOUR: 52,
  6346. FIVE: 53,
  6347. SIX: 54,
  6348. SEVEN: 55,
  6349. EIGHT: 56,
  6350. NINE: 57,
  6351. QUESTION_MARK: 63, // needs localization
  6352. A: 65,
  6353. B: 66,
  6354. C: 67,
  6355. D: 68,
  6356. E: 69,
  6357. F: 70,
  6358. G: 71,
  6359. H: 72,
  6360. I: 73,
  6361. J: 74,
  6362. K: 75,
  6363. L: 76,
  6364. M: 77,
  6365. N: 78,
  6366. O: 79,
  6367. P: 80,
  6368. Q: 81,
  6369. R: 82,
  6370. S: 83,
  6371. T: 84,
  6372. U: 85,
  6373. V: 86,
  6374. W: 87,
  6375. X: 88,
  6376. Y: 89,
  6377. Z: 90,
  6378. META: 91, // WIN_KEY_LEFT
  6379. WIN_KEY_RIGHT: 92,
  6380. CONTEXT_MENU: 93,
  6381. NUM_ZERO: 96,
  6382. NUM_ONE: 97,
  6383. NUM_TWO: 98,
  6384. NUM_THREE: 99,
  6385. NUM_FOUR: 100,
  6386. NUM_FIVE: 101,
  6387. NUM_SIX: 102,
  6388. NUM_SEVEN: 103,
  6389. NUM_EIGHT: 104,
  6390. NUM_NINE: 105,
  6391. NUM_MULTIPLY: 106,
  6392. NUM_PLUS: 107,
  6393. NUM_MINUS: 109,
  6394. NUM_PERIOD: 110,
  6395. NUM_DIVISION: 111,
  6396. F1: 112,
  6397. F2: 113,
  6398. F3: 114,
  6399. F4: 115,
  6400. F5: 116,
  6401. F6: 117,
  6402. F7: 118,
  6403. F8: 119,
  6404. F9: 120,
  6405. F10: 121,
  6406. F11: 122,
  6407. F12: 123,
  6408. NUMLOCK: 144,
  6409. SEMICOLON: 186, // needs localization
  6410. DASH: 189, // needs localization
  6411. EQUALS: 187, // needs localization
  6412. COMMA: 188, // needs localization
  6413. PERIOD: 190, // needs localization
  6414. SLASH: 191, // needs localization
  6415. APOSTROPHE: 192, // needs localization
  6416. SINGLE_QUOTE: 222, // needs localization
  6417. OPEN_SQUARE_BRACKET: 219, // needs localization
  6418. BACKSLASH: 220, // needs localization
  6419. CLOSE_SQUARE_BRACKET: 221, // needs localization
  6420. WIN_KEY: 224,
  6421. MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
  6422. WIN_IME: 229
  6423. };
  6424. KeyCodes.isTextModifyingKeyEvent = function(e) {
  6425. if (e.altKey && !e.ctrlKey ||
  6426. e.metaKey ||
  6427. // Function keys don't generate text
  6428. e.keyCode >= KeyCodes.F1 &&
  6429. e.keyCode <= KeyCodes.F12) {
  6430. return false;
  6431. }
  6432. // The following keys are quite harmless, even in combination with
  6433. // CTRL, ALT or SHIFT.
  6434. switch (e.keyCode) {
  6435. case KeyCodes.ALT:
  6436. case KeyCodes.CAPS_LOCK:
  6437. case KeyCodes.CONTEXT_MENU:
  6438. case KeyCodes.CTRL:
  6439. case KeyCodes.DOWN:
  6440. case KeyCodes.END:
  6441. case KeyCodes.ESC:
  6442. case KeyCodes.HOME:
  6443. case KeyCodes.INSERT:
  6444. case KeyCodes.LEFT:
  6445. case KeyCodes.MAC_FF_META:
  6446. case KeyCodes.META:
  6447. case KeyCodes.NUMLOCK:
  6448. case KeyCodes.NUM_CENTER:
  6449. case KeyCodes.PAGE_DOWN:
  6450. case KeyCodes.PAGE_UP:
  6451. case KeyCodes.PAUSE:
  6452. case KeyCodes.PHANTOM:
  6453. case KeyCodes.PRINT_SCREEN:
  6454. case KeyCodes.RIGHT:
  6455. case KeyCodes.SHIFT:
  6456. case KeyCodes.UP:
  6457. case KeyCodes.WIN_KEY:
  6458. case KeyCodes.WIN_KEY_RIGHT:
  6459. return false;
  6460. default:
  6461. return true;
  6462. }
  6463. };
  6464. KeyCodes.isCharacterKey = function(keyCode) {
  6465. if (keyCode >= KeyCodes.ZERO &&
  6466. keyCode <= KeyCodes.NINE) {
  6467. return true;
  6468. }
  6469. if (keyCode >= KeyCodes.NUM_ZERO &&
  6470. keyCode <= KeyCodes.NUM_MULTIPLY) {
  6471. return true;
  6472. }
  6473. if (keyCode >= KeyCodes.A &&
  6474. keyCode <= KeyCodes.Z) {
  6475. return true;
  6476. }
  6477. // Safari sends zero key code for non-latin characters.
  6478. if (goog.userAgent.WEBKIT && keyCode == 0) {
  6479. return true;
  6480. }
  6481. switch (keyCode) {
  6482. case KeyCodes.SPACE:
  6483. case KeyCodes.QUESTION_MARK:
  6484. case KeyCodes.NUM_PLUS:
  6485. case KeyCodes.NUM_MINUS:
  6486. case KeyCodes.NUM_PERIOD:
  6487. case KeyCodes.NUM_DIVISION:
  6488. case KeyCodes.SEMICOLON:
  6489. case KeyCodes.DASH:
  6490. case KeyCodes.EQUALS:
  6491. case KeyCodes.COMMA:
  6492. case KeyCodes.PERIOD:
  6493. case KeyCodes.SLASH:
  6494. case KeyCodes.APOSTROPHE:
  6495. case KeyCodes.SINGLE_QUOTE:
  6496. case KeyCodes.OPEN_SQUARE_BRACKET:
  6497. case KeyCodes.BACKSLASH:
  6498. case KeyCodes.CLOSE_SQUARE_BRACKET:
  6499. return true;
  6500. default:
  6501. return false;
  6502. }
  6503. };
  6504. return KeyCodes;
  6505. });
  6506. /**
  6507. * @module EventObject
  6508. * @author lifesinger@gmail.com
  6509. */
  6510. KISSY.add('event/object', function(S, undefined) {
  6511. var doc = document,
  6512. props = ('altKey attrChange attrName bubbles button cancelable ' +
  6513. 'charCode clientX clientY ctrlKey currentTarget data detail ' +
  6514. 'eventPhase fromElement handler keyCode metaKey ' +
  6515. 'newValue offsetX offsetY originalTarget pageX pageY prevValue ' +
  6516. 'relatedNode relatedTarget screenX screenY shiftKey srcElement ' +
  6517. 'target toElement view wheelDelta which axis').split(' ');
  6518. /**
  6519. * KISSY's event system normalizes the event object according to
  6520. * W3C standards. The event object is guaranteed to be passed to
  6521. * the event handler. Most properties from the original event are
  6522. * copied over and normalized to the new event object.
  6523. */
  6524. function EventObject(currentTarget, domEvent, type) {
  6525. var self = this;
  6526. self.currentTarget = currentTarget;
  6527. self.originalEvent = domEvent || { };
  6528. if (domEvent) { // html element
  6529. self.type = domEvent.type;
  6530. self._fix();
  6531. }
  6532. else { // custom
  6533. self.type = type;
  6534. self.target = currentTarget;
  6535. }
  6536. // bug fix: in _fix() method, ie maybe reset currentTarget to undefined.
  6537. self.currentTarget = currentTarget;
  6538. self.fixed = true;
  6539. }
  6540. S.augment(EventObject, {
  6541. _fix: function() {
  6542. var self = this,
  6543. originalEvent = self.originalEvent,
  6544. l = props.length, prop,
  6545. ct = self.currentTarget,
  6546. ownerDoc = (ct.nodeType === 9) ? ct : (ct.ownerDocument || doc); // support iframe
  6547. // clone properties of the original event object
  6548. while (l) {
  6549. prop = props[--l];
  6550. self[prop] = originalEvent[prop];
  6551. }
  6552. // fix target property, if necessary
  6553. if (!self.target) {
  6554. self.target = self.srcElement || doc; // srcElement might not be defined either
  6555. }
  6556. // check if target is a textnode (safari)
  6557. if (self.target.nodeType === 3) {
  6558. self.target = self.target.parentNode;
  6559. }
  6560. // add relatedTarget, if necessary
  6561. if (!self.relatedTarget && self.fromElement) {
  6562. self.relatedTarget = (self.fromElement === self.target) ? self.toElement : self.fromElement;
  6563. }
  6564. // calculate pageX/Y if missing and clientX/Y available
  6565. if (self.pageX === undefined && self.clientX !== undefined) {
  6566. var docEl = ownerDoc.documentElement, bd = ownerDoc.body;
  6567. self.pageX = self.clientX + (docEl && docEl.scrollLeft || bd && bd.scrollLeft || 0) - (docEl && docEl.clientLeft || bd && bd.clientLeft || 0);
  6568. self.pageY = self.clientY + (docEl && docEl.scrollTop || bd && bd.scrollTop || 0) - (docEl && docEl.clientTop || bd && bd.clientTop || 0);
  6569. }
  6570. // add which for key events
  6571. if (self.which === undefined) {
  6572. self.which = (self.charCode === undefined) ? self.keyCode : self.charCode;
  6573. }
  6574. // add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
  6575. if (self.metaKey === undefined) {
  6576. self.metaKey = self.ctrlKey;
  6577. }
  6578. // add which for click: 1 === left; 2 === middle; 3 === right
  6579. // Note: button is not normalized, so don't use it
  6580. if (!self.which && self.button !== undefined) {
  6581. self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : ( self.button & 4 ? 2 : 0)));
  6582. }
  6583. },
  6584. /**
  6585. * Prevents the event's default behavior
  6586. */
  6587. preventDefault: function() {
  6588. var e = this.originalEvent;
  6589. // if preventDefault exists run it on the original event
  6590. if (e.preventDefault) {
  6591. e.preventDefault();
  6592. }
  6593. // otherwise set the returnValue property of the original event to false (IE)
  6594. else {
  6595. e.returnValue = false;
  6596. }
  6597. this.isDefaultPrevented = true;
  6598. },
  6599. /**
  6600. * Stops the propagation to the next bubble target
  6601. */
  6602. stopPropagation: function() {
  6603. var e = this.originalEvent;
  6604. // if stopPropagation exists run it on the original event
  6605. if (e.stopPropagation) {
  6606. e.stopPropagation();
  6607. }
  6608. // otherwise set the cancelBubble property of the original event to true (IE)
  6609. else {
  6610. e.cancelBubble = true;
  6611. }
  6612. this.isPropagationStopped = true;
  6613. },
  6614. /**
  6615. * Stops the propagation to the next bubble target and
  6616. * prevents any additional listeners from being exectued
  6617. * on the current target.
  6618. */
  6619. stopImmediatePropagation: function() {
  6620. var self = this;
  6621. self.isImmediatePropagationStopped = true;
  6622. // fixed 1.2
  6623. // call stopPropagation implicitly
  6624. self.stopPropagation();
  6625. },
  6626. /**
  6627. * Stops the event propagation and prevents the default
  6628. * event behavior.
  6629. * @param immediate {boolean} if true additional listeners
  6630. * on the current target will not be executed
  6631. */
  6632. halt: function(immediate) {
  6633. if (immediate) {
  6634. this.stopImmediatePropagation();
  6635. } else {
  6636. this.stopPropagation();
  6637. }
  6638. this.preventDefault();
  6639. }
  6640. });
  6641. if (1 > 2) {
  6642. alert(S.cancelBubble);
  6643. }
  6644. return EventObject;
  6645. });
  6646. /**
  6647. * NOTES:
  6648. *
  6649. * 2010.04
  6650. * - http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  6651. *
  6652. * TODO:
  6653. * - pageX, clientX, scrollLeft, clientLeft 的详细测试
  6654. */
  6655. /**
  6656. * utils for event
  6657. * @author yiminghe@gmail.com
  6658. */
  6659. KISSY.add("event/utils", function(S, DOM) {
  6660. /**
  6661. * whether two event listens are the same
  6662. * @param h1 已有的 handler 描述
  6663. * @param h2 用户提供的 handler 描述
  6664. */
  6665. function isIdenticalHandler(h1, h2, el) {
  6666. var scope1 = h1.scope || el,
  6667. ret = 1,
  6668. d1,
  6669. d2,
  6670. scope2 = h2.scope || el;
  6671. if (h1.fn !== h2.fn
  6672. || scope1 !== scope2) {
  6673. ret = 0;
  6674. } else if ((d1 = h1.data) !== (d2 = h2.data)) {
  6675. // undelgate 不能 remove 普通 on 的 handler
  6676. // remove 不能 remove delegate 的 handler
  6677. if (!d1 && d2
  6678. || d1 && !d2
  6679. ) {
  6680. ret = 0;
  6681. } else if (d1 && d2) {
  6682. if (!d1.equals || !d2.equals) {
  6683. S.error("no equals in data");
  6684. } else if (!d1.equals(d2,el)) {
  6685. ret = 0;
  6686. }
  6687. }
  6688. }
  6689. return ret;
  6690. }
  6691. function isValidTarget(target) {
  6692. // 3 - is text node
  6693. // 8 - is comment node
  6694. return target &&
  6695. target.nodeType !== DOM.TEXT_NODE &&
  6696. target.nodeType !== DOM.COMMENT_NODE;
  6697. }
  6698. function batchForType(obj, methodName, targets, types) {
  6699. // on(target, 'click focus', fn)
  6700. if (types && types.indexOf(" ") > 0) {
  6701. var args = S.makeArray(arguments);
  6702. S.each(types.split(/\s+/), function(type) {
  6703. var args2 = [].concat(args);
  6704. args2.splice(0, 4, targets, type);
  6705. obj[methodName].apply(obj, args2);
  6706. });
  6707. return true;
  6708. }
  6709. return 0;
  6710. }
  6711. function splitAndRun(type, fn) {
  6712. S.each(type.split(/\s+/), fn);
  6713. }
  6714. var doc = document,
  6715. simpleAdd = doc.addEventListener ?
  6716. function(el, type, fn, capture) {
  6717. if (el.addEventListener) {
  6718. el.addEventListener(type, fn, !!capture);
  6719. }
  6720. } :
  6721. function(el, type, fn) {
  6722. if (el.attachEvent) {
  6723. el.attachEvent('on' + type, fn);
  6724. }
  6725. },
  6726. simpleRemove = doc.removeEventListener ?
  6727. function(el, type, fn, capture) {
  6728. if (el.removeEventListener) {
  6729. el.removeEventListener(type, fn, !!capture);
  6730. }
  6731. } :
  6732. function(el, type, fn) {
  6733. if (el.detachEvent) {
  6734. el.detachEvent('on' + type, fn);
  6735. }
  6736. };
  6737. return {
  6738. splitAndRun:splitAndRun,
  6739. batchForType:batchForType,
  6740. isValidTarget:isValidTarget,
  6741. isIdenticalHandler:isIdenticalHandler,
  6742. simpleAdd:simpleAdd,
  6743. simpleRemove:simpleRemove
  6744. };
  6745. }, {
  6746. requires:['dom']
  6747. });
  6748. /**
  6749. * scalable event framework for kissy (refer DOM3 Events)
  6750. * @author yiminghe@gmail.com,lifesinger@gmail.com
  6751. */
  6752. KISSY.add('event/base', function(S, DOM, EventObject, Utils, undefined) {
  6753. var isValidTarget = Utils.isValidTarget,
  6754. isIdenticalHandler = Utils.isIdenticalHandler,
  6755. batchForType = Utils.batchForType,
  6756. simpleRemove = Utils.simpleRemove,
  6757. simpleAdd = Utils.simpleAdd,
  6758. splitAndRun = Utils.splitAndRun,
  6759. nodeName = DOM._nodeName,
  6760. makeArray = S.makeArray,
  6761. each = S.each,
  6762. trim = S.trim,
  6763. // 记录手工 fire(domElement,type) 时的 type
  6764. // 再在浏览器通知的系统 eventHandler 中检查
  6765. // 如果相同,那么证明已经 fire 过了,不要再次触发了
  6766. Event_Triggered = "",
  6767. TRIGGERED_NONE = "trigger-none-" + S.now(),
  6768. EVENT_SPECIAL = {},
  6769. // 事件存储位置 key
  6770. // { handler: eventHandler, events: {type:[{scope:scope,fn:fn}]} } }
  6771. EVENT_GUID = 'ksEventTargetId' + S.now();
  6772. /**
  6773. * @name Event
  6774. * @namespace
  6775. */
  6776. var Event = {
  6777. _clone:function(src, dest) {
  6778. if (dest.nodeType !== DOM.ELEMENT_NODE ||
  6779. !Event._hasData(src)) {
  6780. return;
  6781. }
  6782. var eventDesc = Event._data(src),
  6783. events = eventDesc.events;
  6784. each(events, function(handlers, type) {
  6785. each(handlers, function(handler) {
  6786. // scope undefined 时不能写死在 handlers 中,否则不能保证 clone 时的 this
  6787. Event.on(dest, type, handler.fn, handler.scope, handler.data);
  6788. });
  6789. });
  6790. },
  6791. _hasData:function(elem) {
  6792. return DOM.hasData(elem, EVENT_GUID);
  6793. },
  6794. _data:function(elem) {
  6795. var args = makeArray(arguments);
  6796. args.splice(1, 0, EVENT_GUID);
  6797. return DOM.data.apply(DOM, args);
  6798. },
  6799. _removeData:function(elem) {
  6800. var args = makeArray(arguments);
  6801. args.splice(1, 0, EVENT_GUID);
  6802. return DOM.removeData.apply(DOM, args);
  6803. },
  6804. // such as: { 'mouseenter' : { setup:fn ,tearDown:fn} }
  6805. special: EVENT_SPECIAL,
  6806. // single type , single target , fixed native
  6807. __add:function(isNativeTarget, target, type, fn, scope, data) {
  6808. var eventDesc;
  6809. // 不是有效的 target 或 参数不对
  6810. if (!target ||
  6811. !S.isFunction(fn) ||
  6812. (isNativeTarget && !isValidTarget(target))) {
  6813. return;
  6814. }
  6815. // 获取事件描述
  6816. eventDesc = Event._data(target);
  6817. if (!eventDesc) {
  6818. Event._data(target, eventDesc = {});
  6819. }
  6820. //事件 listeners , similar to eventListeners in DOM3 Events
  6821. var events = eventDesc.events = eventDesc.events || {},
  6822. handlers = events[type] = events[type] || [],
  6823. handleObj = {
  6824. fn: fn,
  6825. scope: scope,
  6826. data:data
  6827. },
  6828. eventHandler = eventDesc.handler;
  6829. // 该元素没有 handler ,并且该元素是 dom 节点时才需要注册 dom 事件
  6830. if (!eventHandler) {
  6831. eventHandler = eventDesc.handler = function(event, data) {
  6832. // 是经过 fire 手动调用而浏览器同步触发导致的,就不要再次触发了,
  6833. // 已经在 fire 中 bubble 过一次了
  6834. if (event && event.type == Event_Triggered) {
  6835. return;
  6836. }
  6837. var currentTarget = eventHandler.target;
  6838. if (!event || !event.fixed) {
  6839. event = new EventObject(currentTarget, event);
  6840. }
  6841. var type = event.type;
  6842. if (S.isPlainObject(data)) {
  6843. S.mix(event, data);
  6844. }
  6845. // protect type
  6846. if (type) {
  6847. event.type = type;
  6848. }
  6849. return _handle(currentTarget, event);
  6850. };
  6851. // as for native dom event , this represents currentTarget !
  6852. eventHandler.target = target;
  6853. }
  6854. for (var i = handlers.length - 1; i >= 0; --i) {
  6855. /**
  6856. * If multiple identical EventListeners are registered on the same EventTarget
  6857. * with the same parameters the duplicate instances are discarded.
  6858. * They do not cause the EventListener to be called twice
  6859. * and since they are discarded
  6860. * they do not need to be removed with the removeEventListener method.
  6861. */
  6862. if (isIdenticalHandler(handlers[i], handleObj, target)) {
  6863. return;
  6864. }
  6865. }
  6866. if (isNativeTarget) {
  6867. addDomEvent(target, type, eventHandler, handlers, handleObj);
  6868. //nullify to prevent memory leak in ie ?
  6869. target = null;
  6870. }
  6871. // 增加 listener
  6872. handlers.push(handleObj);
  6873. },
  6874. /**
  6875. * Adds an event listener.similar to addEventListener in DOM3 Events
  6876. * @param targets KISSY selector
  6877. * @param type {String} The type of event to append.
  6878. * @param fn {Function} The event handler/listener.
  6879. * @param scope {Object} (optional) The scope (this reference) in which the handler function is executed.
  6880. */
  6881. add: function(targets, type, fn, scope /* optional */, data/*internal usage*/) {
  6882. type = trim(type);
  6883. // data : 附加在回调后面的数据,delegate 检查使用
  6884. // remove 时 data 相等(指向同一对象或者定义了 equals 比较函数)
  6885. if (batchForType(Event, 'add', targets, type, fn, scope, data)) {
  6886. return targets;
  6887. }
  6888. DOM.query(targets).each(function(target) {
  6889. Event.__add(true, target, type, fn, scope, data);
  6890. });
  6891. return targets;
  6892. },
  6893. // single target, single type, fixed native
  6894. __remove:function(isNativeTarget, target, type, fn, scope, data) {
  6895. if (
  6896. !target ||
  6897. (isNativeTarget && !isValidTarget(target))
  6898. ) {
  6899. return;
  6900. }
  6901. var eventDesc = Event._data(target),
  6902. events = eventDesc && eventDesc.events,
  6903. handlers,
  6904. len,
  6905. i,
  6906. j,
  6907. t,
  6908. special = (isNativeTarget && EVENT_SPECIAL[type]) || { };
  6909. if (!events) {
  6910. return;
  6911. }
  6912. // remove all types of event
  6913. if (!type) {
  6914. for (type in events) {
  6915. Event.__remove(isNativeTarget, target, type);
  6916. }
  6917. return;
  6918. }
  6919. if ((handlers = events[type])) {
  6920. len = handlers.length;
  6921. // 移除 fn
  6922. if (fn && len) {
  6923. var currentHandler = {
  6924. data:data,
  6925. fn:fn,
  6926. scope:scope
  6927. },handler;
  6928. for (i = 0,j = 0,t = []; i < len; ++i) {
  6929. handler = handlers[i];
  6930. // 注意顺序,用户提供的 handler 在第二个参数
  6931. if (!isIdenticalHandler(handler, currentHandler, target)) {
  6932. t[j++] = handler;
  6933. } else if (special.remove) {
  6934. special.remove.call(target, handler);
  6935. }
  6936. }
  6937. events[type] = t;
  6938. len = t.length;
  6939. }
  6940. // remove(el, type) or fn 已移除光
  6941. if (fn === undefined || len === 0) {
  6942. // dom node need to detach handler from dom node
  6943. if (isNativeTarget &&
  6944. (!special['tearDown'] ||
  6945. special['tearDown'].call(target) === false)) {
  6946. simpleRemove(target, type, eventDesc.handler);
  6947. }
  6948. // remove target's single event description
  6949. delete events[type];
  6950. }
  6951. }
  6952. // remove target's all events description
  6953. if (S.isEmptyObject(events)) {
  6954. eventDesc.handler.target = null;
  6955. delete eventDesc.handler;
  6956. delete eventDesc.events;
  6957. Event._removeData(target);
  6958. }
  6959. },
  6960. /**
  6961. * Detach an event or set of events from an element. similar to removeEventListener in DOM3 Events
  6962. * @param targets KISSY selector
  6963. * @param type {String} The type of event to append.
  6964. * @param fn {Function} The event handler/listener.
  6965. * @param scope {Object} (optional) The scope (this reference) in which the handler function is executed.
  6966. */
  6967. remove: function(targets, type /* optional */, fn /* optional */, scope /* optional */, data/*internal usage*/) {
  6968. type = trim(type);
  6969. if (batchForType(Event, 'remove', targets, type, fn, scope)) {
  6970. return targets;
  6971. }
  6972. DOM.query(targets).each(function(target) {
  6973. Event.__remove(true, target, type, fn, scope, data);
  6974. });
  6975. return targets;
  6976. },
  6977. _handle:_handle,
  6978. /**
  6979. * fire event , simulate bubble in browser. similar to dispatchEvent in DOM3 Events
  6980. * @return boolean The return value of fire/dispatchEvent indicates
  6981. * whether any of the listeners which handled the event called preventDefault.
  6982. * If preventDefault was called the value is false, else the value is true.
  6983. */
  6984. fire: function(targets, eventType, eventData, onlyHandlers) {
  6985. var ret = true;
  6986. eventType = trim(eventType);
  6987. if (eventType.indexOf(" ") > -1) {
  6988. splitAndRun(eventType, function(t) {
  6989. ret = Event.fire(targets, t, eventData, onlyHandlers) && ret;
  6990. });
  6991. return ret;
  6992. }
  6993. // custom event firing moved to target.js
  6994. eventData = eventData || {};
  6995. // protect event type
  6996. eventData.type = eventType;
  6997. DOM.query(targets).each(function(target) {
  6998. ret = fireDOMEvent(target, eventType, eventData, onlyHandlers) && ret;
  6999. });
  7000. return ret;
  7001. }
  7002. };
  7003. // for compatibility
  7004. Event['__getListeners'] = getListeners
  7005. // shorthand
  7006. Event.on = Event.add;
  7007. Event.detach = Event.remove;
  7008. function getListeners(target, type) {
  7009. var events = getEvents(target) || {};
  7010. return events[type] || [];
  7011. }
  7012. function _handle(target, event) {
  7013. /* As some listeners may remove themselves from the
  7014. event, the original array length is dynamic. So,
  7015. let's make a copy of all listeners, so we are
  7016. sure we'll call all of them.*/
  7017. /**
  7018. * DOM3 Events: EventListenerList objects in the DOM are live. ??
  7019. */
  7020. var listeners = getListeners(target, event.type).slice(0),
  7021. ret,
  7022. gRet,
  7023. i = 0,
  7024. len = listeners.length,
  7025. listener;
  7026. for (; i < len; ++i) {
  7027. listener = listeners[i];
  7028. // 传入附件参数data,目前用于委托
  7029. // scope undefined 时不能写死在 listener 中,否则不能保证 clone 时的 this
  7030. ret = listener.fn.call(listener.scope || target,
  7031. event, listener.data);
  7032. // 和 jQuery 逻辑保持一致
  7033. if (ret !== undefined) {
  7034. // 有一个 false,最终结果就是 false
  7035. // 否则等于最后一个返回值
  7036. if (gRet !== false) {
  7037. gRet = ret;
  7038. }
  7039. // return false 等价 preventDefault + stopProgation
  7040. if (ret === false) {
  7041. event.halt();
  7042. }
  7043. }
  7044. if (event.isImmediatePropagationStopped) {
  7045. break;
  7046. }
  7047. }
  7048. // fire 时判断如果 preventDefault,则返回 false 否则返回 true
  7049. // 这里返回值意义不同
  7050. return gRet;
  7051. }
  7052. function getEvents(target) {
  7053. // 获取事件描述
  7054. var eventDesc = Event._data(target);
  7055. return eventDesc && eventDesc.events;
  7056. }
  7057. /**
  7058. * dom node need eventHandler attached to dom node
  7059. */
  7060. function addDomEvent(target, type, eventHandler, handlers, handleObj) {
  7061. var special = EVENT_SPECIAL[type] || {};
  7062. // 第一次注册该事件,dom 节点才需要注册 dom 事件
  7063. if (!handlers.length &&
  7064. (!special.setup || special.setup.call(target) === false)) {
  7065. simpleAdd(target, type, eventHandler)
  7066. }
  7067. if (special.add) {
  7068. special.add.call(target, handleObj);
  7069. }
  7070. }
  7071. /**
  7072. * fire dom event from bottom to up , emulate dispatchEvent in DOM3 Events
  7073. * @return boolean The return value of dispatchEvent indicates
  7074. * whether any of the listeners which handled the event called preventDefault.
  7075. * If preventDefault was called the value is false, else the value is true.
  7076. */
  7077. function fireDOMEvent(target, eventType, eventData, onlyHandlers) {
  7078. if (!isValidTarget(target)) {
  7079. return false;
  7080. }
  7081. var event,
  7082. ret = true;
  7083. if (eventData instanceof EventObject) {
  7084. event = eventData;
  7085. } else {
  7086. event = new EventObject(target, undefined, eventType);
  7087. S.mix(event, eventData);
  7088. }
  7089. /*
  7090. The target of the event is the EventTarget on which dispatchEvent is called.
  7091. */
  7092. // TODO: protect target , but incompatible
  7093. // event.target=target;
  7094. // protect type
  7095. event.type = eventType;
  7096. // 只运行自己的绑定函数,不冒泡也不触发默认行为
  7097. if (onlyHandlers) {
  7098. event.halt();
  7099. }
  7100. var cur = target,
  7101. ontype = "on" + eventType;
  7102. //bubble up dom tree
  7103. do{
  7104. event.currentTarget = cur;
  7105. _handle(cur, event);
  7106. // Trigger an inline bound script
  7107. if (cur[ ontype ] &&
  7108. cur[ ontype ].call(cur) === false) {
  7109. event.preventDefault();
  7110. }
  7111. // Bubble up to document, then to window
  7112. cur = cur.parentNode ||
  7113. cur.ownerDocument ||
  7114. cur === target.ownerDocument && window;
  7115. } while (cur && !event.isPropagationStopped);
  7116. if (!event.isDefaultPrevented) {
  7117. if (!(eventType === "click" &&
  7118. nodeName(target, "a"))) {
  7119. var old;
  7120. try {
  7121. if (ontype && target[ eventType ]) {
  7122. // Don't re-trigger an onFOO event when we call its FOO() method
  7123. old = target[ ontype ];
  7124. if (old) {
  7125. target[ ontype ] = null;
  7126. }
  7127. // 记录当前 trigger 触发
  7128. Event_Triggered = eventType;
  7129. // 只触发默认事件,而不要执行绑定的用户回调
  7130. // 同步触发
  7131. target[ eventType ]();
  7132. }
  7133. } catch (ieError) {
  7134. S.log("trigger action error : ");
  7135. S.log(ieError);
  7136. }
  7137. if (old) {
  7138. target[ ontype ] = old;
  7139. }
  7140. Event_Triggered = TRIGGERED_NONE;
  7141. }
  7142. } else {
  7143. ret = false;
  7144. }
  7145. return ret;
  7146. }
  7147. return Event;
  7148. }, {
  7149. requires:["dom","./object","./utils"]
  7150. });
  7151. /**
  7152. * 2011-11-24
  7153. * - 自定义事件和 dom 事件操作彻底分离
  7154. * - TODO: group event from DOM3 Event
  7155. *
  7156. * 2011-06-07
  7157. * - refer : http://www.w3.org/TR/2001/WD-DOM-Level-3-Events-20010823/events.html
  7158. * - 重构
  7159. * - eventHandler 一个元素一个而不是一个元素一个事件一个,节省内存
  7160. * - 减少闭包使用,prevent ie 内存泄露?
  7161. * - 增加 fire ,模拟冒泡处理 dom 事件
  7162. */
  7163. /**
  7164. * @module EventTarget
  7165. * @author yiminghe@gmail.com
  7166. */
  7167. KISSY.add('event/target', function(S, Event, EventObject, Utils, undefined) {
  7168. var KS_PUBLISH = "__~ks_publish",
  7169. trim = S.trim,
  7170. splitAndRun = Utils.splitAndRun,
  7171. KS_BUBBLE_TARGETS = "__~ks_bubble_targets",
  7172. ALL_EVENT = "*";
  7173. function getCustomEvent(self, type, eventData) {
  7174. if (eventData instanceof EventObject) {
  7175. // set currentTarget in the process of bubbling
  7176. eventData.currentTarget = self;
  7177. return eventData;
  7178. }
  7179. var customEvent = new EventObject(self, undefined, type);
  7180. if (S.isPlainObject(eventData)) {
  7181. S.mix(customEvent, eventData);
  7182. }
  7183. // protect type
  7184. customEvent.type = type;
  7185. return customEvent
  7186. }
  7187. function getEventPublishObj(self) {
  7188. self[KS_PUBLISH] = self[KS_PUBLISH] || {};
  7189. return self[KS_PUBLISH];
  7190. }
  7191. function getBubbleTargetsObj(self) {
  7192. self[KS_BUBBLE_TARGETS] = self[KS_BUBBLE_TARGETS] || {};
  7193. return self[KS_BUBBLE_TARGETS];
  7194. }
  7195. function isBubblable(self, eventType) {
  7196. var publish = getEventPublishObj(self);
  7197. return publish[eventType] && publish[eventType].bubbles || publish[ALL_EVENT] && publish[ALL_EVENT].bubbles
  7198. }
  7199. function attach(method) {
  7200. return function(type, fn, scope) {
  7201. var self = this;
  7202. type = trim(type);
  7203. splitAndRun(type, function(t) {
  7204. Event["__" + method](false, self, t, fn, scope);
  7205. });
  7206. return self; // chain
  7207. };
  7208. }
  7209. /**
  7210. * 提供事件发布和订阅机制
  7211. * @name Target
  7212. * @memberOf Event
  7213. */
  7214. var Target =
  7215. /**
  7216. * @lends Event.Target
  7217. */
  7218. {
  7219. /**
  7220. * 触发事件
  7221. * @param {String} type 事件名
  7222. * @param {Object} eventData 事件附加信息对象
  7223. * @returns 如果一个 listener 返回false,则返回 false ,否则返回最后一个 listener 的值.
  7224. */
  7225. fire: function(type, eventData) {
  7226. var self = this,
  7227. ret,
  7228. r2,
  7229. customEvent;
  7230. type = trim(type);
  7231. if (type.indexOf(" ") > 0) {
  7232. splitAndRun(type, function(t) {
  7233. r2 = self.fire(t, eventData);
  7234. if (r2 === false) {
  7235. ret = false;
  7236. }
  7237. });
  7238. return ret;
  7239. }
  7240. customEvent = getCustomEvent(self, type, eventData);
  7241. ret = Event._handle(self, customEvent);
  7242. if (!customEvent.isPropagationStopped &&
  7243. isBubblable(self, type)) {
  7244. r2 = self.bubble(type, customEvent);
  7245. // false 优先返回
  7246. if (ret !== false) {
  7247. ret = r2;
  7248. }
  7249. }
  7250. return ret
  7251. },
  7252. /**
  7253. * defined event config
  7254. * @param type
  7255. * @param cfg
  7256. * example { bubbles: true}
  7257. * default bubbles: false
  7258. */
  7259. publish: function(type, cfg) {
  7260. var self = this,
  7261. publish = getEventPublishObj(self);
  7262. type = trim(type);
  7263. if (type) {
  7264. publish[type] = cfg;
  7265. }
  7266. },
  7267. /**
  7268. * bubble event to its targets
  7269. * @param type
  7270. * @param eventData
  7271. */
  7272. bubble: function(type, eventData) {
  7273. var self = this,
  7274. ret,
  7275. targets = getBubbleTargetsObj(self);
  7276. S.each(targets, function(t) {
  7277. var r2 = t.fire(type, eventData);
  7278. if (ret !== false) {
  7279. ret = r2;
  7280. }
  7281. });
  7282. return ret;
  7283. },
  7284. /**
  7285. * add target which bubblable event bubbles towards
  7286. * @param target another EventTarget instance
  7287. */
  7288. addTarget: function(target) {
  7289. var self = this,
  7290. targets = getBubbleTargetsObj(self);
  7291. targets[S.stamp(target)] = target;
  7292. },
  7293. removeTarget:function(target) {
  7294. var self = this,
  7295. targets = getBubbleTargetsObj(self);
  7296. delete targets[S.stamp(target)];
  7297. },
  7298. /**
  7299. * 监听事件
  7300. * @param {String} type 事件名
  7301. * @param {Function} fn 事件处理器
  7302. * @param {Object} scope 事件处理器内的 this 值,默认当前实例
  7303. * @returns 当前实例
  7304. */
  7305. on: attach("add")
  7306. };
  7307. /**
  7308. * 取消监听事件
  7309. * @param {String} type 事件名
  7310. * @param {Function} fn 事件处理器
  7311. * @param {Object} scope 事件处理器内的 this 值,默认当前实例
  7312. * @returns 当前实例
  7313. */
  7314. Target.detach = attach("remove");
  7315. return Target;
  7316. }, {
  7317. /*
  7318. 实际上只需要 dom/data ,但是不要跨模块引用另一模块的子模块,
  7319. 否则会导致build打包文件 dom 和 dom-data 重复载入
  7320. */
  7321. requires:["./base",'./object','./utils']
  7322. });
  7323. /**
  7324. * yiminghe:2011-10-17
  7325. * - implement bubble for custom event
  7326. **/
  7327. /**
  7328. * @module event-focusin
  7329. * @author yiminghe@gmail.com
  7330. */
  7331. KISSY.add('event/focusin', function(S, UA, Event) {
  7332. // 让非 IE 浏览器支持 focusin/focusout
  7333. if (!UA['ie']) {
  7334. S.each([
  7335. { name: 'focusin', fix: 'focus' },
  7336. { name: 'focusout', fix: 'blur' }
  7337. ], function(o) {
  7338. var attaches = 0;
  7339. Event.special[o.name] = {
  7340. // 统一在 document 上 capture focus/blur 事件,然后模拟冒泡 fire 出来
  7341. // 达到和 focusin 一样的效果 focusin -> focus
  7342. // refer: http://yiminghe.iteye.com/blog/813255
  7343. setup: function() {
  7344. if (attaches++ === 0) {
  7345. document.addEventListener(o.fix, handler, true);
  7346. }
  7347. },
  7348. tearDown:function() {
  7349. if (--attaches === 0) {
  7350. document.removeEventListener(o.fix, handler, true);
  7351. }
  7352. }
  7353. };
  7354. function handler(event) {
  7355. var target = event.target;
  7356. return Event.fire(target, o.name);
  7357. }
  7358. });
  7359. }
  7360. return Event;
  7361. }, {
  7362. requires:["ua","./base"]
  7363. });
  7364. /**
  7365. * 承玉:2011-06-07
  7366. * - refactor to jquery , 更加合理的模拟冒泡顺序,子元素先出触发,父元素后触发
  7367. *
  7368. * NOTES:
  7369. * - webkit 和 opera 已支持 DOMFocusIn/DOMFocusOut 事件,但上面的写法已经能达到预期效果,暂时不考虑原生支持。
  7370. */
  7371. /**
  7372. * @module event-hashchange
  7373. * @author yiminghe@gmail.com , xiaomacji@gmail.com
  7374. */
  7375. KISSY.add('event/hashchange', function(S, Event, DOM, UA) {
  7376. var doc = document,
  7377. docMode = doc['documentMode'],
  7378. ie = docMode || UA['ie'],
  7379. HASH_CHANGE = 'hashchange';
  7380. // ie8 支持 hashchange
  7381. // 但IE8以上切换浏览器模式到IE7(兼容模式),会导致 'onhashchange' in window === true,但是不触发事件
  7382. // 1. 不支持 hashchange 事件,支持 hash 导航(opera??):定时器监控
  7383. // 2. 不支持 hashchange 事件,不支持 hash 导航(ie67) : iframe + 定时器
  7384. if ((!( 'on' + HASH_CHANGE in window)) || ie && ie < 8) {
  7385. function getIframeDoc(iframe) {
  7386. return iframe.contentWindow.document;
  7387. }
  7388. var POLL_INTERVAL = 50,
  7389. win = window,
  7390. IFRAME_TEMPLATE = "<html><head><title>" + (doc.title || "") +
  7391. " - {hash}</title>{head}</head><body>{hash}</body></html>",
  7392. getHash = function() {
  7393. // 不能 location.hash
  7394. // http://xx.com/#yy?z=1
  7395. // ie6 => location.hash = #yy
  7396. // 其他浏览器 => location.hash = #yy?z=1
  7397. var url = location.href;
  7398. return '#' + url.replace(/^[^#]*#?(.*)$/, '$1');
  7399. },
  7400. timer,
  7401. // 用于定时器检测,上次定时器记录的 hash 值
  7402. lastHash,
  7403. poll = function () {
  7404. var hash = getHash();
  7405. if (hash !== lastHash) {
  7406. // S.log("poll success :" + hash + " :" + lastHash);
  7407. // 通知完调用者 hashchange 事件前设置 lastHash
  7408. lastHash = hash;
  7409. // ie<8 同步 : hashChange -> onIframeLoad
  7410. hashChange(hash);
  7411. }
  7412. timer = setTimeout(poll, POLL_INTERVAL);
  7413. },
  7414. hashChange = ie && ie < 8 ? function(hash) {
  7415. // S.log("set iframe html :" + hash);
  7416. var html = S.substitute(IFRAME_TEMPLATE, {
  7417. hash: hash,
  7418. // 一定要加哦
  7419. head:DOM._isCustomDomain() ? "<script>document.domain = '" +
  7420. doc.domain
  7421. + "';</script>" : ""
  7422. }),
  7423. iframeDoc = getIframeDoc(iframe);
  7424. try {
  7425. // 写入历史 hash
  7426. iframeDoc.open();
  7427. // 取时要用 innerText !!
  7428. // 否则取 innerHtml 会因为 escapeHtml 导置 body.innerHTMl != hash
  7429. iframeDoc.write(html);
  7430. iframeDoc.close();
  7431. // 立刻同步调用 onIframeLoad !!!!
  7432. } catch (e) {
  7433. // S.log('doc write error : ', 'error');
  7434. // S.log(e, 'error');
  7435. }
  7436. } : function () {
  7437. notifyHashChange();
  7438. },
  7439. notifyHashChange = function () {
  7440. // S.log("hash changed : " + getHash());
  7441. Event.fire(win, HASH_CHANGE);
  7442. },
  7443. setup = function () {
  7444. if (!timer) {
  7445. poll();
  7446. }
  7447. },
  7448. tearDown = function () {
  7449. timer && clearTimeout(timer);
  7450. timer = 0;
  7451. },
  7452. iframe;
  7453. // ie6, 7, 覆盖一些function
  7454. if (ie < 8) {
  7455. /**
  7456. * 前进后退 : start -> notifyHashChange
  7457. * 直接输入 : poll -> hashChange -> start
  7458. * iframe 内容和 url 同步
  7459. */
  7460. setup = function() {
  7461. if (!iframe) {
  7462. var iframeSrc = DOM._genEmptyIframeSrc();
  7463. //http://www.paciellogroup.com/blog/?p=604
  7464. iframe = DOM.create('<iframe ' +
  7465. (iframeSrc ? 'src="' + iframeSrc + '"' : '') +
  7466. ' style="display: none" ' +
  7467. 'height="0" ' +
  7468. 'width="0" ' +
  7469. 'tabindex="-1" ' +
  7470. 'title="empty"/>');
  7471. // Append the iframe to the documentElement rather than the body.
  7472. // Keeping it outside the body prevents scrolling on the initial
  7473. // page load
  7474. DOM.prepend(iframe, doc.documentElement);
  7475. // init,第一次触发,以后都是 onIframeLoad
  7476. Event.add(iframe, "load", function() {
  7477. Event.remove(iframe, "load");
  7478. // Update the iframe with the initial location hash, if any. This
  7479. // will create an initial history entry that the user can return to
  7480. // after the state has changed.
  7481. hashChange(getHash());
  7482. Event.add(iframe, "load", onIframeLoad);
  7483. poll();
  7484. });
  7485. // Whenever `document.title` changes, update the Iframe's title to
  7486. // prettify the back/next history menu entries. Since IE sometimes
  7487. // errors with "Unspecified error" the very first time this is set
  7488. // (yes, very useful) wrap this with a try/catch block.
  7489. doc.onpropertychange = function() {
  7490. try {
  7491. if (event.propertyName === 'title') {
  7492. getIframeDoc(iframe).title =
  7493. doc.title + " - " + getHash();
  7494. }
  7495. } catch(e) {
  7496. }
  7497. };
  7498. /**
  7499. * 前进后退 : onIframeLoad -> 触发
  7500. * 直接输入 : timer -> hashChange -> onIframeLoad -> 触发
  7501. * 触发统一在 start(load)
  7502. * iframe 内容和 url 同步
  7503. */
  7504. function onIframeLoad() {
  7505. // S.log('iframe start load..');
  7506. // 2011.11.02 note: 不能用 innerHtml 会自动转义!!
  7507. // #/x?z=1&y=2 => #/x?z=1&amp;y=2
  7508. var c = S.trim(getIframeDoc(iframe).body.innerText),
  7509. ch = getHash();
  7510. // 后退时不等
  7511. // 定时器调用 hashChange() 修改 iframe 同步调用过来的(手动改变 location)则相等
  7512. if (c != ch) {
  7513. S.log("set loc hash :" + c);
  7514. location.hash = c;
  7515. // 使lasthash为 iframe 历史, 不然重新写iframe,
  7516. // 会导致最新状态(丢失前进状态)
  7517. // 后退则立即触发 hashchange,
  7518. // 并更新定时器记录的上个 hash 值
  7519. lastHash = c;
  7520. }
  7521. notifyHashChange();
  7522. }
  7523. }
  7524. };
  7525. tearDown = function() {
  7526. timer && clearTimeout(timer);
  7527. timer = 0;
  7528. Event.detach(iframe);
  7529. DOM.remove(iframe);
  7530. iframe = 0;
  7531. };
  7532. }
  7533. Event.special[HASH_CHANGE] = {
  7534. setup: function() {
  7535. if (this !== win) {
  7536. return;
  7537. }
  7538. // 第一次启动 hashchange 时取一下,不能类库载入后立即取
  7539. // 防止类库嵌入后,手动修改过 hash,
  7540. lastHash = getHash();
  7541. // 不用注册 dom 事件
  7542. setup();
  7543. },
  7544. tearDown: function() {
  7545. if (this !== win) {
  7546. return;
  7547. }
  7548. tearDown();
  7549. }
  7550. };
  7551. }
  7552. }, {
  7553. requires:["./base","dom","ua"]
  7554. });
  7555. /**
  7556. * 已知 bug :
  7557. * - ie67 有时后退后取得的 location.hash 不和地址栏一致,导致必须后退两次才能触发 hashchange
  7558. *
  7559. * v1 : 2010-12-29
  7560. * v1.1: 支持非IE,但不支持onhashchange事件的浏览器(例如低版本的firefox、safari)
  7561. * refer : http://yiminghe.javaeye.com/blog/377867
  7562. * https://github.com/cowboy/jquery-hashchange
  7563. */
  7564. /**
  7565. * inspired by yui3 :
  7566. *
  7567. * Synthetic event that fires when the <code>value</code> property of an input
  7568. * field or textarea changes as a result of a keystroke, mouse operation, or
  7569. * input method editor (IME) input event.
  7570. *
  7571. * Unlike the <code>onchange</code> event, this event fires when the value
  7572. * actually changes and not when the element loses focus. This event also
  7573. * reports IME and multi-stroke input more reliably than <code>oninput</code> or
  7574. * the various key events across browsers.
  7575. *
  7576. * @author yiminghe@gmail.com
  7577. */
  7578. KISSY.add('event/valuechange', function (S, Event, DOM) {
  7579. var VALUE_CHANGE = "valuechange",
  7580. nodeName = DOM._nodeName,
  7581. KEY = "event/valuechange",
  7582. HISTORY_KEY = KEY + "/history",
  7583. POLL_KEY = KEY + "/poll",
  7584. interval = 50;
  7585. function stopPoll(target) {
  7586. DOM.removeData(target, HISTORY_KEY);
  7587. if (DOM.hasData(target, POLL_KEY)) {
  7588. var poll = DOM.data(target, POLL_KEY);
  7589. clearTimeout(poll);
  7590. DOM.removeData(target, POLL_KEY);
  7591. }
  7592. }
  7593. function stopPollHandler(ev) {
  7594. var target = ev.target;
  7595. stopPoll(target);
  7596. }
  7597. function startPoll(target) {
  7598. if (DOM.hasData(target, POLL_KEY)) return;
  7599. DOM.data(target, POLL_KEY, setTimeout(function () {
  7600. var v = target.value, h = DOM.data(target, HISTORY_KEY);
  7601. if (v !== h) {
  7602. // 只触发自己绑定的 handler
  7603. Event.fire(target, VALUE_CHANGE, {
  7604. prevVal:h,
  7605. newVal:v
  7606. }, true);
  7607. DOM.data(target, HISTORY_KEY, v);
  7608. }
  7609. DOM.data(target, POLL_KEY, setTimeout(arguments.callee, interval));
  7610. }, interval));
  7611. }
  7612. function startPollHandler(ev) {
  7613. var target = ev.target;
  7614. // when focus ,record its current value immediately
  7615. if (ev.type == "focus") {
  7616. DOM.data(target, HISTORY_KEY, target.value);
  7617. }
  7618. startPoll(target);
  7619. }
  7620. function monitor(target) {
  7621. unmonitored(target);
  7622. Event.on(target, "blur", stopPollHandler);
  7623. Event.on(target, "mousedown keyup keydown focus", startPollHandler);
  7624. }
  7625. function unmonitored(target) {
  7626. stopPoll(target);
  7627. Event.remove(target, "blur", stopPollHandler);
  7628. Event.remove(target, "mousedown keyup keydown focus", startPollHandler);
  7629. }
  7630. Event.special[VALUE_CHANGE] = {
  7631. setup:function () {
  7632. var target = this;
  7633. if (nodeName(target, "input")
  7634. || nodeName(target, "textarea")) {
  7635. monitor(target);
  7636. }
  7637. },
  7638. tearDown:function () {
  7639. var target = this;
  7640. unmonitored(target);
  7641. }
  7642. };
  7643. return Event;
  7644. }, {
  7645. requires:["./base", "dom"]
  7646. });
  7647. /**
  7648. * kissy delegate for event module
  7649. * @author yiminghe@gmail.com
  7650. */
  7651. KISSY.add("event/delegate", function(S, DOM, Event, Utils) {
  7652. var batchForType = Utils.batchForType,
  7653. delegateMap = {
  7654. "focus":{
  7655. type:"focusin"
  7656. },
  7657. "blur":{
  7658. type:"focusout"
  7659. },
  7660. "mouseenter":{
  7661. type:"mouseover",
  7662. handler:mouseHandler
  7663. },
  7664. "mouseleave":{
  7665. type:"mouseout",
  7666. handler:mouseHandler
  7667. }
  7668. };
  7669. S.mix(Event, {
  7670. delegate:function(targets, type, selector, fn, scope) {
  7671. if (batchForType(Event, 'delegate', targets, type, selector, fn, scope)) {
  7672. return targets;
  7673. }
  7674. DOM.query(targets).each(function(target) {
  7675. var preType = type,handler = delegateHandler;
  7676. if (delegateMap[type]) {
  7677. type = delegateMap[preType].type;
  7678. handler = delegateMap[preType].handler || handler;
  7679. }
  7680. Event.on(target, type, handler, target, {
  7681. fn:fn,
  7682. selector:selector,
  7683. preType:preType,
  7684. scope:scope,
  7685. equals:equals
  7686. });
  7687. });
  7688. return targets;
  7689. },
  7690. undelegate:function(targets, type, selector, fn, scope) {
  7691. if (batchForType(Event, 'undelegate', targets, type, selector, fn, scope)) {
  7692. return targets;
  7693. }
  7694. DOM.query(targets).each(function(target) {
  7695. var preType = type,
  7696. handler = delegateHandler;
  7697. if (delegateMap[type]) {
  7698. type = delegateMap[preType].type;
  7699. handler = delegateMap[preType].handler || handler;
  7700. }
  7701. Event.remove(target, type, handler, target, {
  7702. fn:fn,
  7703. selector:selector,
  7704. preType:preType,
  7705. scope:scope,
  7706. equals:equals
  7707. });
  7708. });
  7709. return targets;
  7710. }
  7711. });
  7712. // 比较函数,两个 delegate 描述对象比较
  7713. // 注意顺序: 已有data 和 用户提供的 data 比较
  7714. function equals(d, el) {
  7715. // 用户不提供 fn selector 那么肯定成功
  7716. if (d.fn === undefined && d.selector === undefined) {
  7717. return true;
  7718. }
  7719. // 用户不提供 fn 则只比较 selector
  7720. else if (d.fn === undefined) {
  7721. return this.selector == d.selector;
  7722. } else {
  7723. var scope = this.scope || el,
  7724. dScope = d.scope || el;
  7725. return this.fn == d.fn && this.selector == d.selector && scope == dScope;
  7726. }
  7727. }
  7728. // 根据 selector ,从事件源得到对应节点
  7729. function delegateHandler(event, data) {
  7730. var delegateTarget = this,
  7731. target = event.target,
  7732. invokeds = DOM.closest(target, [data.selector], delegateTarget);
  7733. // 找到了符合 selector 的元素,可能并不是事件源
  7734. return invokes.call(delegateTarget, invokeds, event, data);
  7735. }
  7736. // mouseenter/leave 特殊处理
  7737. function mouseHandler(event, data) {
  7738. var delegateTarget = this,
  7739. ret,
  7740. target = event.target,
  7741. relatedTarget = event.relatedTarget;
  7742. // 恢复为用户想要的 mouseenter/leave 类型
  7743. event.type = data.preType;
  7744. // mouseenter/leave 不会冒泡,只选择最近一个
  7745. target = DOM.closest(target, data.selector, delegateTarget);
  7746. if (target) {
  7747. if (target !== relatedTarget &&
  7748. (!relatedTarget || !DOM.contains(target, relatedTarget))
  7749. ) {
  7750. var currentTarget = event.currentTarget;
  7751. event.currentTarget = target;
  7752. ret = data.fn.call(data.scope || delegateTarget, event);
  7753. event.currentTarget = currentTarget;
  7754. }
  7755. }
  7756. return ret;
  7757. }
  7758. function invokes(invokeds, event, data) {
  7759. var self = this;
  7760. if (invokeds) {
  7761. // 保护 currentTarget
  7762. // 否则 fire 影响 delegated listener 之后正常的 listener 事件
  7763. var currentTarget = event.currentTarget;
  7764. for (var i = 0; i < invokeds.length; i++) {
  7765. event.currentTarget = invokeds[i];
  7766. var ret = data.fn.call(data.scope || self, event);
  7767. // delegate 的 handler 操作事件和根元素本身操作事件效果一致
  7768. if (ret === false) {
  7769. event.halt();
  7770. }
  7771. if (event.isPropagationStopped) {
  7772. break;
  7773. }
  7774. }
  7775. event.currentTarget = currentTarget;
  7776. }
  7777. }
  7778. return Event;
  7779. }, {
  7780. requires:["dom","./base","./utils"]
  7781. });
  7782. /**
  7783. * focusin/out 的特殊之处 , delegate 只能在容器上注册 focusin/out ,
  7784. * 1.其实非 ie 都是注册 focus capture=true,然后注册到 focusin 对应 handlers
  7785. * 1.1 当 Event.fire("focus"),没有 focus 对应的 handlers 数组,然后调用元素 focus 方法,
  7786. * focusin.js 调用 Event.fire("focusin") 进而执行 focusin 对应的 handlers 数组
  7787. * 1.2 当调用 Event.fire("focusin"),直接执行 focusin 对应的 handlers 数组,但不会真正聚焦
  7788. *
  7789. * 2.ie 直接注册 focusin , focusin handlers 也有对应用户回调
  7790. * 2.1 当 Event.fire("focus") , 同 1.1
  7791. * 2.2 当 Event.fire("focusin"),直接执行 focusin 对应的 handlers 数组,但不会真正聚焦
  7792. *
  7793. * mouseenter/leave delegate 特殊处理, mouseenter 没有冒泡的概念,只能替换为 mouseover/out
  7794. *
  7795. * form submit 事件 ie<9 不会冒泡
  7796. *
  7797. **/
  7798. /**
  7799. * @module event-mouseenter
  7800. * @author lifesinger@gmail.com , yiminghe@gmail.com
  7801. */
  7802. KISSY.add('event/mouseenter', function(S, Event, DOM, UA) {
  7803. if (!UA['ie']) {
  7804. S.each([
  7805. { name: 'mouseenter', fix: 'mouseover' },
  7806. { name: 'mouseleave', fix: 'mouseout' }
  7807. ], function(o) {
  7808. // 元素内触发的 mouseover/out 不能算 mouseenter/leave
  7809. function withinElement(event) {
  7810. var self = this,
  7811. parent = event.relatedTarget;
  7812. // 设置用户实际注册的事件名,触发该事件所对应的 listener 数组
  7813. event.type = o.name;
  7814. // Firefox sometimes assigns relatedTarget a XUL element
  7815. // which we cannot access the parentNode property of
  7816. try {
  7817. // Chrome does something similar, the parentNode property
  7818. // can be accessed but is null.
  7819. if (parent && parent !== document && !parent.parentNode) {
  7820. return;
  7821. }
  7822. // 在自身外边就触发
  7823. if (parent !== self &&
  7824. // self==document , parent==null
  7825. (!parent || !DOM.contains(self, parent))
  7826. ) {
  7827. // handle event if we actually just moused on to a non sub-element
  7828. Event._handle(self, event);
  7829. }
  7830. // assuming we've left the element since we most likely mousedover a xul element
  7831. } catch(e) {
  7832. S.log("withinElement error : ", "error");
  7833. S.log(e, "error");
  7834. }
  7835. }
  7836. Event.special[o.name] = {
  7837. // 第一次 mouseenter 时注册下
  7838. // 以后都直接放到 listener 数组里, 由 mouseover 读取触发
  7839. setup: function() {
  7840. Event.add(this, o.fix, withinElement);
  7841. },
  7842. //当 listener 数组为空时,也清掉 mouseover 注册,不再读取
  7843. tearDown:function() {
  7844. Event.remove(this, o.fix, withinElement);
  7845. }
  7846. }
  7847. });
  7848. }
  7849. return Event;
  7850. }, {
  7851. requires:["./base","dom","ua"]
  7852. });
  7853. /**
  7854. * 承玉:2011-06-07
  7855. * - 根据新结构,调整 mouseenter 兼容处理
  7856. * - fire('mouseenter') 可以的,直接执行 mouseenter 的 handlers 用户回调数组
  7857. *
  7858. *
  7859. * TODO:
  7860. * - ie6 下,原生的 mouseenter/leave 貌似也有 bug, 比如 <div><div /><div /><div /></div>
  7861. * jQuery 也异常,需要进一步研究
  7862. */
  7863. /**
  7864. * patch for ie<9 submit : does not bubble !
  7865. * @author yiminghe@gmail.com
  7866. */
  7867. KISSY.add("event/submit", function(S, UA, Event, DOM) {
  7868. var mode = document['documentMode'];
  7869. if (UA['ie'] && (UA['ie'] < 9 || (mode && mode < 9))) {
  7870. var nodeName = DOM._nodeName;
  7871. Event.special['submit'] = {
  7872. setup: function() {
  7873. var el = this;
  7874. // form use native
  7875. if (nodeName(el, "form")) {
  7876. return false;
  7877. }
  7878. // lazy add submit for inside forms
  7879. // note event order : click/keypress -> submit
  7880. // keypoint : find the forms
  7881. Event.on(el, "click keypress", detector);
  7882. },
  7883. tearDown:function() {
  7884. var el = this;
  7885. // form use native
  7886. if (nodeName(el, "form")) {
  7887. return false;
  7888. }
  7889. Event.remove(el, "click keypress", detector);
  7890. DOM.query("form", el).each(function(form) {
  7891. if (form.__submit__fix) {
  7892. form.__submit__fix = 0;
  7893. Event.remove(form, "submit", submitBubble);
  7894. }
  7895. });
  7896. }
  7897. };
  7898. function detector(e) {
  7899. var t = e.target,
  7900. form = nodeName(t, "input") || nodeName(t, "button") ? t.form : null;
  7901. if (form && !form.__submit__fix) {
  7902. form.__submit__fix = 1;
  7903. Event.on(form, "submit", submitBubble);
  7904. }
  7905. }
  7906. function submitBubble(e) {
  7907. var form = this;
  7908. if (form.parentNode) {
  7909. // simulated bubble for submit
  7910. // fire from parentNode. if form.on("submit") , this logic is never run!
  7911. Event.fire(form.parentNode, "submit", e);
  7912. }
  7913. }
  7914. }
  7915. }, {
  7916. requires:["ua","./base","dom"]
  7917. });
  7918. /**
  7919. * modified from jq ,fix submit in ie<9
  7920. **/
  7921. /**
  7922. * change bubble and checkbox/radio fix patch for ie<9
  7923. * @author yiminghe@gmail.com
  7924. */
  7925. KISSY.add("event/change", function(S, UA, Event, DOM) {
  7926. var mode = document['documentMode'];
  7927. if (UA['ie'] && (UA['ie'] < 9 || (mode && mode < 9))) {
  7928. var rformElems = /^(?:textarea|input|select)$/i;
  7929. function isFormElement(n) {
  7930. return rformElems.test(n.nodeName);
  7931. }
  7932. function isCheckBoxOrRadio(el) {
  7933. var type = el.type;
  7934. return type == "checkbox" || type == "radio";
  7935. }
  7936. Event.special['change'] = {
  7937. setup: function() {
  7938. var el = this;
  7939. if (isFormElement(el)) {
  7940. // checkbox/radio only fires change when blur in ie<9
  7941. // so use another technique from jquery
  7942. if (isCheckBoxOrRadio(el)) {
  7943. // change in ie<9
  7944. // change = propertychange -> click
  7945. Event.on(el, "propertychange", propertyChange);
  7946. Event.on(el, "click", onClick);
  7947. } else {
  7948. // other form elements use native , do not bubble
  7949. return false;
  7950. }
  7951. } else {
  7952. // if bind on parentNode ,lazy bind change event to its form elements
  7953. // note event order : beforeactivate -> change
  7954. // note 2: checkbox/radio is exceptional
  7955. Event.on(el, "beforeactivate", beforeActivate);
  7956. }
  7957. },
  7958. tearDown:function() {
  7959. var el = this;
  7960. if (isFormElement(el)) {
  7961. if (isCheckBoxOrRadio(el)) {
  7962. Event.remove(el, "propertychange", propertyChange);
  7963. Event.remove(el, "click", onClick);
  7964. } else {
  7965. return false;
  7966. }
  7967. } else {
  7968. Event.remove(el, "beforeactivate", beforeActivate);
  7969. DOM.query("textarea,input,select", el).each(function(fel) {
  7970. if (fel.__changeHandler) {
  7971. fel.__changeHandler = 0;
  7972. Event.remove(fel, "change", changeHandler);
  7973. }
  7974. });
  7975. }
  7976. }
  7977. };
  7978. function propertyChange(e) {
  7979. if (e.originalEvent.propertyName == "checked") {
  7980. this.__changed = 1;
  7981. }
  7982. }
  7983. function onClick(e) {
  7984. if (this.__changed) {
  7985. this.__changed = 0;
  7986. // fire from itself
  7987. Event.fire(this, "change", e);
  7988. }
  7989. }
  7990. function beforeActivate(e) {
  7991. var t = e.target;
  7992. if (isFormElement(t) && !t.__changeHandler) {
  7993. t.__changeHandler = 1;
  7994. // lazy bind change
  7995. Event.on(t, "change", changeHandler);
  7996. }
  7997. }
  7998. function changeHandler(e) {
  7999. var fel = this;
  8000. // checkbox/radio already bubble using another technique
  8001. if (isCheckBoxOrRadio(fel)) {
  8002. return;
  8003. }
  8004. var p;
  8005. if (p = fel.parentNode) {
  8006. // fire from parent , itself is handled natively
  8007. Event.fire(p, "change", e);
  8008. }
  8009. }
  8010. }
  8011. }, {
  8012. requires:["ua","./base","dom"]
  8013. });
  8014. /**
  8015. * normalize mousewheel in gecko
  8016. * @author yiminghe@gmail.com
  8017. */
  8018. KISSY.add("event/mousewheel", function(S, Event, UA, Utils, EventObject) {
  8019. var MOUSE_WHEEL = UA.gecko ? 'DOMMouseScroll' : 'mousewheel',
  8020. simpleRemove = Utils.simpleRemove,
  8021. simpleAdd = Utils.simpleAdd,
  8022. mousewheelHandler = "mousewheelHandler";
  8023. function handler(e) {
  8024. var deltaX,
  8025. currentTarget = this,
  8026. deltaY,
  8027. delta,
  8028. detail = e.detail;
  8029. if (e.wheelDelta) {
  8030. delta = e.wheelDelta / 120;
  8031. }
  8032. if (e.detail) {
  8033. // press control e.detail == 1 else e.detail == 3
  8034. delta = -(detail % 3 == 0 ? detail / 3 : detail);
  8035. }
  8036. // Gecko
  8037. if (e.axis !== undefined) {
  8038. if (e.axis === e['HORIZONTAL_AXIS']) {
  8039. deltaY = 0;
  8040. deltaX = -1 * delta;
  8041. } else if (e.axis === e['VERTICAL_AXIS']) {
  8042. deltaX = 0;
  8043. deltaY = delta;
  8044. }
  8045. }
  8046. // Webkit
  8047. if (e['wheelDeltaY'] !== undefined) {
  8048. deltaY = e['wheelDeltaY'] / 120;
  8049. }
  8050. if (e['wheelDeltaX'] !== undefined) {
  8051. deltaX = -1 * e['wheelDeltaX'] / 120;
  8052. }
  8053. // 默认 deltaY ( ie )
  8054. if (!deltaX && !deltaY) {
  8055. deltaY = delta;
  8056. }
  8057. // can not invoke eventDesc.handler , it will protect type
  8058. // but here in firefox , we want to change type really
  8059. e = new EventObject(currentTarget, e);
  8060. S.mix(e, {
  8061. deltaY:deltaY,
  8062. delta:delta,
  8063. deltaX:deltaX,
  8064. type:'mousewheel'
  8065. });
  8066. return Event._handle(currentTarget, e);
  8067. }
  8068. Event.special['mousewheel'] = {
  8069. setup: function() {
  8070. var el = this,
  8071. mousewheelHandler,
  8072. eventDesc = Event._data(el);
  8073. // solve this in ie
  8074. mousewheelHandler = eventDesc[mousewheelHandler] = S.bind(handler, el);
  8075. simpleAdd(this, MOUSE_WHEEL, mousewheelHandler);
  8076. },
  8077. tearDown:function() {
  8078. var el = this,
  8079. mousewheelHandler,
  8080. eventDesc = Event._data(el);
  8081. mousewheelHandler = eventDesc[mousewheelHandler];
  8082. simpleRemove(this, MOUSE_WHEEL, mousewheelHandler);
  8083. delete eventDesc[mousewheelHandler];
  8084. }
  8085. };
  8086. }, {
  8087. requires:['./base','ua','./utils','./object']
  8088. });
  8089. /**
  8090. note:
  8091. not perfect in osx : accelerated scroll
  8092. refer:
  8093. https://github.com/brandonaaron/jquery-mousewheel/blob/master/jquery.mousewheel.js
  8094. http://www.planabc.net/2010/08/12/mousewheel_event_in_javascript/
  8095. http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel
  8096. http://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers/5542105#5542105
  8097. http://www.javascriptkit.com/javatutors/onmousewheel.shtml
  8098. http://www.adomas.org/javascript-mouse-wheel/
  8099. http://plugins.jquery.com/project/mousewheel
  8100. http://www.cnblogs.com/aiyuchen/archive/2011/04/19/2020843.html
  8101. http://www.w3.org/TR/DOM-Level-3-Events/#events-mousewheelevents
  8102. **/
  8103. /**
  8104. * KISSY Scalable Event Framework
  8105. * @author yiminghe@gmail.com
  8106. */
  8107. KISSY.add("event", function(S, KeyCodes, Event, Target, Object) {
  8108. Event.KeyCodes = KeyCodes;
  8109. Event.Target = Target;
  8110. Event.Object = Object;
  8111. return Event;
  8112. }, {
  8113. requires:[
  8114. "event/keycodes",
  8115. "event/base",
  8116. "event/target",
  8117. "event/object",
  8118. "event/focusin",
  8119. "event/hashchange",
  8120. "event/valuechange",
  8121. "event/delegate",
  8122. "event/mouseenter",
  8123. "event/submit",
  8124. "event/change",
  8125. "event/mousewheel"
  8126. ]
  8127. });
  8128. /**
  8129. * definition for node and nodelist
  8130. * @author yiminghe@gmail.com,lifesinger@gmail.com
  8131. */
  8132. KISSY.add("node/base", function(S, DOM, undefined) {
  8133. var AP = Array.prototype,
  8134. makeArray = S.makeArray,
  8135. isNodeList = DOM._isNodeList;
  8136. /**
  8137. * The NodeList class provides a wrapper for manipulating DOM Node.
  8138. * @constructor
  8139. */
  8140. function NodeList(html, props, ownerDocument) {
  8141. var self = this,
  8142. domNode;
  8143. if (!(self instanceof NodeList)) {
  8144. return new NodeList(html, props, ownerDocument);
  8145. }
  8146. // handle NodeList(''), NodeList(null), or NodeList(undefined)
  8147. if (!html) {
  8148. return undefined;
  8149. }
  8150. else if (S.isString(html)) {
  8151. // create from html
  8152. domNode = DOM.create(html, props, ownerDocument);
  8153. // ('<p>1</p><p>2</p>') 转换为 NodeList
  8154. if (domNode.nodeType === DOM.DOCUMENT_FRAGMENT_NODE) { // fragment
  8155. AP.push.apply(this, makeArray(domNode.childNodes));
  8156. return undefined;
  8157. }
  8158. }
  8159. else if (S.isArray(html) || isNodeList(html)) {
  8160. AP.push.apply(this, makeArray(html));
  8161. return undefined;
  8162. }
  8163. else {
  8164. // node, document, window
  8165. domNode = html;
  8166. }
  8167. self[0] = domNode;
  8168. self.length = 1;
  8169. return undefined;
  8170. }
  8171. S.augment(NodeList, {
  8172. /**
  8173. * 默认长度为 0
  8174. */
  8175. length: 0,
  8176. item: function(index) {
  8177. var self = this;
  8178. if (S.isNumber(index)) {
  8179. if (index >= self.length) {
  8180. return null;
  8181. } else {
  8182. return new NodeList(self[index]);
  8183. }
  8184. } else {
  8185. return new NodeList(index);
  8186. }
  8187. },
  8188. add:function(selector, context, index) {
  8189. if (S.isNumber(context)) {
  8190. index = context;
  8191. context = undefined;
  8192. }
  8193. var list = NodeList.all(selector, context).getDOMNodes(),
  8194. ret = new NodeList(this);
  8195. if (index === undefined) {
  8196. AP.push.apply(ret, list);
  8197. } else {
  8198. var args = [index,0];
  8199. args.push.apply(args, list);
  8200. AP.splice.apply(ret, args);
  8201. }
  8202. return ret;
  8203. },
  8204. slice:function(start, end) {
  8205. return new NodeList(AP.slice.call(this, start, end));
  8206. },
  8207. /**
  8208. * Retrieves the DOMNodes.
  8209. */
  8210. getDOMNodes: function() {
  8211. return AP.slice.call(this);
  8212. },
  8213. /**
  8214. * Applies the given function to each Node in the NodeList.
  8215. * @param fn The function to apply. It receives 3 arguments: the current node instance, the node's index, and the NodeList instance
  8216. * @param context An optional context to apply the function with Default context is the current NodeList instance
  8217. */
  8218. each: function(fn, context) {
  8219. var self = this;
  8220. S.each(self, function(n, i) {
  8221. n = new NodeList(n);
  8222. return fn.call(context || n, n, i, self);
  8223. });
  8224. return self;
  8225. },
  8226. /**
  8227. * Retrieves the DOMNode.
  8228. */
  8229. getDOMNode: function() {
  8230. return this[0];
  8231. },
  8232. /**
  8233. * stack sub query
  8234. */
  8235. end:function() {
  8236. var self = this;
  8237. return self.__parent || self;
  8238. },
  8239. all:function(selector) {
  8240. var ret,self = this;
  8241. if (self.length > 0) {
  8242. ret = NodeList.all(selector, self);
  8243. } else {
  8244. ret = new NodeList();
  8245. }
  8246. ret.__parent = self;
  8247. return ret;
  8248. },
  8249. one:function(selector) {
  8250. var self = this,all = self.all(selector),
  8251. ret = all.length ? all.slice(0, 1) : null;
  8252. if (ret) {
  8253. ret.__parent = self;
  8254. }
  8255. return ret;
  8256. }
  8257. });
  8258. S.mix(NodeList, {
  8259. /**
  8260. * 查找位于上下文中并且符合选择器定义的节点列表或根据 html 生成新节点
  8261. * @param {String|HTMLElement[]|NodeList} selector html 字符串或<a href='http://docs.kissyui.com/docs/html/api/core/dom/selector.html'>选择器</a>或节点列表
  8262. * @param {String|Array<HTMLElement>|NodeList|HTMLElement|Document} [context] 上下文定义
  8263. * @returns {NodeList} 节点列表对象
  8264. */
  8265. all:function(selector, context) {
  8266. // are we dealing with html string ?
  8267. // TextNode 仍需要自己 new Node
  8268. if (S.isString(selector)
  8269. && (selector = S.trim(selector))
  8270. && selector.length >= 3
  8271. && S.startsWith(selector, "<")
  8272. && S.endsWith(selector, ">")
  8273. ) {
  8274. if (context) {
  8275. if (context.getDOMNode) {
  8276. context = context.getDOMNode();
  8277. }
  8278. if (context.ownerDocument) {
  8279. context = context.ownerDocument;
  8280. }
  8281. }
  8282. return new NodeList(selector, undefined, context);
  8283. }
  8284. return new NodeList(DOM.query(selector, context));
  8285. },
  8286. one:function(selector, context) {
  8287. var all = NodeList.all(selector, context);
  8288. return all.length ? all.slice(0, 1) : null;
  8289. }
  8290. });
  8291. S.mix(NodeList, DOM._NODE_TYPE);
  8292. return NodeList;
  8293. }, {
  8294. requires:["dom"]
  8295. });
  8296. /**
  8297. * Notes:
  8298. * 2011-05-25
  8299. * - 承玉:参考 jquery,只有一个 NodeList 对象,Node 就是 NodeList 的别名
  8300. *
  8301. * 2010.04
  8302. * - each 方法传给 fn 的 this, 在 jQuery 里指向原生对象,这样可以避免性能问题。
  8303. * 但从用户角度讲,this 的第一直觉是 $(this), kissy 和 yui3 保持一致,牺牲
  8304. * 性能,以易用为首。
  8305. * - 有了 each 方法,似乎不再需要 import 所有 dom 方法,意义不大。
  8306. * - dom 是低级 api, node 是中级 api, 这是分层的一个原因。还有一个原因是,如果
  8307. * 直接在 node 里实现 dom 方法,则不大好将 dom 的方法耦合到 nodelist 里。可
  8308. * 以说,技术成本会制约 api 设计。
  8309. */
  8310. /**
  8311. * import methods from DOM to NodeList.prototype
  8312. * @author yiminghe@gmail.com
  8313. */
  8314. KISSY.add('node/attach', function(S, DOM, Event, NodeList, undefined) {
  8315. var NLP = NodeList.prototype,
  8316. makeArray = S.makeArray,
  8317. // DOM 添加到 NP 上的方法
  8318. // if DOM methods return undefined , Node methods need to transform result to itself
  8319. DOM_INCLUDES_NORM = [
  8320. "equals",
  8321. "contains",
  8322. "scrollTop",
  8323. "scrollLeft",
  8324. "height",
  8325. "width",
  8326. "innerHeight",
  8327. "innerWidth",
  8328. "outerHeight",
  8329. "outerWidth",
  8330. "addStyleSheet",
  8331. // "append" will be overridden
  8332. "appendTo",
  8333. // "prepend" will be overridden
  8334. "prependTo",
  8335. "insertBefore",
  8336. "before",
  8337. "after",
  8338. "insertAfter",
  8339. "test",
  8340. "hasClass",
  8341. "addClass",
  8342. "removeClass",
  8343. "replaceClass",
  8344. "toggleClass",
  8345. "removeAttr",
  8346. "hasAttr",
  8347. "hasProp",
  8348. // anim override
  8349. // "show",
  8350. // "hide",
  8351. // "toggle",
  8352. "scrollIntoView",
  8353. "remove",
  8354. "empty",
  8355. "removeData",
  8356. "hasData",
  8357. "unselectable"
  8358. ],
  8359. // if return array ,need transform to nodelist
  8360. DOM_INCLUDES_NORM_NODE_LIST = [
  8361. "filter",
  8362. "first",
  8363. "last",
  8364. "parent",
  8365. "closest",
  8366. "next",
  8367. "prev",
  8368. "clone",
  8369. "siblings",
  8370. "children"
  8371. ],
  8372. // if set return this else if get return true value ,no nodelist transform
  8373. DOM_INCLUDES_NORM_IF = {
  8374. // dom method : set parameter index
  8375. "attr":1,
  8376. "text":0,
  8377. "css":1,
  8378. "style":1,
  8379. "val":0,
  8380. "prop":1,
  8381. "offset":0,
  8382. "html":0,
  8383. "data":1
  8384. },
  8385. // Event 添加到 NP 上的方法
  8386. EVENT_INCLUDES = ["on","detach","fire","delegate","undelegate"];
  8387. function accessNorm(fn, self, args) {
  8388. args.unshift(self);
  8389. var ret = DOM[fn].apply(DOM, args);
  8390. if (ret === undefined) {
  8391. return self;
  8392. }
  8393. return ret;
  8394. }
  8395. function accessNormList(fn, self, args) {
  8396. args.unshift(self);
  8397. var ret = DOM[fn].apply(DOM, args);
  8398. if (ret === undefined) {
  8399. return self;
  8400. }
  8401. else if (ret === null) {
  8402. return null;
  8403. }
  8404. return new NodeList(ret);
  8405. }
  8406. function accessNormIf(fn, self, index, args) {
  8407. // get
  8408. if (args[index] === undefined
  8409. // 并且第一个参数不是对象,否则可能是批量设置写
  8410. && !S.isObject(args[0])) {
  8411. args.unshift(self);
  8412. return DOM[fn].apply(DOM, args);
  8413. }
  8414. // set
  8415. return accessNorm(fn, self, args);
  8416. }
  8417. S.each(DOM_INCLUDES_NORM, function(k) {
  8418. NLP[k] = function() {
  8419. var args = makeArray(arguments);
  8420. return accessNorm(k, this, args);
  8421. };
  8422. });
  8423. S.each(DOM_INCLUDES_NORM_NODE_LIST, function(k) {
  8424. NLP[k] = function() {
  8425. var args = makeArray(arguments);
  8426. return accessNormList(k, this, args);
  8427. };
  8428. });
  8429. S.each(DOM_INCLUDES_NORM_IF, function(index, k) {
  8430. NLP[k] = function() {
  8431. var args = makeArray(arguments);
  8432. return accessNormIf(k, this, index, args);
  8433. };
  8434. });
  8435. S.each(EVENT_INCLUDES, function(k) {
  8436. NLP[k] = function() {
  8437. var self=this,
  8438. args = makeArray(arguments);
  8439. args.unshift(self);
  8440. Event[k].apply(Event, args);
  8441. return self;
  8442. }
  8443. });
  8444. }, {
  8445. requires:["dom","event","./base"]
  8446. });
  8447. /**
  8448. * 2011-05-24
  8449. * - 承玉:
  8450. * - 将 DOM 中的方法包装成 NodeList 方法
  8451. * - Node 方法调用参数中的 KISSY NodeList 要转换成第一个 HTML Node
  8452. * - 要注意链式调用,如果 DOM 方法返回 undefined (无返回值),则 NodeList 对应方法返回 this
  8453. * - 实际上可以完全使用 NodeList 来代替 DOM,不和节点关联的方法如:viewportHeight 等,在 window,document 上调用
  8454. * - 存在 window/document 虚节点,通过 S.one(window)/new Node(window) ,S.one(document)/new NodeList(document) 获得
  8455. */
  8456. /**
  8457. * overrides methods in NodeList.prototype
  8458. * @author yiminghe@gmail.com
  8459. */
  8460. KISSY.add("node/override", function(S, DOM, Event, NodeList) {
  8461. /**
  8462. * append(node ,parent) : 参数顺序反过来了
  8463. * appendTo(parent,node) : 才是正常
  8464. *
  8465. */
  8466. S.each(['append', 'prepend','before','after'], function(insertType) {
  8467. NodeList.prototype[insertType] = function(html) {
  8468. var newNode = html,self = this;
  8469. // 创建
  8470. if (S.isString(newNode)) {
  8471. newNode = DOM.create(newNode);
  8472. }
  8473. if (newNode) {
  8474. DOM[insertType](newNode, self);
  8475. }
  8476. return self;
  8477. };
  8478. });
  8479. }, {
  8480. requires:["dom","event","./base","./attach"]
  8481. });
  8482. /**
  8483. * 2011-05-24
  8484. * - 承玉:
  8485. * - 重写 NodeList 的某些方法
  8486. * - 添加 one ,all ,从当前 NodeList 往下开始选择节点
  8487. * - 处理 append ,prepend 和 DOM 的参数实际上是反过来的
  8488. * - append/prepend 参数是节点时,如果当前 NodeList 数量 > 1 需要经过 clone,因为同一节点不可能被添加到多个节点中去(NodeList)
  8489. */
  8490. /**
  8491. * @module anim-easing
  8492. */
  8493. KISSY.add('anim/easing', function() {
  8494. // Based on Easing Equations (c) 2003 Robert Penner, all rights reserved.
  8495. // This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html
  8496. // Preview: http://www.robertpenner.com/easing/easing_demo.html
  8497. /**
  8498. * 和 YUI 的 Easing 相比,S.Easing 进行了归一化处理,参数调整为:
  8499. * @param {Number} t Time value used to compute current value 保留 0 =< t <= 1
  8500. * @param {Number} b Starting value b = 0
  8501. * @param {Number} c Delta between start and end values c = 1
  8502. * @param {Number} d Total length of animation d = 1
  8503. */
  8504. var PI = Math.PI,
  8505. pow = Math.pow,
  8506. sin = Math.sin,
  8507. BACK_CONST = 1.70158,
  8508. Easing = {
  8509. swing:function(t) {
  8510. return ( -Math.cos(t * PI) / 2 ) + 0.5;
  8511. },
  8512. /**
  8513. * Uniform speed between points.
  8514. */
  8515. easeNone: function (t) {
  8516. return t;
  8517. },
  8518. /**
  8519. * Begins slowly and accelerates towards end. (quadratic)
  8520. */
  8521. easeIn: function (t) {
  8522. return t * t;
  8523. },
  8524. /**
  8525. * Begins quickly and decelerates towards end. (quadratic)
  8526. */
  8527. easeOut: function (t) {
  8528. return ( 2 - t) * t;
  8529. },
  8530. /**
  8531. * Begins slowly and decelerates towards end. (quadratic)
  8532. */
  8533. easeBoth: function (t) {
  8534. return (t *= 2) < 1 ?
  8535. .5 * t * t :
  8536. .5 * (1 - (--t) * (t - 2));
  8537. },
  8538. /**
  8539. * Begins slowly and accelerates towards end. (quartic)
  8540. */
  8541. easeInStrong: function (t) {
  8542. return t * t * t * t;
  8543. },
  8544. /**
  8545. * Begins quickly and decelerates towards end. (quartic)
  8546. */
  8547. easeOutStrong: function (t) {
  8548. return 1 - (--t) * t * t * t;
  8549. },
  8550. /**
  8551. * Begins slowly and decelerates towards end. (quartic)
  8552. */
  8553. easeBothStrong: function (t) {
  8554. return (t *= 2) < 1 ?
  8555. .5 * t * t * t * t :
  8556. .5 * (2 - (t -= 2) * t * t * t);
  8557. },
  8558. /**
  8559. * Snap in elastic effect.
  8560. */
  8561. elasticIn: function (t) {
  8562. var p = .3, s = p / 4;
  8563. if (t === 0 || t === 1) return t;
  8564. return -(pow(2, 10 * (t -= 1)) * sin((t - s) * (2 * PI) / p));
  8565. },
  8566. /**
  8567. * Snap out elastic effect.
  8568. */
  8569. elasticOut: function (t) {
  8570. var p = .3, s = p / 4;
  8571. if (t === 0 || t === 1) return t;
  8572. return pow(2, -10 * t) * sin((t - s) * (2 * PI) / p) + 1;
  8573. },
  8574. /**
  8575. * Snap both elastic effect.
  8576. */
  8577. elasticBoth: function (t) {
  8578. var p = .45, s = p / 4;
  8579. if (t === 0 || (t *= 2) === 2) return t;
  8580. if (t < 1) {
  8581. return -.5 * (pow(2, 10 * (t -= 1)) *
  8582. sin((t - s) * (2 * PI) / p));
  8583. }
  8584. return pow(2, -10 * (t -= 1)) *
  8585. sin((t - s) * (2 * PI) / p) * .5 + 1;
  8586. },
  8587. /**
  8588. * Backtracks slightly, then reverses direction and moves to end.
  8589. */
  8590. backIn: function (t) {
  8591. if (t === 1) t -= .001;
  8592. return t * t * ((BACK_CONST + 1) * t - BACK_CONST);
  8593. },
  8594. /**
  8595. * Overshoots end, then reverses and comes back to end.
  8596. */
  8597. backOut: function (t) {
  8598. return (t -= 1) * t * ((BACK_CONST + 1) * t + BACK_CONST) + 1;
  8599. },
  8600. /**
  8601. * Backtracks slightly, then reverses direction, overshoots end,
  8602. * then reverses and comes back to end.
  8603. */
  8604. backBoth: function (t) {
  8605. if ((t *= 2 ) < 1) {
  8606. return .5 * (t * t * (((BACK_CONST *= (1.525)) + 1) * t - BACK_CONST));
  8607. }
  8608. return .5 * ((t -= 2) * t * (((BACK_CONST *= (1.525)) + 1) * t + BACK_CONST) + 2);
  8609. },
  8610. /**
  8611. * Bounce off of start.
  8612. */
  8613. bounceIn: function (t) {
  8614. return 1 - Easing.bounceOut(1 - t);
  8615. },
  8616. /**
  8617. * Bounces off end.
  8618. */
  8619. bounceOut: function (t) {
  8620. var s = 7.5625, r;
  8621. if (t < (1 / 2.75)) {
  8622. r = s * t * t;
  8623. }
  8624. else if (t < (2 / 2.75)) {
  8625. r = s * (t -= (1.5 / 2.75)) * t + .75;
  8626. }
  8627. else if (t < (2.5 / 2.75)) {
  8628. r = s * (t -= (2.25 / 2.75)) * t + .9375;
  8629. }
  8630. else {
  8631. r = s * (t -= (2.625 / 2.75)) * t + .984375;
  8632. }
  8633. return r;
  8634. },
  8635. /**
  8636. * Bounces off start and end.
  8637. */
  8638. bounceBoth: function (t) {
  8639. if (t < .5) {
  8640. return Easing.bounceIn(t * 2) * .5;
  8641. }
  8642. return Easing.bounceOut(t * 2 - 1) * .5 + .5;
  8643. }
  8644. };
  8645. Easing.NativeTimeFunction = {
  8646. easeNone: 'linear',
  8647. ease: 'ease',
  8648. easeIn: 'ease-in',
  8649. easeOut: 'ease-out',
  8650. easeBoth: 'ease-in-out',
  8651. // Ref:
  8652. // 1. http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag
  8653. // 2. http://www.robertpenner.com/easing/easing_demo.html
  8654. // 3. assets/cubic-bezier-timing-function.html
  8655. // 注:是模拟值,非精确推导值
  8656. easeInStrong: 'cubic-bezier(0.9, 0.0, 0.9, 0.5)',
  8657. easeOutStrong: 'cubic-bezier(0.1, 0.5, 0.1, 1.0)',
  8658. easeBothStrong: 'cubic-bezier(0.9, 0.0, 0.1, 1.0)'
  8659. };
  8660. return Easing;
  8661. });
  8662. /**
  8663. * TODO:
  8664. * - test-easing.html 详细的测试 + 曲线可视化
  8665. *
  8666. * NOTES:
  8667. * - 综合比较 jQuery UI/scripty2/YUI 的 easing 命名,还是觉得 YUI 的对用户
  8668. * 最友好。因此这次完全照搬 YUI 的 Easing, 只是代码上做了点压缩优化。
  8669. *
  8670. */
  8671. /**
  8672. * single timer for the whole anim module
  8673. * @author yiminghe@gmail.com
  8674. */
  8675. KISSY.add("anim/manager", function(S) {
  8676. var stamp = S.stamp;
  8677. return {
  8678. interval:15,
  8679. runnings:{},
  8680. timer:null,
  8681. start:function(anim) {
  8682. var self = this,
  8683. kv = stamp(anim);
  8684. if (self.runnings[kv]) {
  8685. return;
  8686. }
  8687. self.runnings[kv] = anim;
  8688. self.startTimer();
  8689. },
  8690. stop:function(anim) {
  8691. this.notRun(anim);
  8692. },
  8693. notRun:function(anim) {
  8694. var self = this,
  8695. kv = stamp(anim);
  8696. delete self.runnings[kv];
  8697. if (S.isEmptyObject(self.runnings)) {
  8698. self.stopTimer();
  8699. }
  8700. },
  8701. pause:function(anim) {
  8702. this.notRun(anim);
  8703. },
  8704. resume:function(anim) {
  8705. this.start(anim);
  8706. },
  8707. startTimer:function() {
  8708. var self = this;
  8709. if (!self.timer) {
  8710. self.timer = setTimeout(function() {
  8711. if (!self.runFrames()) {
  8712. self.timer = 0;
  8713. self.startTimer();
  8714. } else {
  8715. self.stopTimer();
  8716. }
  8717. }, self.interval);
  8718. }
  8719. },
  8720. stopTimer:function() {
  8721. var self = this,
  8722. t = self.timer;
  8723. if (t) {
  8724. clearTimeout(t);
  8725. self.timer = 0;
  8726. }
  8727. },
  8728. runFrames:function() {
  8729. var self = this,
  8730. done = 1,
  8731. runnings = self.runnings;
  8732. for (var r in runnings) {
  8733. if (runnings.hasOwnProperty(r)) {
  8734. done = 0;
  8735. runnings[r]._frame();
  8736. }
  8737. }
  8738. return done;
  8739. }
  8740. };
  8741. });
  8742. /**
  8743. * animate on single property
  8744. * @author yiminghe@gmail.com
  8745. */
  8746. KISSY.add("anim/fx", function(S, DOM, undefined) {
  8747. /**
  8748. * basic animation about single css property or element attribute
  8749. * @param cfg
  8750. */
  8751. function Fx(cfg) {
  8752. this.load(cfg);
  8753. }
  8754. S.augment(Fx, {
  8755. load:function(cfg) {
  8756. var self = this;
  8757. S.mix(self, cfg);
  8758. self.startTime = S.now();
  8759. self.pos = 0;
  8760. self.unit = self.unit || "";
  8761. },
  8762. frame:function(end) {
  8763. var self = this,
  8764. endFlag = 0,
  8765. elapsedTime,
  8766. t = S.now();
  8767. if (end || t >= self.duration + self.startTime) {
  8768. self.pos = 1;
  8769. endFlag = 1;
  8770. } else {
  8771. elapsedTime = t - self.startTime;
  8772. self.pos = self.easing(elapsedTime / self.duration);
  8773. }
  8774. self.update();
  8775. return endFlag;
  8776. },
  8777. /**
  8778. * 数值插值函数
  8779. * @param {Number} from 源值
  8780. * @param {Number} to 目的值
  8781. * @param {Number} pos 当前位置,从 easing 得到 0~1
  8782. * @return {Number} 当前值
  8783. */
  8784. interpolate:function (from, to, pos) {
  8785. // 默认只对数字进行 easing
  8786. if (S.isNumber(from) &&
  8787. S.isNumber(to)) {
  8788. return (from + (to - from) * pos).toFixed(3);
  8789. } else {
  8790. return undefined;
  8791. }
  8792. },
  8793. update:function() {
  8794. var self = this,
  8795. prop = self.prop,
  8796. elem = self.elem,
  8797. from = self.from,
  8798. to = self.to,
  8799. val = self.interpolate(from, to, self.pos);
  8800. if (val === undefined) {
  8801. // 插值出错,直接设置为最终值
  8802. if (!self.finished) {
  8803. self.finished = 1;
  8804. DOM.css(elem, prop, to);
  8805. S.log(self.prop + " update directly ! : " + val + " : " + from + " : " + to);
  8806. }
  8807. } else {
  8808. val += self.unit;
  8809. if (isAttr(elem, prop)) {
  8810. DOM.attr(elem, prop, val, 1);
  8811. } else {
  8812. DOM.css(elem, prop, val);
  8813. }
  8814. }
  8815. },
  8816. /**
  8817. * current value
  8818. */
  8819. cur:function() {
  8820. var self = this,
  8821. prop = self.prop,
  8822. elem = self.elem;
  8823. if (isAttr(elem, prop)) {
  8824. return DOM.attr(elem, prop, undefined, 1);
  8825. }
  8826. var parsed,
  8827. r = DOM.css(elem, prop);
  8828. // Empty strings, null, undefined and "auto" are converted to 0,
  8829. // complex values such as "rotate(1rad)" are returned as is,
  8830. // simple values such as "10px" are parsed to Float.
  8831. return isNaN(parsed = parseFloat(r)) ?
  8832. !r || r === "auto" ? 0 : r
  8833. : parsed;
  8834. }
  8835. });
  8836. function isAttr(elem, prop) {
  8837. // support scrollTop/Left now!
  8838. if ((!elem.style || elem.style[ prop ] == null) &&
  8839. DOM.attr(elem, prop, undefined, 1) != null) {
  8840. return 1;
  8841. }
  8842. return 0;
  8843. }
  8844. Fx.Factories = {};
  8845. Fx.getFx = function(cfg) {
  8846. var Constructor = Fx.Factories[cfg.prop] || Fx;
  8847. return new Constructor(cfg);
  8848. };
  8849. return Fx;
  8850. }, {
  8851. requires:['dom']
  8852. });
  8853. /**
  8854. * TODO
  8855. * 支持 transform ,ie 使用 matrix
  8856. * - http://shawphy.com/2011/01/transformation-matrix-in-front-end.html
  8857. * - http://www.cnblogs.com/winter-cn/archive/2010/12/29/1919266.html
  8858. * - 标准:http://www.zenelements.com/blog/css3-transform/
  8859. * - ie: http://www.useragentman.com/IETransformsTranslator/
  8860. * - wiki: http://en.wikipedia.org/wiki/Transformation_matrix
  8861. * - jq 插件: http://plugins.jquery.com/project/2d-transform
  8862. **/
  8863. /**
  8864. * queue of anim objects
  8865. * @author yiminghe@gmail.com
  8866. */
  8867. KISSY.add("anim/queue", function(S, DOM) {
  8868. var /*队列集合容器*/
  8869. queueCollectionKey = S.guid("ks-queue-" + S.now() + "-"),
  8870. /*默认队列*/
  8871. queueKey = S.guid("ks-queue-" + S.now() + "-"),
  8872. // 当前队列是否有动画正在执行
  8873. processing = "...";
  8874. function getQueue(elem, name, readOnly) {
  8875. name = name || queueKey;
  8876. var qu,
  8877. quCollection = DOM.data(elem, queueCollectionKey);
  8878. if (!quCollection && !readOnly) {
  8879. DOM.data(elem, queueCollectionKey, quCollection = {});
  8880. }
  8881. if (quCollection) {
  8882. qu = quCollection[name];
  8883. if (!qu && !readOnly) {
  8884. qu = quCollection[name] = [];
  8885. }
  8886. }
  8887. return qu;
  8888. }
  8889. function removeQueue(elem, name) {
  8890. name = name || queueKey;
  8891. var quCollection = DOM.data(elem, queueCollectionKey);
  8892. if (quCollection) {
  8893. delete quCollection[name];
  8894. }
  8895. if (S.isEmptyObject(quCollection)) {
  8896. DOM.removeData(elem, queueCollectionKey);
  8897. }
  8898. }
  8899. var q = {
  8900. queueCollectionKey:queueCollectionKey,
  8901. queue:function(anim) {
  8902. var elem = anim.elem,
  8903. name = anim.config.queue,
  8904. qu = getQueue(elem, name);
  8905. qu.push(anim);
  8906. if (qu[0] !== processing) {
  8907. q.dequeue(anim);
  8908. }
  8909. return qu;
  8910. },
  8911. remove:function(anim) {
  8912. var elem = anim.elem,
  8913. name = anim.config.queue,
  8914. qu = getQueue(elem, name, 1),index;
  8915. if (qu) {
  8916. index = S.indexOf(anim, qu);
  8917. if (index > -1) {
  8918. qu.splice(index, 1);
  8919. }
  8920. }
  8921. },
  8922. removeQueues:function(elem) {
  8923. DOM.removeData(elem, queueCollectionKey);
  8924. },
  8925. removeQueue:removeQueue,
  8926. dequeue:function(anim) {
  8927. var elem = anim.elem,
  8928. name = anim.config.queue,
  8929. qu = getQueue(elem, name, 1),
  8930. nextAnim = qu && qu.shift();
  8931. if (nextAnim == processing) {
  8932. nextAnim = qu.shift();
  8933. }
  8934. if (nextAnim) {
  8935. qu.unshift(processing);
  8936. nextAnim._runInternal();
  8937. } else {
  8938. // remove queue data
  8939. removeQueue(elem, name);
  8940. }
  8941. }
  8942. };
  8943. return q;
  8944. }, {
  8945. requires:['dom']
  8946. });
  8947. /**
  8948. * animation framework for KISSY
  8949. * @author yiminghe@gmail.com,lifesinger@gmail.com
  8950. */
  8951. KISSY.add('anim/base', function(S, DOM, Event, Easing, UA, AM, Fx, Q) {
  8952. var camelCase = DOM._camelCase,
  8953. _isElementNode = DOM._isElementNode,
  8954. specialVals = ["hide","show","toggle"],
  8955. // shorthand css properties
  8956. SHORT_HANDS = {
  8957. border:[
  8958. "borderBottomWidth",
  8959. "borderLeftWidth",
  8960. 'borderRightWidth',
  8961. // 'borderSpacing', 组合属性?
  8962. 'borderTopWidth'
  8963. ],
  8964. "borderBottom":["borderBottomWidth"],
  8965. "borderLeft":["borderLeftWidth"],
  8966. borderTop:["borderTopWidth"],
  8967. borderRight:["borderRightWidth"],
  8968. font:[
  8969. 'fontSize',
  8970. 'fontWeight'
  8971. ],
  8972. margin:[
  8973. 'marginBottom',
  8974. 'marginLeft',
  8975. 'marginRight',
  8976. 'marginTop'
  8977. ],
  8978. padding:[
  8979. 'paddingBottom',
  8980. 'paddingLeft',
  8981. 'paddingRight',
  8982. 'paddingTop'
  8983. ]
  8984. },
  8985. defaultConfig = {
  8986. duration: 1,
  8987. easing: 'easeNone'
  8988. },
  8989. rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i;
  8990. Anim.SHORT_HANDS = SHORT_HANDS;
  8991. /**
  8992. * get a anim instance associate
  8993. * @param elem 元素或者 window ( window 时只能动画 scrollTop/scrollLeft )
  8994. * @param props
  8995. * @param duration
  8996. * @param easing
  8997. * @param callback
  8998. */
  8999. function Anim(elem, props, duration, easing, callback) {
  9000. var self = this,config;
  9001. // ignore non-exist element
  9002. if (!(elem = DOM.get(elem))) {
  9003. return;
  9004. }
  9005. // factory or constructor
  9006. if (!(self instanceof Anim)) {
  9007. return new Anim(elem, props, duration, easing, callback);
  9008. }
  9009. /**
  9010. * the transition properties
  9011. */
  9012. if (S.isString(props)) {
  9013. props = S.unparam(props, ";", ":");
  9014. } else {
  9015. // clone to prevent collision within multiple instance
  9016. props = S.clone(props);
  9017. }
  9018. /**
  9019. * 驼峰属性名
  9020. */
  9021. for (var prop in props) {
  9022. var camelProp = camelCase(S.trim(prop));
  9023. if (prop != camelProp) {
  9024. props[camelProp] = props[prop];
  9025. delete props[prop];
  9026. }
  9027. }
  9028. /**
  9029. * animation config
  9030. */
  9031. if (S.isPlainObject(duration)) {
  9032. config = S.clone(duration);
  9033. } else {
  9034. config = {
  9035. duration:parseFloat(duration) || undefined,
  9036. easing:easing,
  9037. complete:callback
  9038. };
  9039. }
  9040. config = S.merge(defaultConfig, config);
  9041. self.config = config;
  9042. config.duration *= 1000;
  9043. // domEl deprecated!
  9044. self.elem = self['domEl'] = elem;
  9045. self.props = props;
  9046. // 实例属性
  9047. self._backupProps = {};
  9048. self._fxs = {};
  9049. // register callback
  9050. self.on("complete", onComplete);
  9051. }
  9052. function onComplete(e) {
  9053. var self = this,
  9054. _backupProps = self._backupProps,
  9055. config = self.config;
  9056. // only recover after complete anim
  9057. if (!S.isEmptyObject(_backupProps = self._backupProps)) {
  9058. DOM.css(self.elem, _backupProps);
  9059. }
  9060. if (config.complete) {
  9061. config.complete.call(self, e);
  9062. }
  9063. }
  9064. function runInternal() {
  9065. var self = this,
  9066. config = self.config,
  9067. _backupProps = self._backupProps,
  9068. elem = self.elem,
  9069. hidden,
  9070. val,
  9071. prop,
  9072. specialEasing = (config['specialEasing'] || {}),
  9073. fxs = self._fxs,
  9074. props = self.props;
  9075. // 进入该函数即代表执行(q[0] 已经是 ...)
  9076. saveRunning(self);
  9077. if (self.fire("start") === false) {
  9078. // no need to invoke complete
  9079. self.stop(0);
  9080. return;
  9081. }
  9082. if (_isElementNode(elem)) {
  9083. hidden = DOM.css(elem, "display") == "none";
  9084. for (prop in props) {
  9085. val = props[prop];
  9086. // 直接结束
  9087. if (val == "hide" && hidden || val == 'show' && !hidden) {
  9088. // need to invoke complete
  9089. self.stop(1);
  9090. return;
  9091. }
  9092. }
  9093. }
  9094. // 分离 easing
  9095. S.each(props, function(val, prop) {
  9096. if (!props.hasOwnProperty(prop)) {
  9097. return;
  9098. }
  9099. var easing;
  9100. if (S.isArray(val)) {
  9101. easing = specialEasing[prop] = val[1];
  9102. props[prop] = val[0];
  9103. } else {
  9104. easing = specialEasing[prop] = (specialEasing[prop] || config.easing);
  9105. }
  9106. if (S.isString(easing)) {
  9107. easing = specialEasing[prop] = Easing[easing];
  9108. }
  9109. specialEasing[prop] = easing || Easing.easeNone;
  9110. });
  9111. // 扩展分属性
  9112. S.each(SHORT_HANDS, function(shortHands, p) {
  9113. var sh,
  9114. origin,
  9115. val;
  9116. if (val = props[p]) {
  9117. origin = {};
  9118. S.each(shortHands, function(sh) {
  9119. // 得到原始分属性之前值
  9120. origin[sh] = DOM.css(elem, sh);
  9121. specialEasing[sh] = specialEasing[p];
  9122. });
  9123. DOM.css(elem, p, val);
  9124. for (sh in origin) {
  9125. // 得到期待的分属性最后值
  9126. props[sh] = DOM.css(elem, sh);
  9127. // 还原
  9128. DOM.css(elem, sh, origin[sh]);
  9129. }
  9130. // 删除复合属性
  9131. delete props[p];
  9132. }
  9133. });
  9134. // 取得单位,并对单个属性构建 Fx 对象
  9135. for (prop in props) {
  9136. if (!props.hasOwnProperty(prop)) {
  9137. continue;
  9138. }
  9139. val = S.trim(props[prop]);
  9140. var to,
  9141. from,
  9142. propCfg = {
  9143. elem:elem,
  9144. prop:prop,
  9145. duration:config.duration,
  9146. easing:specialEasing[prop]
  9147. },
  9148. fx = Fx.getFx(propCfg);
  9149. // hide/show/toggle : special treat!
  9150. if (S.inArray(val, specialVals)) {
  9151. // backup original value
  9152. _backupProps[prop] = DOM.style(elem, prop);
  9153. if (val == "toggle") {
  9154. val = hidden ? "show" : "hide";
  9155. }
  9156. if (val == "hide") {
  9157. to = 0;
  9158. from = fx.cur();
  9159. // 执行完后隐藏
  9160. _backupProps.display = 'none';
  9161. } else {
  9162. from = 0;
  9163. to = fx.cur();
  9164. // prevent flash of content
  9165. DOM.css(elem, prop, from);
  9166. DOM.show(elem);
  9167. }
  9168. val = to;
  9169. } else {
  9170. to = val;
  9171. from = fx.cur();
  9172. }
  9173. val += "";
  9174. var unit = "",
  9175. parts = val.match(rfxnum);
  9176. if (parts) {
  9177. to = parseFloat(parts[2]);
  9178. unit = parts[3];
  9179. // 有单位但单位不是 px
  9180. if (unit && unit !== "px") {
  9181. DOM.css(elem, prop, val);
  9182. from = (to / fx.cur()) * from;
  9183. DOM.css(elem, prop, from + unit);
  9184. }
  9185. // 相对
  9186. if (parts[1]) {
  9187. to = ( (parts[ 1 ] === "-=" ? -1 : 1) * to ) + from;
  9188. }
  9189. }
  9190. propCfg.from = from;
  9191. propCfg.to = to;
  9192. propCfg.unit = unit;
  9193. fx.load(propCfg);
  9194. fxs[prop] = fx;
  9195. }
  9196. if (_isElementNode(elem) &&
  9197. (props.width || props.height)) {
  9198. // Make sure that nothing sneaks out
  9199. // Record all 3 overflow attributes because IE does not
  9200. // change the overflow attribute when overflowX and
  9201. // overflowY are set to the same value
  9202. S.mix(_backupProps, {
  9203. overflow:DOM.style(elem, "overflow"),
  9204. "overflow-x":DOM.style(elem, "overflowX"),
  9205. "overflow-y":DOM.style(elem, "overflowY")
  9206. });
  9207. DOM.css(elem, "overflow", "hidden");
  9208. // inline element should has layout/inline-block
  9209. if (DOM.css(elem, "display") === "inline" &&
  9210. DOM.css(elem, "float") === "none") {
  9211. if (UA['ie']) {
  9212. DOM.css(elem, "zoom", 1);
  9213. } else {
  9214. DOM.css(elem, "display", "inline-block");
  9215. }
  9216. }
  9217. }
  9218. AM.start(self);
  9219. }
  9220. S.augment(Anim, Event.Target, {
  9221. /**
  9222. * @type {boolean} 是否在运行
  9223. */
  9224. isRunning:function() {
  9225. return isRunning(this);
  9226. },
  9227. _runInternal:runInternal,
  9228. /**
  9229. * 开始动画
  9230. */
  9231. run: function() {
  9232. var self = this,
  9233. queueName = self.config.queue;
  9234. if (queueName === false) {
  9235. runInternal.call(self);
  9236. } else {
  9237. // 当前动画对象加入队列
  9238. Q.queue(self);
  9239. }
  9240. return self;
  9241. },
  9242. _frame:function() {
  9243. var self = this,
  9244. prop,
  9245. end = 1,
  9246. fxs = self._fxs;
  9247. for (prop in fxs) {
  9248. if (fxs.hasOwnProperty(prop)) {
  9249. end &= fxs[prop].frame();
  9250. }
  9251. }
  9252. if ((self.fire("step") === false) ||
  9253. end) {
  9254. // complete 事件只在动画到达最后一帧时才触发
  9255. self.stop(end);
  9256. }
  9257. },
  9258. stop: function(finish) {
  9259. var self = this,
  9260. config = self.config,
  9261. queueName = config.queue,
  9262. prop,
  9263. fxs = self._fxs;
  9264. // already stopped
  9265. if (!self.isRunning()) {
  9266. // 从自己的队列中移除
  9267. if (queueName !== false) {
  9268. Q.remove(self);
  9269. }
  9270. return;
  9271. }
  9272. if (finish) {
  9273. for (prop in fxs) {
  9274. if (fxs.hasOwnProperty(prop)) {
  9275. fxs[prop].frame(1);
  9276. }
  9277. }
  9278. self.fire("complete");
  9279. }
  9280. AM.stop(self);
  9281. removeRunning(self);
  9282. if (queueName !== false) {
  9283. // notify next anim to run in the same queue
  9284. Q.dequeue(self);
  9285. }
  9286. return self;
  9287. }
  9288. });
  9289. var runningKey = S.guid("ks-anim-unqueued-" + S.now() + "-");
  9290. function saveRunning(anim) {
  9291. var elem = anim.elem,
  9292. allRunning = DOM.data(elem, runningKey);
  9293. if (!allRunning) {
  9294. DOM.data(elem, runningKey, allRunning = {});
  9295. }
  9296. allRunning[S.stamp(anim)] = anim;
  9297. }
  9298. function removeRunning(anim) {
  9299. var elem = anim.elem,
  9300. allRunning = DOM.data(elem, runningKey);
  9301. if (allRunning) {
  9302. delete allRunning[S.stamp(anim)];
  9303. if (S.isEmptyObject(allRunning)) {
  9304. DOM.removeData(elem, runningKey);
  9305. }
  9306. }
  9307. }
  9308. function isRunning(anim) {
  9309. var elem = anim.elem,
  9310. allRunning = DOM.data(elem, runningKey);
  9311. if (allRunning) {
  9312. return !!allRunning[S.stamp(anim)];
  9313. }
  9314. return 0;
  9315. }
  9316. /**
  9317. * stop all the anims currently running
  9318. * @param elem element which anim belongs to
  9319. * @param end
  9320. * @param clearQueue
  9321. */
  9322. Anim.stop = function(elem, end, clearQueue, queueName) {
  9323. if (
  9324. // default queue
  9325. queueName === null ||
  9326. // name of specified queue
  9327. S.isString(queueName) ||
  9328. // anims not belong to any queue
  9329. queueName === false
  9330. ) {
  9331. return stopQueue.apply(undefined, arguments);
  9332. }
  9333. // first stop first anim in queues
  9334. if (clearQueue) {
  9335. Q.removeQueues(elem);
  9336. }
  9337. var allRunning = DOM.data(elem, runningKey),
  9338. // can not stop in for/in , stop will modified allRunning too
  9339. anims = S.merge(allRunning);
  9340. for (var k in anims) {
  9341. anims[k].stop(end);
  9342. }
  9343. };
  9344. /**
  9345. *
  9346. * @param elem element which anim belongs to
  9347. * @param queueName queue'name if set to false only remove
  9348. * @param end
  9349. * @param clearQueue
  9350. */
  9351. function stopQueue(elem, end, clearQueue, queueName) {
  9352. if (clearQueue && queueName !== false) {
  9353. Q.removeQueue(elem, queueName);
  9354. }
  9355. var allRunning = DOM.data(elem, runningKey),
  9356. anims = S.merge(allRunning);
  9357. for (var k in anims) {
  9358. var anim = anims[k];
  9359. if (anim.config.queue == queueName) {
  9360. anim.stop(end);
  9361. }
  9362. }
  9363. }
  9364. /**
  9365. * whether elem is running anim
  9366. * @param elem
  9367. */
  9368. Anim['isRunning'] = function(elem) {
  9369. var allRunning = DOM.data(elem, runningKey);
  9370. return allRunning && !S.isEmptyObject(allRunning);
  9371. };
  9372. Anim.Q = Q;
  9373. if (SHORT_HANDS) {
  9374. }
  9375. return Anim;
  9376. }, {
  9377. requires:["dom","event","./easing","ua","./manager","./fx","./queue"]
  9378. });
  9379. /**
  9380. * 2011-11
  9381. * - 重构,抛弃 emile,优化性能,只对需要的属性进行动画
  9382. * - 添加 stop/stopQueue/isRunning,支持队列管理
  9383. *
  9384. * 2011-04
  9385. * - 借鉴 yui3 ,中央定时器,否则 ie6 内存泄露?
  9386. * - 支持配置 scrollTop/scrollLeft
  9387. *
  9388. *
  9389. * TODO:
  9390. * - 效率需要提升,当使用 nativeSupport 时仍做了过多动作
  9391. * - opera nativeSupport 存在 bug ,浏览器自身 bug ?
  9392. * - 实现 jQuery Effects 的 queue / specialEasing / += / 等特性
  9393. *
  9394. * NOTES:
  9395. * - 与 emile 相比,增加了 borderStyle, 使得 border: 5px solid #ccc 能从无到有,正确显示
  9396. * - api 借鉴了 YUI, jQuery 以及 http://www.w3.org/TR/css3-transitions/
  9397. * - 代码实现了借鉴了 Emile.js: http://github.com/madrobby/emile *
  9398. */
  9399. /**
  9400. * special patch for making color gradual change
  9401. * @author yiminghe@gmail.com
  9402. */
  9403. KISSY.add("anim/color", function(S, DOM, Anim, Fx) {
  9404. var HEX_BASE = 16,
  9405. floor = Math.floor,
  9406. KEYWORDS = {
  9407. "black":[0,0,0],
  9408. "silver":[192,192,192],
  9409. "gray":[128,128,128],
  9410. "white":[255,255,255],
  9411. "maroon":[128,0,0],
  9412. "red":[255,0,0],
  9413. "purple":[128,0,128],
  9414. "fuchsia":[255,0,255],
  9415. "green":[0,128,0],
  9416. "lime":[0,255,0],
  9417. "olive":[128,128,0],
  9418. "yellow":[255,255,0],
  9419. "navy":[0,0,128],
  9420. "blue":[0,0,255],
  9421. "teal":[0,128,128],
  9422. "aqua":[0,255,255]
  9423. },
  9424. re_RGB = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
  9425. re_RGBA = /^rgba\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+),\s*([0-9]+)\)$/i,
  9426. re_hex = /^#?([0-9A-F]{1,2})([0-9A-F]{1,2})([0-9A-F]{1,2})$/i,
  9427. SHORT_HANDS = Anim.SHORT_HANDS,
  9428. COLORS = [
  9429. 'backgroundColor' ,
  9430. 'borderBottomColor' ,
  9431. 'borderLeftColor' ,
  9432. 'borderRightColor' ,
  9433. 'borderTopColor' ,
  9434. 'color' ,
  9435. 'outlineColor'
  9436. ];
  9437. SHORT_HANDS['background'] = ['backgroundColor'];
  9438. SHORT_HANDS['borderColor'] = [
  9439. 'borderBottomColor',
  9440. 'borderLeftColor',
  9441. 'borderRightColor',
  9442. 'borderTopColor'
  9443. ];
  9444. SHORT_HANDS['border'].push(
  9445. 'borderBottomColor',
  9446. 'borderLeftColor',
  9447. 'borderRightColor',
  9448. 'borderTopColor'
  9449. );
  9450. SHORT_HANDS['borderBottom'].push(
  9451. 'borderBottomColor'
  9452. );
  9453. SHORT_HANDS['borderLeft'].push(
  9454. 'borderLeftColor'
  9455. );
  9456. SHORT_HANDS['borderRight'].push(
  9457. 'borderRightColor'
  9458. );
  9459. SHORT_HANDS['borderTop'].push(
  9460. 'borderTopColor'
  9461. );
  9462. //得到颜色的数值表示,红绿蓝数字数组
  9463. function numericColor(val) {
  9464. val = (val + "");
  9465. var match;
  9466. if (match = val.match(re_RGB)) {
  9467. return [
  9468. parseInt(match[1]),
  9469. parseInt(match[2]),
  9470. parseInt(match[3])
  9471. ];
  9472. }
  9473. else if (match = val.match(re_RGBA)) {
  9474. return [
  9475. parseInt(match[1]),
  9476. parseInt(match[2]),
  9477. parseInt(match[3]),
  9478. parseInt(match[4])
  9479. ];
  9480. }
  9481. else if (match = val.match(re_hex)) {
  9482. for (var i = 1; i < match.length; i++) {
  9483. if (match[i].length < 2) {
  9484. match[i] += match[i];
  9485. }
  9486. }
  9487. return [
  9488. parseInt(match[1], HEX_BASE),
  9489. parseInt(match[2], HEX_BASE),
  9490. parseInt(match[3], HEX_BASE)
  9491. ];
  9492. }
  9493. if (KEYWORDS[val = val.toLowerCase()]) {
  9494. return KEYWORDS[val];
  9495. }
  9496. //transparent 或者 颜色字符串返回
  9497. S.log("only allow rgb or hex color string : " + val, "warn");
  9498. return [255,255,255];
  9499. }
  9500. function ColorFx() {
  9501. ColorFx.superclass.constructor.apply(this, arguments);
  9502. }
  9503. S.extend(ColorFx, Fx, {
  9504. load:function() {
  9505. var self = this;
  9506. ColorFx.superclass.load.apply(self, arguments);
  9507. if (self.from) {
  9508. self.from = numericColor(self.from);
  9509. }
  9510. if (self.to) {
  9511. self.to = numericColor(self.to);
  9512. }
  9513. },
  9514. interpolate:function (from, to, pos) {
  9515. var interpolate = ColorFx.superclass.interpolate;
  9516. if (from.length == 3 && to.length == 3) {
  9517. return 'rgb(' + [
  9518. floor(interpolate(from[0], to[0], pos)),
  9519. floor(interpolate(from[1], to[1], pos)),
  9520. floor(interpolate(from[2], to[2], pos))
  9521. ].join(', ') + ')';
  9522. } else if (from.length == 4 || to.length == 4) {
  9523. return 'rgba(' + [
  9524. floor(interpolate(from[0], to[0], pos)),
  9525. floor(interpolate(from[1], to[1], pos)),
  9526. floor(interpolate(from[2], to[2], pos)),
  9527. // 透明度默认 1
  9528. floor(interpolate(from[3] || 1, to[3] || 1, pos))
  9529. ].join(', ') + ')';
  9530. } else {
  9531. S.log("anim/color unknown value : " + from);
  9532. }
  9533. }
  9534. });
  9535. S.each(COLORS, function(color) {
  9536. Fx.Factories[color] = ColorFx;
  9537. });
  9538. return ColorFx;
  9539. }, {
  9540. requires:["dom","./base","./fx"]
  9541. });
  9542. /**
  9543. * TODO
  9544. * 支持 hsla
  9545. * - https://github.com/jquery/jquery-color/blob/master/jquery.color.js
  9546. **/
  9547. KISSY.add("anim", function(S, Anim,Easing) {
  9548. Anim.Easing=Easing;
  9549. return Anim;
  9550. }, {
  9551. requires:["anim/base","anim/easing","anim/color"]
  9552. });
  9553. /**
  9554. * @module anim-node-plugin
  9555. * @author yiminghe@gmail.com,
  9556. * lifesinger@gmail.com,
  9557. * qiaohua@taobao.com,
  9558. *
  9559. */
  9560. KISSY.add('node/anim', function(S, DOM, Anim, Node, undefined) {
  9561. var FX = [
  9562. // height animations
  9563. [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
  9564. // width animations
  9565. [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
  9566. // opacity animations
  9567. [ "opacity" ]
  9568. ];
  9569. function getFxs(type, num, from) {
  9570. var ret = [],
  9571. obj = {};
  9572. for (var i = from || 0; i < num; i++) {
  9573. ret.push.apply(ret, FX[i]);
  9574. }
  9575. for (i = 0; i < ret.length; i++) {
  9576. obj[ret[i]] = type;
  9577. }
  9578. return obj;
  9579. }
  9580. S.augment(Node, {
  9581. animate:function() {
  9582. var self = this,
  9583. args = S.makeArray(arguments);
  9584. S.each(self, function(elem) {
  9585. Anim.apply(undefined, [elem].concat(args)).run();
  9586. });
  9587. return self;
  9588. },
  9589. stop:function(end, clearQueue, queue) {
  9590. var self = this;
  9591. S.each(self, function(elem) {
  9592. Anim.stop(elem, end, clearQueue, queue);
  9593. });
  9594. return self;
  9595. },
  9596. isRunning:function() {
  9597. var self = this;
  9598. for (var i = 0; i < self.length; i++) {
  9599. if (Anim.isRunning(self[i])) {
  9600. return 1;
  9601. }
  9602. }
  9603. return 0;
  9604. }
  9605. });
  9606. S.each({
  9607. show: getFxs("show", 3),
  9608. hide: getFxs("hide", 3),
  9609. toggle:getFxs("toggle", 3),
  9610. fadeIn: getFxs("show", 3, 2),
  9611. fadeOut: getFxs("hide", 3, 2),
  9612. fadeToggle:getFxs("toggle", 3, 2),
  9613. slideDown: getFxs("show", 1),
  9614. slideUp: getFxs("hide", 1),
  9615. slideToggle:getFxs("toggle", 1)
  9616. },
  9617. function(v, k) {
  9618. Node.prototype[k] = function(speed, callback, easing) {
  9619. var self = this;
  9620. // 没有参数时,调用 DOM 中的对应方法
  9621. if (DOM[k] && !speed) {
  9622. DOM[k](self);
  9623. } else {
  9624. S.each(self, function(elem) {
  9625. Anim(elem, v, speed, easing || 'easeOut', callback).run();
  9626. });
  9627. }
  9628. return self;
  9629. };
  9630. });
  9631. }, {
  9632. requires:["dom","anim","./base"]
  9633. });
  9634. /**
  9635. * 2011-11-10
  9636. * - 重写,逻辑放到 Anim 模块,这边只进行转发
  9637. *
  9638. * 2011-05-17
  9639. * - 承玉:添加 stop ,随时停止动画
  9640. *
  9641. * TODO
  9642. * - anim needs queue mechanism ?
  9643. */
  9644. KISSY.add("node", function(S, Event, Node) {
  9645. Node.KeyCodes = Event.KeyCodes;
  9646. return Node;
  9647. }, {
  9648. requires:[
  9649. "event",
  9650. "node/base",
  9651. "node/attach",
  9652. "node/override",
  9653. "node/anim"]
  9654. });
  9655. /*
  9656. http://www.JSON.org/json2.js
  9657. 2010-08-25
  9658. Public Domain.
  9659. NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  9660. See http://www.JSON.org/js.html
  9661. This code should be minified before deployment.
  9662. See http://javascript.crockford.com/jsmin.html
  9663. USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
  9664. NOT CONTROL.
  9665. This file creates a global JSON object containing two methods: stringify
  9666. and parse.
  9667. JSON.stringify(value, replacer, space)
  9668. value any JavaScript value, usually an object or array.
  9669. replacer an optional parameter that determines how object
  9670. values are stringified for objects. It can be a
  9671. function or an array of strings.
  9672. space an optional parameter that specifies the indentation
  9673. of nested structures. If it is omitted, the text will
  9674. be packed without extra whitespace. If it is a number,
  9675. it will specify the number of spaces to indent at each
  9676. level. If it is a string (such as '\t' or '&nbsp;'),
  9677. it contains the characters used to indent at each level.
  9678. This method produces a JSON text from a JavaScript value.
  9679. When an object value is found, if the object contains a toJSON
  9680. method, its toJSON method will be called and the result will be
  9681. stringified. A toJSON method does not serialize: it returns the
  9682. value represented by the name/value pair that should be serialized,
  9683. or undefined if nothing should be serialized. The toJSON method
  9684. will be passed the key associated with the value, and this will be
  9685. bound to the value
  9686. For example, this would serialize Dates as ISO strings.
  9687. Date.prototype.toJSON = function (key) {
  9688. function f(n) {
  9689. // Format integers to have at least two digits.
  9690. return n < 10 ? '0' + n : n;
  9691. }
  9692. return this.getUTCFullYear() + '-' +
  9693. f(this.getUTCMonth() + 1) + '-' +
  9694. f(this.getUTCDate()) + 'T' +
  9695. f(this.getUTCHours()) + ':' +
  9696. f(this.getUTCMinutes()) + ':' +
  9697. f(this.getUTCSeconds()) + 'Z';
  9698. };
  9699. You can provide an optional replacer method. It will be passed the
  9700. key and value of each member, with this bound to the containing
  9701. object. The value that is returned from your method will be
  9702. serialized. If your method returns undefined, then the member will
  9703. be excluded from the serialization.
  9704. If the replacer parameter is an array of strings, then it will be
  9705. used to select the members to be serialized. It filters the results
  9706. such that only members with keys listed in the replacer array are
  9707. stringified.
  9708. Values that do not have JSON representations, such as undefined or
  9709. functions, will not be serialized. Such values in objects will be
  9710. dropped; in arrays they will be replaced with null. You can use
  9711. a replacer function to replace those with JSON values.
  9712. JSON.stringify(undefined) returns undefined.
  9713. The optional space parameter produces a stringification of the
  9714. value that is filled with line breaks and indentation to make it
  9715. easier to read.
  9716. If the space parameter is a non-empty string, then that string will
  9717. be used for indentation. If the space parameter is a number, then
  9718. the indentation will be that many spaces.
  9719. Example:
  9720. text = JSON.stringify(['e', {pluribus: 'unum'}]);
  9721. // text is '["e",{"pluribus":"unum"}]'
  9722. text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
  9723. // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
  9724. text = JSON.stringify([new Date()], function (key, value) {
  9725. return this[key] instanceof Date ?
  9726. 'Date(' + this[key] + ')' : value;
  9727. });
  9728. // text is '["Date(---current time---)"]'
  9729. JSON.parse(text, reviver)
  9730. This method parses a JSON text to produce an object or array.
  9731. It can throw a SyntaxError exception.
  9732. The optional reviver parameter is a function that can filter and
  9733. transform the results. It receives each of the keys and values,
  9734. and its return value is used instead of the original value.
  9735. If it returns what it received, then the structure is not modified.
  9736. If it returns undefined then the member is deleted.
  9737. Example:
  9738. // Parse the text. Values that look like ISO date strings will
  9739. // be converted to Date objects.
  9740. myData = JSON.parse(text, function (key, value) {
  9741. var a;
  9742. if (typeof value === 'string') {
  9743. a =
  9744. /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
  9745. if (a) {
  9746. return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
  9747. +a[5], +a[6]));
  9748. }
  9749. }
  9750. return value;
  9751. });
  9752. myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
  9753. var d;
  9754. if (typeof value === 'string' &&
  9755. value.slice(0, 5) === 'Date(' &&
  9756. value.slice(-1) === ')') {
  9757. d = new Date(value.slice(5, -1));
  9758. if (d) {
  9759. return d;
  9760. }
  9761. }
  9762. return value;
  9763. });
  9764. This is a reference implementation. You are free to copy, modify, or
  9765. redistribute.
  9766. */
  9767. /*jslint evil: true, strict: false */
  9768. /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
  9769. call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
  9770. getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
  9771. lastIndex, length, parse, prototype, push, replace, slice, stringify,
  9772. test, toJSON, toString, valueOf
  9773. */
  9774. // Create a JSON object only if one does not already exist. We create the
  9775. // methods in a closure to avoid creating global variables.
  9776. KISSY.add("json/json2", function(S, UA) {
  9777. var win = window,JSON = win.JSON;
  9778. // ie 8.0.7600.16315@win7 json 有问题
  9779. if (!JSON || UA['ie'] < 9) {
  9780. JSON = win.JSON = {};
  9781. }
  9782. function f(n) {
  9783. // Format integers to have at least two digits.
  9784. return n < 10 ? '0' + n : n;
  9785. }
  9786. if (typeof Date.prototype.toJSON !== 'function') {
  9787. Date.prototype.toJSON = function (key) {
  9788. return isFinite(this.valueOf()) ?
  9789. this.getUTCFullYear() + '-' +
  9790. f(this.getUTCMonth() + 1) + '-' +
  9791. f(this.getUTCDate()) + 'T' +
  9792. f(this.getUTCHours()) + ':' +
  9793. f(this.getUTCMinutes()) + ':' +
  9794. f(this.getUTCSeconds()) + 'Z' : null;
  9795. };
  9796. String.prototype.toJSON =
  9797. Number.prototype.toJSON =
  9798. Boolean.prototype.toJSON = function (key) {
  9799. return this.valueOf();
  9800. };
  9801. }
  9802. var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  9803. escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
  9804. gap,
  9805. indent,
  9806. meta = { // table of character substitutions
  9807. '\b': '\\b',
  9808. '\t': '\\t',
  9809. '\n': '\\n',
  9810. '\f': '\\f',
  9811. '\r': '\\r',
  9812. '"' : '\\"',
  9813. '\\': '\\\\'
  9814. },
  9815. rep;
  9816. function quote(string) {
  9817. // If the string contains no control characters, no quote characters, and no
  9818. // backslash characters, then we can safely slap some quotes around it.
  9819. // Otherwise we must also replace the offending characters with safe escape
  9820. // sequences.
  9821. escapable['lastIndex'] = 0;
  9822. return escapable.test(string) ?
  9823. '"' + string.replace(escapable, function (a) {
  9824. var c = meta[a];
  9825. return typeof c === 'string' ? c :
  9826. '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  9827. }) + '"' :
  9828. '"' + string + '"';
  9829. }
  9830. function str(key, holder) {
  9831. // Produce a string from holder[key].
  9832. var i, // The loop counter.
  9833. k, // The member key.
  9834. v, // The member value.
  9835. length,
  9836. mind = gap,
  9837. partial,
  9838. value = holder[key];
  9839. // If the value has a toJSON method, call it to obtain a replacement value.
  9840. if (value && typeof value === 'object' &&
  9841. typeof value.toJSON === 'function') {
  9842. value = value.toJSON(key);
  9843. }
  9844. // If we were called with a replacer function, then call the replacer to
  9845. // obtain a replacement value.
  9846. if (typeof rep === 'function') {
  9847. value = rep.call(holder, key, value);
  9848. }
  9849. // What happens next depends on the value's type.
  9850. switch (typeof value) {
  9851. case 'string':
  9852. return quote(value);
  9853. case 'number':
  9854. // JSON numbers must be finite. Encode non-finite numbers as null.
  9855. return isFinite(value) ? String(value) : 'null';
  9856. case 'boolean':
  9857. case 'null':
  9858. // If the value is a boolean or null, convert it to a string. Note:
  9859. // typeof null does not produce 'null'. The case is included here in
  9860. // the remote chance that this gets fixed someday.
  9861. return String(value);
  9862. // If the type is 'object', we might be dealing with an object or an array or
  9863. // null.
  9864. case 'object':
  9865. // Due to a specification blunder in ECMAScript, typeof null is 'object',
  9866. // so watch out for that case.
  9867. if (!value) {
  9868. return 'null';
  9869. }
  9870. // Make an array to hold the partial results of stringifying this object value.
  9871. gap += indent;
  9872. partial = [];
  9873. // Is the value an array?
  9874. if (Object.prototype.toString.apply(value) === '[object Array]') {
  9875. // The value is an array. Stringify every element. Use null as a placeholder
  9876. // for non-JSON values.
  9877. length = value.length;
  9878. for (i = 0; i < length; i += 1) {
  9879. partial[i] = str(i, value) || 'null';
  9880. }
  9881. // Join all of the elements together, separated with commas, and wrap them in
  9882. // brackets.
  9883. v = partial.length === 0 ? '[]' :
  9884. gap ? '[\n' + gap +
  9885. partial.join(',\n' + gap) + '\n' +
  9886. mind + ']' :
  9887. '[' + partial.join(',') + ']';
  9888. gap = mind;
  9889. return v;
  9890. }
  9891. // If the replacer is an array, use it to select the members to be stringified.
  9892. if (rep && typeof rep === 'object') {
  9893. length = rep.length;
  9894. for (i = 0; i < length; i += 1) {
  9895. k = rep[i];
  9896. if (typeof k === 'string') {
  9897. v = str(k, value);
  9898. if (v) {
  9899. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  9900. }
  9901. }
  9902. }
  9903. } else {
  9904. // Otherwise, iterate through all of the keys in the object.
  9905. for (k in value) {
  9906. if (Object.hasOwnProperty.call(value, k)) {
  9907. v = str(k, value);
  9908. if (v) {
  9909. partial.push(quote(k) + (gap ? ': ' : ':') + v);
  9910. }
  9911. }
  9912. }
  9913. }
  9914. // Join all of the member texts together, separated with commas,
  9915. // and wrap them in braces.
  9916. v = partial.length === 0 ? '{}' :
  9917. gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
  9918. mind + '}' : '{' + partial.join(',') + '}';
  9919. gap = mind;
  9920. return v;
  9921. }
  9922. }
  9923. // If the JSON object does not yet have a stringify method, give it one.
  9924. if (typeof JSON.stringify !== 'function') {
  9925. JSON.stringify = function (value, replacer, space) {
  9926. // The stringify method takes a value and an optional replacer, and an optional
  9927. // space parameter, and returns a JSON text. The replacer can be a function
  9928. // that can replace values, or an array of strings that will select the keys.
  9929. // A default replacer method can be provided. Use of the space parameter can
  9930. // produce text that is more easily readable.
  9931. var i;
  9932. gap = '';
  9933. indent = '';
  9934. // If the space parameter is a number, make an indent string containing that
  9935. // many spaces.
  9936. if (typeof space === 'number') {
  9937. for (i = 0; i < space; i += 1) {
  9938. indent += ' ';
  9939. }
  9940. // If the space parameter is a string, it will be used as the indent string.
  9941. } else if (typeof space === 'string') {
  9942. indent = space;
  9943. }
  9944. // If there is a replacer, it must be a function or an array.
  9945. // Otherwise, throw an error.
  9946. rep = replacer;
  9947. if (replacer && typeof replacer !== 'function' &&
  9948. (typeof replacer !== 'object' ||
  9949. typeof replacer.length !== 'number')) {
  9950. throw new Error('JSON.stringify');
  9951. }
  9952. // Make a fake root object containing our value under the key of ''.
  9953. // Return the result of stringifying the value.
  9954. return str('', {'': value});
  9955. };
  9956. }
  9957. // If the JSON object does not yet have a parse method, give it one.
  9958. if (typeof JSON.parse !== 'function') {
  9959. JSON.parse = function (text, reviver) {
  9960. // The parse method takes a text and an optional reviver function, and returns
  9961. // a JavaScript value if the text is a valid JSON text.
  9962. var j;
  9963. function walk(holder, key) {
  9964. // The walk method is used to recursively walk the resulting structure so
  9965. // that modifications can be made.
  9966. var k, v, value = holder[key];
  9967. if (value && typeof value === 'object') {
  9968. for (k in value) {
  9969. if (Object.hasOwnProperty.call(value, k)) {
  9970. v = walk(value, k);
  9971. if (v !== undefined) {
  9972. value[k] = v;
  9973. } else {
  9974. delete value[k];
  9975. }
  9976. }
  9977. }
  9978. }
  9979. return reviver.call(holder, key, value);
  9980. }
  9981. // Parsing happens in four stages. In the first stage, we replace certain
  9982. // Unicode characters with escape sequences. JavaScript handles many characters
  9983. // incorrectly, either silently deleting them, or treating them as line endings.
  9984. text = String(text);
  9985. cx['lastIndex'] = 0;
  9986. if (cx.test(text)) {
  9987. text = text.replace(cx, function (a) {
  9988. return '\\u' +
  9989. ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
  9990. });
  9991. }
  9992. // In the second stage, we run the text against regular expressions that look
  9993. // for non-JSON patterns. We are especially concerned with '()' and 'new'
  9994. // because they can cause invocation, and '=' because it can cause mutation.
  9995. // But just to be safe, we want to reject all unexpected forms.
  9996. // We split the second stage into 4 regexp operations in order to work around
  9997. // crippling inefficiencies in IE's and Safari's regexp engines. First we
  9998. // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
  9999. // replace all simple value tokens with ']' characters. Third, we delete all
  10000. // open brackets that follow a colon or comma or that begin the text. Finally,
  10001. // we look to see that the remaining characters are only whitespace or ']' or
  10002. // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
  10003. if (/^[\],:{}\s]*$/
  10004. .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
  10005. .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
  10006. .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
  10007. // In the third stage we use the eval function to compile the text into a
  10008. // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
  10009. // in JavaScript: it can begin a block or an object literal. We wrap the text
  10010. // in parens to eliminate the ambiguity.
  10011. j = eval('(' + text + ')');
  10012. // In the optional fourth stage, we recursively walk the new structure, passing
  10013. // each name/value pair to a reviver function for possible transformation.
  10014. return typeof reviver === 'function' ?
  10015. walk({'': j}, '') : j;
  10016. }
  10017. // If the text is not JSON parseable, then a SyntaxError is thrown.
  10018. throw new SyntaxError('JSON.parse');
  10019. };
  10020. }
  10021. return JSON;
  10022. }, {requires:['ua']});
  10023. /**
  10024. * adapt json2 to kissy
  10025. * @author lifesinger@gmail.com
  10026. */
  10027. KISSY.add('json', function (S, JSON) {
  10028. return {
  10029. parse: function(text) {
  10030. // 当输入为 undefined / null / '' 时,返回 null
  10031. if (S.isNullOrUndefined(text) || text === '') {
  10032. return null;
  10033. }
  10034. return JSON.parse(text);
  10035. },
  10036. stringify: JSON.stringify
  10037. };
  10038. }, {
  10039. requires:["json/json2"]
  10040. });
  10041. /**
  10042. * form data serialization util
  10043. * @author yiminghe@gmail.com
  10044. */
  10045. KISSY.add("ajax/form-serializer", function(S, DOM) {
  10046. var rselectTextarea = /^(?:select|textarea)/i,
  10047. rCRLF = /\r?\n/g,
  10048. rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i;
  10049. return {
  10050. /**
  10051. * 序列化表单元素
  10052. * @param {String|HTMLElement[]|HTMLElement|Node} forms
  10053. */
  10054. serialize:function(forms) {
  10055. var elements = [],data = {};
  10056. DOM.query(forms).each(function(el) {
  10057. // form 取其表单元素集合
  10058. // 其他直接取自身
  10059. var subs = el.elements ? S.makeArray(el.elements) : [el];
  10060. elements.push.apply(elements, subs);
  10061. });
  10062. // 对表单元素进行过滤,具备有效值的才保留
  10063. elements = S.filter(elements, function(el) {
  10064. // 有名字
  10065. return el.name &&
  10066. // 不被禁用
  10067. !el.disabled &&
  10068. (
  10069. // radio,checkbox 被选择了
  10070. el.checked ||
  10071. // select 或者 textarea
  10072. rselectTextarea.test(el.nodeName) ||
  10073. // input 类型
  10074. rinput.test(el.type)
  10075. );
  10076. // 这样子才取值
  10077. });
  10078. S.each(elements, function(el) {
  10079. var val = DOM.val(el),vs;
  10080. // 字符串换行平台归一化
  10081. val = S.map(S.makeArray(val), function(v) {
  10082. return v.replace(rCRLF, "\r\n");
  10083. });
  10084. // 全部搞成数组,防止同名
  10085. vs = data[el.name] = data[el.name] || [];
  10086. vs.push.apply(vs, val);
  10087. });
  10088. // 名值键值对序列化,数组元素名字前不加 []
  10089. return S.param(data, undefined, undefined, false);
  10090. }
  10091. };
  10092. }, {
  10093. requires:['dom']
  10094. });
  10095. /**
  10096. * encapsulation of io object . as transaction object in yui3
  10097. * @author yiminghe@gmail.com
  10098. */
  10099. KISSY.add("ajax/xhrobject", function(S, Event) {
  10100. var OK_CODE = 200,
  10101. MULTIPLE_CHOICES = 300,
  10102. NOT_MODIFIED = 304,
  10103. // get individual response header from responseheader str
  10104. rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg;
  10105. function handleResponseData(xhr) {
  10106. // text xml 是否原生转化支持
  10107. var text = xhr.responseText,
  10108. xml = xhr.responseXML,
  10109. c = xhr.config,
  10110. cConverts = c.converters,
  10111. xConverts = xhr.converters || {},
  10112. type,
  10113. responseData,
  10114. contents = c.contents,
  10115. dataType = c.dataType;
  10116. // 例如 script 直接是js引擎执行,没有返回值,不需要自己处理初始返回值
  10117. // jsonp 时还需要把 script 转换成 json,后面还得自己来
  10118. if (text || xml) {
  10119. var contentType = xhr.mimeType || xhr.getResponseHeader("Content-Type");
  10120. // 去除无用的通用格式
  10121. while (dataType[0] == "*") {
  10122. dataType.shift();
  10123. }
  10124. if (!dataType.length) {
  10125. // 获取源数据格式,放在第一个
  10126. for (type in contents) {
  10127. if (contents[type].test(contentType)) {
  10128. if (dataType[0] != type) {
  10129. dataType.unshift(type);
  10130. }
  10131. break;
  10132. }
  10133. }
  10134. }
  10135. // 服务器端没有告知(并且客户端没有mimetype)默认 text 类型
  10136. dataType[0] = dataType[0] || "text";
  10137. //获得合适的初始数据
  10138. if (dataType[0] == "text" && text !== undefined) {
  10139. responseData = text;
  10140. }
  10141. // 有 xml 值才直接取,否则可能还要从 xml 转
  10142. else if (dataType[0] == "xml" && xml !== undefined) {
  10143. responseData = xml;
  10144. } else {
  10145. // 看能否从 text xml 转换到合适数据
  10146. S.each(["text","xml"], function(prevType) {
  10147. var type = dataType[0],
  10148. converter = xConverts[prevType] && xConverts[prevType][type] ||
  10149. cConverts[prevType] && cConverts[prevType][type];
  10150. if (converter) {
  10151. dataType.unshift(prevType);
  10152. responseData = prevType == "text" ? text : xml;
  10153. return false;
  10154. }
  10155. });
  10156. }
  10157. }
  10158. var prevType = dataType[0];
  10159. // 按照转化链把初始数据转换成我们想要的数据类型
  10160. for (var i = 1; i < dataType.length; i++) {
  10161. type = dataType[i];
  10162. var converter = xConverts[prevType] && xConverts[prevType][type] ||
  10163. cConverts[prevType] && cConverts[prevType][type];
  10164. if (!converter) {
  10165. throw "no covert for " + prevType + " => " + type;
  10166. }
  10167. responseData = converter(responseData);
  10168. prevType = type;
  10169. }
  10170. xhr.responseData = responseData;
  10171. }
  10172. function XhrObject(c) {
  10173. S.mix(this, {
  10174. // 结构化数据,如 json
  10175. responseData:null,
  10176. config:c || {},
  10177. timeoutTimer:null,
  10178. responseText:null,
  10179. responseXML:null,
  10180. responseHeadersString:"",
  10181. responseHeaders:null,
  10182. requestHeaders:{},
  10183. readyState:0,
  10184. //internal state
  10185. state:0,
  10186. statusText:null,
  10187. status:0,
  10188. transport:null
  10189. });
  10190. }
  10191. S.augment(XhrObject, Event.Target, {
  10192. // Caches the header
  10193. setRequestHeader: function(name, value) {
  10194. this.requestHeaders[ name ] = value;
  10195. return this;
  10196. },
  10197. // Raw string
  10198. getAllResponseHeaders: function() {
  10199. return this.state === 2 ? this.responseHeadersString : null;
  10200. },
  10201. // Builds headers hashtable if needed
  10202. getResponseHeader: function(key) {
  10203. var match;
  10204. if (this.state === 2) {
  10205. if (!this.responseHeaders) {
  10206. this.responseHeaders = {};
  10207. while (( match = rheaders.exec(this.responseHeadersString) )) {
  10208. this.responseHeaders[ match[1] ] = match[ 2 ];
  10209. }
  10210. }
  10211. match = this.responseHeaders[ key];
  10212. }
  10213. return match === undefined ? null : match;
  10214. },
  10215. // Overrides response content-type header
  10216. overrideMimeType: function(type) {
  10217. if (!this.state) {
  10218. this.mimeType = type;
  10219. }
  10220. return this;
  10221. },
  10222. // Cancel the request
  10223. abort: function(statusText) {
  10224. statusText = statusText || "abort";
  10225. if (this.transport) {
  10226. this.transport.abort(statusText);
  10227. }
  10228. this.callback(0, statusText);
  10229. return this;
  10230. },
  10231. callback:function(status, statusText) {
  10232. //debugger
  10233. var xhr = this;
  10234. // 只能执行一次,防止重复执行
  10235. // 例如完成后,调用 abort
  10236. // 到这要么成功,调用success
  10237. // 要么失败,调用 error
  10238. // 最终都会调用 complete
  10239. if (xhr.state == 2) {
  10240. return;
  10241. }
  10242. xhr.state = 2;
  10243. xhr.readyState = 4;
  10244. var isSuccess;
  10245. if (status >= OK_CODE && status < MULTIPLE_CHOICES || status == NOT_MODIFIED) {
  10246. if (status == NOT_MODIFIED) {
  10247. statusText = "notmodified";
  10248. isSuccess = true;
  10249. } else {
  10250. try {
  10251. handleResponseData(xhr);
  10252. statusText = "success";
  10253. isSuccess = true;
  10254. } catch(e) {
  10255. statusText = "parsererror : " + e;
  10256. }
  10257. }
  10258. } else {
  10259. if (status < 0) {
  10260. status = 0;
  10261. }
  10262. }
  10263. xhr.status = status;
  10264. xhr.statusText = statusText;
  10265. if (isSuccess) {
  10266. xhr.fire("success");
  10267. } else {
  10268. xhr.fire("error");
  10269. }
  10270. xhr.fire("complete");
  10271. xhr.transport = undefined;
  10272. }
  10273. }
  10274. );
  10275. return XhrObject;
  10276. }, {
  10277. requires:["event"]
  10278. });
  10279. /**
  10280. * a scalable client io framework
  10281. * @author yiminghe@gmail.com , lijing00333@163.com
  10282. */
  10283. KISSY.add("ajax/base", function(S, JSON, Event, XhrObject) {
  10284. var rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|widget):$/,
  10285. rspace = /\s+/,
  10286. rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  10287. mirror = function(s) {
  10288. return s;
  10289. },
  10290. HTTP_PORT = 80,
  10291. HTTPS_PORT = 443,
  10292. rnoContent = /^(?:GET|HEAD)$/,
  10293. curLocation,
  10294. curLocationParts;
  10295. try {
  10296. curLocation = location.href;
  10297. } catch(e) {
  10298. S.log("ajax/base get curLocation error : ");
  10299. S.log(e);
  10300. // Use the href attribute of an A element
  10301. // since IE will modify it given document.location
  10302. curLocation = document.createElement("a");
  10303. curLocation.href = "";
  10304. curLocation = curLocation.href;
  10305. }
  10306. curLocationParts = rurl.exec(curLocation);
  10307. var isLocal = rlocalProtocol.test(curLocationParts[1]),
  10308. transports = {},
  10309. defaultConfig = {
  10310. // isLocal:isLocal,
  10311. type:"GET",
  10312. // only support utf-8 when post, encoding can not be changed actually
  10313. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  10314. async:true,
  10315. // whether add []
  10316. serializeArray:true,
  10317. // whether param data
  10318. processData:true,
  10319. /*
  10320. url:"",
  10321. context:null,
  10322. // 单位秒!!
  10323. timeout: 0,
  10324. data: null,
  10325. // 可取json | jsonp | script | xml | html | text | null | undefined
  10326. dataType: null,
  10327. username: null,
  10328. password: null,
  10329. cache: null,
  10330. mimeType:null,
  10331. xdr:{
  10332. subDomain:{
  10333. proxy:'http://xx.t.com/proxy.html'
  10334. },
  10335. src:''
  10336. },
  10337. headers: {},
  10338. xhrFields:{},
  10339. // jsonp script charset
  10340. scriptCharset:null,
  10341. crossdomain:false,
  10342. forceScript:false,
  10343. */
  10344. accepts: {
  10345. xml: "application/xml, text/xml",
  10346. html: "text/html",
  10347. text: "text/plain",
  10348. json: "application/json, text/javascript",
  10349. "*": "*/*"
  10350. },
  10351. converters:{
  10352. text:{
  10353. json:JSON.parse,
  10354. html:mirror,
  10355. text:mirror,
  10356. xml:S.parseXML
  10357. }
  10358. },
  10359. contents:{
  10360. xml:/xml/,
  10361. html:/html/,
  10362. json:/json/
  10363. }
  10364. };
  10365. defaultConfig.converters.html = defaultConfig.converters.text;
  10366. function setUpConfig(c) {
  10367. // deep mix
  10368. c = S.mix(S.clone(defaultConfig), c || {}, undefined, undefined, true);
  10369. if (!S.isBoolean(c.crossDomain)) {
  10370. var parts = rurl.exec(c.url.toLowerCase());
  10371. c.crossDomain = !!( parts &&
  10372. ( parts[ 1 ] != curLocationParts[ 1 ] || parts[ 2 ] != curLocationParts[ 2 ] ||
  10373. ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? HTTP_PORT : HTTPS_PORT ) )
  10374. !=
  10375. ( curLocationParts[ 3 ] || ( curLocationParts[ 1 ] === "http:" ? HTTP_PORT : HTTPS_PORT ) ) )
  10376. );
  10377. }
  10378. if (c.processData && c.data && !S.isString(c.data)) {
  10379. // 必须 encodeURIComponent 编码 utf-8
  10380. c.data = S.param(c.data, undefined, undefined, c.serializeArray);
  10381. }
  10382. c.type = c.type.toUpperCase();
  10383. c.hasContent = !rnoContent.test(c.type);
  10384. if (!c.hasContent) {
  10385. if (c.data) {
  10386. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + c.data;
  10387. }
  10388. if (c.cache === false) {
  10389. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + "_ksTS=" + (S.now() + "_" + S.guid());
  10390. }
  10391. }
  10392. // 数据类型处理链,一步步将前面的数据类型转化成最后一个
  10393. c.dataType = S.trim(c.dataType || "*").split(rspace);
  10394. c.context = c.context || c;
  10395. return c;
  10396. }
  10397. function fire(eventType, xhr) {
  10398. io.fire(eventType, { ajaxConfig: xhr.config ,xhr:xhr});
  10399. }
  10400. function handleXhrEvent(e) {
  10401. var xhr = this,
  10402. c = xhr.config,
  10403. type = e.type;
  10404. if (this.timeoutTimer) {
  10405. clearTimeout(this.timeoutTimer);
  10406. }
  10407. if (c[type]) {
  10408. c[type].call(c.context, xhr.responseData, xhr.statusText, xhr);
  10409. }
  10410. fire(type, xhr);
  10411. }
  10412. function io(c) {
  10413. if (!c.url) {
  10414. return undefined;
  10415. }
  10416. c = setUpConfig(c);
  10417. var xhr = new XhrObject(c);
  10418. fire("start", xhr);
  10419. var transportContructor = transports[c.dataType[0]] || transports["*"],
  10420. transport = new transportContructor(xhr);
  10421. xhr.transport = transport;
  10422. if (c.contentType) {
  10423. xhr.setRequestHeader("Content-Type", c.contentType);
  10424. }
  10425. var dataType = c.dataType[0],
  10426. accepts = c.accepts;
  10427. // Set the Accepts header for the server, depending on the dataType
  10428. xhr.setRequestHeader(
  10429. "Accept",
  10430. dataType && accepts[dataType] ?
  10431. accepts[ dataType ] + (dataType === "*" ? "" : ", */*; q=0.01" ) :
  10432. accepts[ "*" ]
  10433. );
  10434. // Check for headers option
  10435. for (var i in c.headers) {
  10436. xhr.setRequestHeader(i, c.headers[ i ]);
  10437. }
  10438. xhr.on("complete success error", handleXhrEvent);
  10439. xhr.readyState = 1;
  10440. fire("send", xhr);
  10441. // Timeout
  10442. if (c.async && c.timeout > 0) {
  10443. xhr.timeoutTimer = setTimeout(function() {
  10444. xhr.abort("timeout");
  10445. }, c.timeout * 1000);
  10446. }
  10447. try {
  10448. // flag as sending
  10449. xhr.state = 1;
  10450. transport.send();
  10451. } catch (e) {
  10452. // Propagate exception as error if not done
  10453. if (xhr.status < 2) {
  10454. xhr.callback(-1, e);
  10455. // Simply rethrow otherwise
  10456. } else {
  10457. S.error(e);
  10458. }
  10459. }
  10460. return xhr;
  10461. }
  10462. S.mix(io, Event.Target);
  10463. S.mix(io, {
  10464. isLocal:isLocal,
  10465. setupConfig:function(setting) {
  10466. S.mix(defaultConfig, setting, undefined, undefined, true);
  10467. },
  10468. setupTransport:function(name, fn) {
  10469. transports[name] = fn;
  10470. },
  10471. getTransport:function(name) {
  10472. return transports[name];
  10473. },
  10474. getConfig:function() {
  10475. return defaultConfig;
  10476. }
  10477. });
  10478. return io;
  10479. },
  10480. {
  10481. requires:["json","event","./xhrobject"]
  10482. });
  10483. /**
  10484. * 借鉴 jquery,优化减少闭包使用
  10485. *
  10486. * TODO:
  10487. * ifModified mode 是否需要?
  10488. * 优点:
  10489. * 不依赖浏览器处理,ajax 请求浏览不会自动加 If-Modified-Since If-None-Match ??
  10490. * 缺点:
  10491. * 内存占用
  10492. **/
  10493. /**
  10494. * base for xhr and subdomain
  10495. * @author yiminghe@gmail.com
  10496. */
  10497. KISSY.add("ajax/xhrbase", function(S, io) {
  10498. var OK_CODE = 200,
  10499. win = window,
  10500. // http://msdn.microsoft.com/en-us/library/cc288060(v=vs.85).aspx
  10501. _XDomainRequest = win['XDomainRequest'],
  10502. NO_CONTENT_CODE = 204,
  10503. NOT_FOUND_CODE = 404,
  10504. NO_CONTENT_CODE2 = 1223,
  10505. XhrBase = {
  10506. proto:{}
  10507. };
  10508. function createStandardXHR(_, refWin) {
  10509. try {
  10510. return new (refWin || win)['XMLHttpRequest']();
  10511. } catch(e) {
  10512. //S.log("createStandardXHR error");
  10513. }
  10514. return undefined;
  10515. }
  10516. function createActiveXHR(_, refWin) {
  10517. try {
  10518. return new (refWin || win)['ActiveXObject']("Microsoft.XMLHTTP");
  10519. } catch(e) {
  10520. S.log("createActiveXHR error");
  10521. }
  10522. return undefined;
  10523. }
  10524. XhrBase.xhr = win.ActiveXObject ? function(crossDomain, refWin) {
  10525. if (crossDomain && _XDomainRequest) {
  10526. return new _XDomainRequest();
  10527. }
  10528. // ie7 XMLHttpRequest 不能访问本地文件
  10529. return !io.isLocal && createStandardXHR(crossDomain, refWin) || createActiveXHR(crossDomain, refWin);
  10530. } : createStandardXHR;
  10531. function isInstanceOfXDomainRequest(xhr) {
  10532. return _XDomainRequest && (xhr instanceof _XDomainRequest);
  10533. }
  10534. S.mix(XhrBase.proto, {
  10535. sendInternal:function() {
  10536. var self = this,
  10537. xhrObj = self.xhrObj,
  10538. c = xhrObj.config;
  10539. var xhr = self.xhr,
  10540. xhrFields,
  10541. i;
  10542. if (c['username']) {
  10543. xhr.open(c.type, c.url, c.async, c['username'], c.password)
  10544. } else {
  10545. xhr.open(c.type, c.url, c.async);
  10546. }
  10547. if (xhrFields = c['xhrFields']) {
  10548. for (i in xhrFields) {
  10549. xhr[ i ] = xhrFields[ i ];
  10550. }
  10551. }
  10552. // Override mime type if supported
  10553. if (xhrObj.mimeType && xhr.overrideMimeType) {
  10554. xhr.overrideMimeType(xhrObj.mimeType);
  10555. }
  10556. // yui3 and jquery both have
  10557. if (!c.crossDomain && !xhrObj.requestHeaders["X-Requested-With"]) {
  10558. xhrObj.requestHeaders[ "X-Requested-With" ] = "XMLHttpRequest";
  10559. }
  10560. try {
  10561. // 跨域时,不能设,否则请求变成
  10562. // OPTIONS /xhr/r.php HTTP/1.1
  10563. if (!c.crossDomain) {
  10564. for (i in xhrObj.requestHeaders) {
  10565. xhr.setRequestHeader(i, xhrObj.requestHeaders[ i ]);
  10566. }
  10567. }
  10568. } catch(e) {
  10569. S.log("setRequestHeader in xhr error : ");
  10570. S.log(e);
  10571. }
  10572. xhr.send(c.hasContent && c.data || null);
  10573. if (!c.async || xhr.readyState == 4) {
  10574. self._callback();
  10575. } else {
  10576. // _XDomainRequest 单独的回调机制
  10577. if (isInstanceOfXDomainRequest(xhr)) {
  10578. xhr.onload = function() {
  10579. xhr.readyState = 4;
  10580. xhr.status = 200;
  10581. self._callback();
  10582. };
  10583. xhr.onerror = function() {
  10584. xhr.readyState = 4;
  10585. xhr.status = 500;
  10586. self._callback();
  10587. };
  10588. } else {
  10589. xhr.onreadystatechange = function() {
  10590. self._callback();
  10591. };
  10592. }
  10593. }
  10594. },
  10595. // 由 xhrObj.abort 调用,自己不可以调用 xhrObj.abort
  10596. abort:function() {
  10597. this._callback(0, 1);
  10598. },
  10599. _callback:function(event, abort) {
  10600. // Firefox throws exceptions when accessing properties
  10601. // of an xhr when a network error occured
  10602. // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
  10603. try {
  10604. var self = this,
  10605. xhr = self.xhr,
  10606. xhrObj = self.xhrObj,
  10607. c = xhrObj.config;
  10608. //abort or complete
  10609. if (abort || xhr.readyState == 4) {
  10610. // ie6 ActiveObject 设置不恰当属性导致出错
  10611. if (isInstanceOfXDomainRequest(xhr)) {
  10612. xhr.onerror = S.noop;
  10613. xhr.onload = S.noop;
  10614. } else {
  10615. // ie6 ActiveObject 只能设置,不能读取这个属性,否则出错!
  10616. xhr.onreadystatechange = S.noop;
  10617. }
  10618. if (abort) {
  10619. // 完成以后 abort 不要调用
  10620. if (xhr.readyState !== 4) {
  10621. xhr.abort();
  10622. }
  10623. } else {
  10624. var status = xhr.status;
  10625. // _XDomainRequest 不能获取响应头
  10626. if (!isInstanceOfXDomainRequest(xhr)) {
  10627. xhrObj.responseHeadersString = xhr.getAllResponseHeaders();
  10628. }
  10629. var xml = xhr.responseXML;
  10630. // Construct response list
  10631. if (xml && xml.documentElement /* #4958 */) {
  10632. xhrObj.responseXML = xml;
  10633. }
  10634. xhrObj.responseText = xhr.responseText;
  10635. // Firefox throws an exception when accessing
  10636. // statusText for faulty cross-domain requests
  10637. try {
  10638. var statusText = xhr.statusText;
  10639. } catch(e) {
  10640. S.log("xhr statustext error : ");
  10641. S.log(e);
  10642. // We normalize with Webkit giving an empty statusText
  10643. statusText = "";
  10644. }
  10645. // Filter status for non standard behaviors
  10646. // If the request is local and we have data: assume a success
  10647. // (success with no data won't get notified, that's the best we
  10648. // can do given current implementations)
  10649. if (!status && io.isLocal && !c.crossDomain) {
  10650. status = xhrObj.responseText ? OK_CODE : NOT_FOUND_CODE;
  10651. // IE - #1450: sometimes returns 1223 when it should be 204
  10652. } else if (status === NO_CONTENT_CODE2) {
  10653. status = NO_CONTENT_CODE;
  10654. }
  10655. xhrObj.callback(status, statusText);
  10656. }
  10657. }
  10658. } catch (firefoxAccessException) {
  10659. xhr.onreadystatechange = S.noop;
  10660. if (!abort) {
  10661. xhrObj.callback(-1, firefoxAccessException);
  10662. }
  10663. }
  10664. }
  10665. });
  10666. return XhrBase;
  10667. }, {
  10668. requires:['./base']
  10669. });
  10670. /**
  10671. * solve io between sub domains using proxy page
  10672. * @author yiminghe@gmail.com
  10673. */
  10674. KISSY.add("ajax/subdomain", function(S, XhrBase, Event, DOM) {
  10675. var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
  10676. PROXY_PAGE = "/sub_domain_proxy.html",
  10677. doc = document,
  10678. iframeMap = {
  10679. // hostname:{iframe: , ready:}
  10680. };
  10681. function SubDomain(xhrObj) {
  10682. var self = this,
  10683. c = xhrObj.config;
  10684. self.xhrObj = xhrObj;
  10685. var m = c.url.match(rurl);
  10686. self.__hostname = m[2];
  10687. self.__protocol = m[1];
  10688. c.crossDomain = false;
  10689. }
  10690. S.augment(SubDomain, XhrBase.proto, {
  10691. send:function() {
  10692. var self = this,
  10693. c = self.xhrObj.config,
  10694. hostname = self.__hostname,
  10695. iframe,
  10696. iframeDesc = iframeMap[hostname];
  10697. var proxy = PROXY_PAGE;
  10698. if (c['xdr'] && c['xdr']['subDomain'] && c['xdr']['subDomain'].proxy) {
  10699. proxy = c['xdr']['subDomain'].proxy;
  10700. }
  10701. if (iframeDesc && iframeDesc.ready) {
  10702. self.xhr = XhrBase.xhr(0, iframeDesc.iframe.contentWindow);
  10703. if (self.xhr) {
  10704. self.sendInternal();
  10705. } else {
  10706. S.error("document.domain not set correctly!");
  10707. }
  10708. return;
  10709. }
  10710. if (!iframeDesc) {
  10711. iframeDesc = iframeMap[hostname] = {};
  10712. iframe = iframeDesc.iframe = document.createElement("iframe");
  10713. DOM.css(iframe, {
  10714. position:'absolute',
  10715. left:'-9999px',
  10716. top:'-9999px'
  10717. });
  10718. DOM.prepend(iframe, doc.body || doc.documentElement);
  10719. iframe.src = self.__protocol + "//" + hostname + proxy;
  10720. } else {
  10721. iframe = iframeDesc.iframe;
  10722. }
  10723. Event.on(iframe, "load", _onLoad, self);
  10724. }
  10725. });
  10726. function _onLoad() {
  10727. var self = this,
  10728. hostname = self.__hostname,
  10729. iframeDesc = iframeMap[hostname];
  10730. iframeDesc.ready = 1;
  10731. Event.detach(iframeDesc.iframe, "load", _onLoad, self);
  10732. self.send();
  10733. }
  10734. return SubDomain;
  10735. }, {
  10736. requires:['./xhrbase','event','dom']
  10737. });
  10738. /**
  10739. * use flash to accomplish cross domain request , usage scenario ? why not jsonp ?
  10740. * @author yiminghe@gmail.com
  10741. */
  10742. KISSY.add("ajax/xdr", function(S, io, DOM) {
  10743. var // current running request instances
  10744. maps = {},
  10745. ID = "io_swf",
  10746. // flash transporter
  10747. flash,
  10748. doc = document,
  10749. // whether create the flash transporter
  10750. init = false;
  10751. // create the flash transporter
  10752. function _swf(uri, _, uid) {
  10753. if (init) {
  10754. return;
  10755. }
  10756. init = true;
  10757. var o = '<object id="' + ID +
  10758. '" type="application/x-shockwave-flash" data="' +
  10759. uri + '" width="0" height="0">' +
  10760. '<param name="movie" value="' +
  10761. uri + '" />' +
  10762. '<param name="FlashVars" value="yid=' +
  10763. _ + '&uid=' +
  10764. uid +
  10765. '&host=KISSY.io" />' +
  10766. '<param name="allowScriptAccess" value="always" />' +
  10767. '</object>',
  10768. c = doc.createElement('div');
  10769. DOM.prepend(c, doc.body || doc.documentElement);
  10770. c.innerHTML = o;
  10771. }
  10772. function XdrTransport(xhrObj) {
  10773. S.log("use flash xdr");
  10774. this.xhrObj = xhrObj;
  10775. }
  10776. S.augment(XdrTransport, {
  10777. // rewrite send to support flash xdr
  10778. send:function() {
  10779. var self = this,
  10780. xhrObj = self.xhrObj,
  10781. c = xhrObj.config;
  10782. var xdr = c['xdr'] || {};
  10783. // 不提供则使用 cdn 默认的 flash
  10784. _swf(xdr.src || (S.Config.base + "ajax/io.swf"), 1, 1);
  10785. // 简便起见,用轮训
  10786. if (!flash) {
  10787. // S.log("detect xdr flash");
  10788. setTimeout(function() {
  10789. self.send();
  10790. }, 200);
  10791. return;
  10792. }
  10793. self._uid = S.guid();
  10794. maps[self._uid] = self;
  10795. // ie67 send 出错?
  10796. flash.send(c.url, {
  10797. id:self._uid,
  10798. uid:self._uid,
  10799. method:c.type,
  10800. data:c.hasContent && c.data || {}
  10801. });
  10802. },
  10803. abort:function() {
  10804. flash.abort(this._uid);
  10805. },
  10806. _xdrResponse:function(e, o) {
  10807. // S.log(e);
  10808. var self = this,
  10809. ret,
  10810. xhrObj = self.xhrObj;
  10811. // need decodeURI to get real value from flash returned value
  10812. xhrObj.responseText = decodeURI(o.c.responseText);
  10813. switch (e) {
  10814. case 'success':
  10815. ret = { status: 200, statusText: "success" };
  10816. delete maps[o.id];
  10817. break;
  10818. case 'abort':
  10819. delete maps[o.id];
  10820. break;
  10821. case 'timeout':
  10822. case 'transport error':
  10823. case 'failure':
  10824. delete maps[o.id];
  10825. ret = { status: 500, statusText: e };
  10826. break;
  10827. }
  10828. if (ret) {
  10829. xhrObj.callback(ret.status, ret.statusText);
  10830. }
  10831. }
  10832. });
  10833. /*called by flash*/
  10834. io['applyTo'] = function(_, cmd, args) {
  10835. // S.log(cmd + " execute");
  10836. var cmds = cmd.split("."),
  10837. func = S;
  10838. S.each(cmds, function(c) {
  10839. func = func[c];
  10840. });
  10841. func.apply(null, args);
  10842. };
  10843. // when flash is loaded
  10844. io['xdrReady'] = function() {
  10845. flash = doc.getElementById(ID);
  10846. };
  10847. /**
  10848. * when response is returned from server
  10849. * @param e response status
  10850. * @param o internal data
  10851. * @param c internal data
  10852. */
  10853. io['xdrResponse'] = function(e, o, c) {
  10854. var xhr = maps[o.uid];
  10855. xhr && xhr._xdrResponse(e, o, c);
  10856. };
  10857. // export io for flash to call
  10858. S.io = io;
  10859. return XdrTransport;
  10860. }, {
  10861. requires:["./base",'dom']
  10862. });
  10863. /**
  10864. * ajax xhr transport class , route subdomain , xdr
  10865. * @author yiminghe@gmail.com
  10866. */
  10867. KISSY.add("ajax/xhr", function(S, io, XhrBase, SubDomain, XdrTransport) {
  10868. var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/;
  10869. var _XDomainRequest = window['XDomainRequest'];
  10870. var detectXhr = XhrBase.xhr();
  10871. if (detectXhr) {
  10872. // slice last two pars
  10873. // xx.taobao.com => taobao.com
  10874. function getMainDomain(host) {
  10875. var t = host.split('.');
  10876. if (t.length < 2) {
  10877. return t.join(".");
  10878. } else {
  10879. return t.reverse().slice(0, 2).reverse().join('.');
  10880. }
  10881. }
  10882. function XhrTransport(xhrObj) {
  10883. var c = xhrObj.config,
  10884. xdrCfg = c['xdr'] || {};
  10885. if (c.crossDomain) {
  10886. var parts = c.url.match(rurl);
  10887. // 跨子域
  10888. if (getMainDomain(location.hostname) == getMainDomain(parts[2])) {
  10889. return new SubDomain(xhrObj);
  10890. }
  10891. /**
  10892. * ie>7 强制使用 flash xdr
  10893. */
  10894. if (!("withCredentials" in detectXhr) &&
  10895. (String(xdrCfg.use) === "flash" || !_XDomainRequest)) {
  10896. return new XdrTransport(xhrObj);
  10897. }
  10898. }
  10899. this.xhrObj = xhrObj;
  10900. return undefined;
  10901. }
  10902. S.augment(XhrTransport, XhrBase.proto, {
  10903. send:function() {
  10904. var self = this,
  10905. xhrObj = self.xhrObj,
  10906. c = xhrObj.config;
  10907. self.xhr = XhrBase.xhr(c.crossDomain);
  10908. self.sendInternal();
  10909. }
  10910. });
  10911. io.setupTransport("*", XhrTransport);
  10912. }
  10913. return io;
  10914. }, {
  10915. requires:["./base",'./xhrbase','./subdomain',"./xdr"]
  10916. });
  10917. /**
  10918. * 借鉴 jquery,优化使用原型替代闭包
  10919. **/
  10920. /**
  10921. * script transport for kissy io
  10922. * @description: modified version of S.getScript , add abort ability
  10923. * @author yiminghe@gmail.com
  10924. */
  10925. KISSY.add("ajax/script", function(S, io) {
  10926. var doc = document;
  10927. var OK_CODE = 200,ERROR_CODE = 500;
  10928. io.setupConfig({
  10929. accepts:{
  10930. script:"text/javascript, " +
  10931. "application/javascript, " +
  10932. "application/ecmascript, " +
  10933. "application/x-ecmascript"
  10934. },
  10935. contents:{
  10936. script:/javascript|ecmascript/
  10937. },
  10938. converters:{
  10939. text:{
  10940. // 如果以 xhr+eval 需要下面的,
  10941. // 否则直接 script node 不需要,引擎自己执行了,
  10942. // 不需要手动 eval
  10943. script:function(text) {
  10944. S.globalEval(text);
  10945. return text;
  10946. }
  10947. }
  10948. }
  10949. });
  10950. function ScriptTransport(xhrObj) {
  10951. // 优先使用 xhr+eval 来执行脚本, ie 下可以探测到(更多)失败状态
  10952. if (!xhrObj.config.crossDomain &&
  10953. !xhrObj.config['forceScript']) {
  10954. return new (io.getTransport("*"))(xhrObj);
  10955. }
  10956. this.xhrObj = xhrObj;
  10957. return 0;
  10958. }
  10959. S.augment(ScriptTransport, {
  10960. send:function() {
  10961. var self = this,
  10962. script,
  10963. xhrObj = this.xhrObj,
  10964. c = xhrObj.config,
  10965. head = doc['head'] ||
  10966. doc.getElementsByTagName("head")[0] ||
  10967. doc.documentElement;
  10968. self.head = head;
  10969. script = doc.createElement("script");
  10970. self.script = script;
  10971. script.async = "async";
  10972. if (c['scriptCharset']) {
  10973. script.charset = c['scriptCharset'];
  10974. }
  10975. script.src = c.url;
  10976. script.onerror =
  10977. script.onload =
  10978. script.onreadystatechange = function(e) {
  10979. e = e || window.event;
  10980. // firefox onerror 没有 type ?!
  10981. self._callback((e.type || "error").toLowerCase());
  10982. };
  10983. head.insertBefore(script, head.firstChild);
  10984. },
  10985. _callback:function(event, abort) {
  10986. var script = this.script,
  10987. xhrObj = this.xhrObj,
  10988. head = this.head;
  10989. // 防止重复调用,成功后 abort
  10990. if (!script) {
  10991. return;
  10992. }
  10993. if (abort ||
  10994. !script.readyState ||
  10995. /loaded|complete/.test(script.readyState)
  10996. || event == "error"
  10997. ) {
  10998. script['onerror'] = script.onload = script.onreadystatechange = null;
  10999. // Remove the script
  11000. if (head && script.parentNode) {
  11001. // ie 报错载入无效 js
  11002. // 怎么 abort ??
  11003. // script.src = "#";
  11004. head.removeChild(script);
  11005. }
  11006. this.script = undefined;
  11007. this.head = undefined;
  11008. // Callback if not abort
  11009. if (!abort && event != "error") {
  11010. xhrObj.callback(OK_CODE, "success");
  11011. }
  11012. // 非 ie<9 可以判断出来
  11013. else if (event == "error") {
  11014. xhrObj.callback(ERROR_CODE, "scripterror");
  11015. }
  11016. }
  11017. },
  11018. abort:function() {
  11019. this._callback(0, 1);
  11020. }
  11021. });
  11022. io.setupTransport("script", ScriptTransport);
  11023. return io;
  11024. }, {
  11025. requires:['./base','./xhr']
  11026. });
  11027. /**
  11028. * jsonp transport based on script transport
  11029. * @author yiminghe@gmail.com
  11030. */
  11031. KISSY.add("ajax/jsonp", function(S, io) {
  11032. io.setupConfig({
  11033. jsonp:"callback",
  11034. jsonpCallback:function() {
  11035. //不使用 now() ,极端情况下可能重复
  11036. return S.guid("jsonp");
  11037. }
  11038. });
  11039. io.on("start", function(e) {
  11040. var xhr = e.xhr,c = xhr.config;
  11041. if (c.dataType[0] == "jsonp") {
  11042. var response,
  11043. cJsonpCallback = c.jsonpCallback,
  11044. jsonpCallback = S.isFunction(cJsonpCallback) ?
  11045. cJsonpCallback() :
  11046. cJsonpCallback,
  11047. previous = window[ jsonpCallback ];
  11048. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + c.jsonp + "=" + jsonpCallback;
  11049. // build temporary JSONP function
  11050. window[jsonpCallback] = function(r) {
  11051. // 使用数组,区别:故意调用了 jsonpCallback(undefined) 与 根本没有调用
  11052. // jsonp 返回了数组
  11053. if (arguments.length > 1) {
  11054. r = S.makeArray(arguments);
  11055. }
  11056. response = [r];
  11057. };
  11058. // cleanup whether success or failure
  11059. xhr.on("complete", function() {
  11060. window[ jsonpCallback ] = previous;
  11061. if (previous === undefined) {
  11062. try {
  11063. delete window[ jsonpCallback ];
  11064. } catch(e) {
  11065. //S.log("delete window variable error : ");
  11066. //S.log(e);
  11067. }
  11068. } else if (response) {
  11069. // after io success handler called
  11070. // then call original existed jsonpcallback
  11071. previous(response[0]);
  11072. }
  11073. });
  11074. xhr.converters = xhr.converters || {};
  11075. xhr.converters.script = xhr.converters.script || {};
  11076. // script -> jsonp ,jsonp need to see json not as script
  11077. xhr.converters.script.json = function() {
  11078. if (!response) {
  11079. S.error(" not call jsonpCallback : " + jsonpCallback)
  11080. }
  11081. return response[0];
  11082. };
  11083. c.dataType.length = 2;
  11084. // 利用 script transport 发送 script 请求
  11085. c.dataType[0] = 'script';
  11086. c.dataType[1] = 'json';
  11087. }
  11088. });
  11089. return io;
  11090. }, {
  11091. requires:['./base']
  11092. });
  11093. KISSY.add("ajax/form", function(S, io, DOM, FormSerializer) {
  11094. io.on("start", function(e) {
  11095. var xhr = e.xhr,
  11096. c = xhr.config;
  11097. // serialize form if needed
  11098. if (c.form) {
  11099. var form = DOM.get(c.form),
  11100. enctype = form['encoding'] || form.enctype;
  11101. // 上传有其他方法
  11102. if (enctype.toLowerCase() != "multipart/form-data") {
  11103. // when get need encode
  11104. var formParam = FormSerializer.serialize(form);
  11105. if (formParam) {
  11106. if (c.hasContent) {
  11107. // post 加到 data 中
  11108. c.data = c.data || "";
  11109. if (c.data) {
  11110. c.data += "&";
  11111. }
  11112. c.data += formParam;
  11113. } else {
  11114. // get 直接加到 url
  11115. c.url += ( /\?/.test(c.url) ? "&" : "?" ) + formParam;
  11116. }
  11117. }
  11118. } else {
  11119. var d = c.dataType[0];
  11120. if (d == "*") {
  11121. d = "text";
  11122. }
  11123. c.dataType.length = 2;
  11124. c.dataType[0] = "iframe";
  11125. c.dataType[1] = d;
  11126. }
  11127. }
  11128. });
  11129. return io;
  11130. }, {
  11131. requires:['./base',"dom","./form-serializer"]
  11132. });
  11133. /**
  11134. * non-refresh upload file with form by iframe
  11135. * @author yiminghe@gmail.com
  11136. */
  11137. KISSY.add("ajax/iframe-upload", function(S, DOM, Event, io) {
  11138. var doc = document;
  11139. var OK_CODE = 200,ERROR_CODE = 500,BREATH_INTERVAL = 30;
  11140. // iframe 内的内容就是 body.innerText
  11141. io.setupConfig({
  11142. converters:{
  11143. // iframe 到其他类型的转化和 text 一样
  11144. iframe:io.getConfig().converters.text,
  11145. text:{
  11146. iframe:function(text) {
  11147. return text;
  11148. }
  11149. }}});
  11150. function createIframe(xhr) {
  11151. var id = S.guid("ajax-iframe");
  11152. xhr.iframe = DOM.create("<iframe " +
  11153. " id='" + id + "'" +
  11154. // need name for target of form
  11155. " name='" + id + "'" +
  11156. " style='position:absolute;left:-9999px;top:-9999px;'/>");
  11157. xhr.iframeId = id;
  11158. DOM.prepend(xhr.iframe, doc.body || doc.documentElement);
  11159. }
  11160. function addDataToForm(data, form, serializeArray) {
  11161. data = S.unparam(data);
  11162. var ret = [];
  11163. for (var d in data) {
  11164. var isArray = S.isArray(data[d]),
  11165. vs = S.makeArray(data[d]);
  11166. // 数组和原生一样对待,创建多个同名输入域
  11167. for (var i = 0; i < vs.length; i++) {
  11168. var e = doc.createElement("input");
  11169. e.type = 'hidden';
  11170. e.name = d + (isArray && serializeArray ? "[]" : "");
  11171. e.value = vs[i];
  11172. DOM.append(e, form);
  11173. ret.push(e);
  11174. }
  11175. }
  11176. return ret;
  11177. }
  11178. function removeFieldsFromData(fields) {
  11179. DOM.remove(fields);
  11180. }
  11181. function IframeTransport(xhr) {
  11182. this.xhr = xhr;
  11183. }
  11184. S.augment(IframeTransport, {
  11185. send:function() {
  11186. //debugger
  11187. var xhr = this.xhr,
  11188. c = xhr.config,
  11189. fields,
  11190. form = DOM.get(c.form);
  11191. this.attrs = {
  11192. target:DOM.attr(form, "target") || "",
  11193. action:DOM.attr(form, "action") || ""
  11194. };
  11195. this.form = form;
  11196. createIframe(xhr);
  11197. // set target to iframe to avoid main page refresh
  11198. DOM.attr(form, {"target": xhr.iframeId,"action": c.url});
  11199. if (c.data) {
  11200. fields = addDataToForm(c.data, form, c.serializeArray);
  11201. }
  11202. this.fields = fields;
  11203. var iframe = xhr.iframe;
  11204. Event.on(iframe, "load error", this._callback, this);
  11205. form.submit();
  11206. },
  11207. _callback:function(event
  11208. //, abort
  11209. ) {
  11210. //debugger
  11211. var form = this.form,
  11212. xhr = this.xhr,
  11213. eventType = event.type,
  11214. iframe = xhr.iframe;
  11215. // 防止重复调用 , 成功后 abort
  11216. if (!iframe) {
  11217. return;
  11218. }
  11219. DOM.attr(form, this.attrs);
  11220. if (eventType == "load") {
  11221. var iframeDoc = iframe.contentWindow.document;
  11222. xhr.responseXML = iframeDoc;
  11223. xhr.responseText = DOM.text(iframeDoc.body);
  11224. xhr.callback(OK_CODE, "success");
  11225. } else if (eventType == 'error') {
  11226. xhr.callback(ERROR_CODE, "error");
  11227. }
  11228. removeFieldsFromData(this.fields);
  11229. Event.detach(iframe);
  11230. setTimeout(function() {
  11231. // firefox will keep loading if not settimeout
  11232. DOM.remove(iframe);
  11233. }, BREATH_INTERVAL);
  11234. // nullify to prevent memory leak?
  11235. xhr.iframe = null;
  11236. },
  11237. abort:function() {
  11238. this._callback(0, 1);
  11239. }
  11240. });
  11241. io.setupTransport("iframe", IframeTransport);
  11242. return io;
  11243. }, {
  11244. requires:["dom","event","./base"]
  11245. });
  11246. KISSY.add("ajax", function(S, serializer, io) {
  11247. var undef = undefined;
  11248. // some shortcut
  11249. S.mix(io, {
  11250. /**
  11251. * form 序列化
  11252. * @param formElement {HTMLFormElement} 将要序列化的 form 元素
  11253. */
  11254. serialize:serializer.serialize,
  11255. get: function(url, data, callback, dataType, _t) {
  11256. // data 参数可省略
  11257. if (S.isFunction(data)) {
  11258. dataType = callback;
  11259. callback = data;
  11260. data = undef;
  11261. }
  11262. return io({
  11263. type: _t || "get",
  11264. url: url,
  11265. data: data,
  11266. success: callback,
  11267. dataType: dataType
  11268. });
  11269. },
  11270. post: function(url, data, callback, dataType) {
  11271. if (S.isFunction(data)) {
  11272. dataType = callback;
  11273. callback = data;
  11274. data = undef;
  11275. }
  11276. return io.get(url, data, callback, dataType, "post");
  11277. },
  11278. jsonp: function(url, data, callback) {
  11279. if (S.isFunction(data)) {
  11280. callback = data;
  11281. data = undef;
  11282. }
  11283. return io.get(url, data, callback, "jsonp");
  11284. },
  11285. // 和 S.getScript 保持一致
  11286. // 更好的 getScript 可以用
  11287. /*
  11288. io({
  11289. dataType:'script'
  11290. });
  11291. */
  11292. getScript:S.getScript,
  11293. getJSON: function(url, data, callback) {
  11294. if (S.isFunction(data)) {
  11295. callback = data;
  11296. data = undef;
  11297. }
  11298. return io.get(url, data, callback, "json");
  11299. },
  11300. upload:function(url, form, data, callback, dataType) {
  11301. if (S.isFunction(data)) {
  11302. dataType = callback;
  11303. callback = data;
  11304. data = undef;
  11305. }
  11306. return io({
  11307. url:url,
  11308. type:'post',
  11309. dataType:dataType,
  11310. form:form,
  11311. data:data,
  11312. success:callback
  11313. });
  11314. }
  11315. });
  11316. return io;
  11317. }, {
  11318. requires:[
  11319. "ajax/form-serializer",
  11320. "ajax/base",
  11321. "ajax/xhrobject",
  11322. "ajax/xhr",
  11323. "ajax/script",
  11324. "ajax/jsonp",
  11325. "ajax/form",
  11326. "ajax/iframe-upload"]
  11327. });
  11328. /**
  11329. * @module Attribute
  11330. * @author yiminghe@gmail.com, lifesinger@gmail.com
  11331. */
  11332. KISSY.add('base/attribute', function(S, undef) {
  11333. // atomic flag
  11334. Attribute.INVALID = {};
  11335. var INVALID = Attribute.INVALID;
  11336. /**
  11337. *
  11338. * @param host
  11339. * @param method
  11340. * @return method if fn or host[method]
  11341. */
  11342. function normalFn(host, method) {
  11343. if (S.isString(method)) {
  11344. return host[method];
  11345. }
  11346. return method;
  11347. }
  11348. /**
  11349. * fire attribute value change
  11350. */
  11351. function __fireAttrChange(self, when, name, prevVal, newVal, subAttrName, attrName) {
  11352. attrName = attrName || name;
  11353. return self.fire(when + capitalFirst(name) + 'Change', {
  11354. attrName: attrName,
  11355. subAttrName:subAttrName,
  11356. prevVal: prevVal,
  11357. newVal: newVal
  11358. });
  11359. }
  11360. /**
  11361. *
  11362. * @param obj
  11363. * @param name
  11364. * @param create
  11365. * @return non-empty property value of obj
  11366. */
  11367. function ensureNonEmpty(obj, name, create) {
  11368. var ret = obj[name] || {};
  11369. if (create) {
  11370. obj[name] = ret;
  11371. }
  11372. return ret;
  11373. }
  11374. /**
  11375. *
  11376. * @param self
  11377. * @return non-empty attr config holder
  11378. */
  11379. function getAttrs(self) {
  11380. /**
  11381. * attribute meta information
  11382. {
  11383. attrName: {
  11384. getter: function,
  11385. setter: function,
  11386. // 注意:只能是普通对象以及系统内置类型,而不能是 new Xx(),否则用 valueFn 替代
  11387. value: v, // default value
  11388. valueFn: function
  11389. }
  11390. }
  11391. */
  11392. return ensureNonEmpty(self, "__attrs", true);
  11393. }
  11394. /**
  11395. *
  11396. * @param self
  11397. * @return non-empty attr value holder
  11398. */
  11399. function getAttrVals(self) {
  11400. /**
  11401. * attribute value
  11402. {
  11403. attrName: attrVal
  11404. }
  11405. */
  11406. return ensureNonEmpty(self, "__attrVals", true);
  11407. }
  11408. /**
  11409. * o, [x,y,z] => o[x][y][z]
  11410. * @param o
  11411. * @param path
  11412. */
  11413. function getValueByPath(o, path) {
  11414. for (var i = 0,len = path.length;
  11415. o != undef && i < len;
  11416. i++) {
  11417. o = o[path[i]];
  11418. }
  11419. return o;
  11420. }
  11421. /**
  11422. * o, [x,y,z], val => o[x][y][z]=val
  11423. * @param o
  11424. * @param path
  11425. * @param val
  11426. */
  11427. function setValueByPath(o, path, val) {
  11428. var rlen = path.length - 1,
  11429. s = o;
  11430. if (rlen >= 0) {
  11431. for (var i = 0; i < rlen; i++) {
  11432. o = o[path[i]];
  11433. }
  11434. if (o != undef) {
  11435. o[path[i]] = val;
  11436. } else {
  11437. s = undef;
  11438. }
  11439. }
  11440. return s;
  11441. }
  11442. function setInternal(self, name, value, opts, attrs) {
  11443. var ret;
  11444. opts = opts || {};
  11445. var dot = ".",
  11446. path,
  11447. subVal,
  11448. prevVal,
  11449. fullName = name;
  11450. if (name.indexOf(dot) !== -1) {
  11451. path = name.split(dot);
  11452. name = path.shift();
  11453. }
  11454. prevVal = self.get(name);
  11455. if (path) {
  11456. subVal = getValueByPath(prevVal, path);
  11457. }
  11458. // if no change, just return
  11459. if (!path && prevVal === value) {
  11460. return undefined;
  11461. } else if (path && subVal === value) {
  11462. return undefined;
  11463. }
  11464. if (path) {
  11465. var tmp = S.clone(prevVal);
  11466. setValueByPath(tmp, path, value);
  11467. value = tmp;
  11468. }
  11469. // check before event
  11470. if (!opts['silent']) {
  11471. if (false === __fireAttrChange(self, 'before', name, prevVal, value, fullName)) {
  11472. return false;
  11473. }
  11474. }
  11475. // set it
  11476. ret = self.__set(name, value);
  11477. if (ret === false) {
  11478. return ret;
  11479. }
  11480. // fire after event
  11481. if (!opts['silent']) {
  11482. value = getAttrVals(self)[name];
  11483. __fireAttrChange(self, 'after', name, prevVal, value, fullName);
  11484. if (!attrs) {
  11485. __fireAttrChange(self,
  11486. '', '*',
  11487. [prevVal], [value],
  11488. [fullName], [name]);
  11489. } else {
  11490. attrs.push({
  11491. prevVal:prevVal,
  11492. newVal:value,
  11493. attrName:name,
  11494. subAttrName:fullName
  11495. });
  11496. }
  11497. }
  11498. return self;
  11499. }
  11500. /**
  11501. * 提供属性管理机制
  11502. * @name Attribute
  11503. * @class
  11504. */
  11505. function Attribute() {
  11506. }
  11507. S.augment(Attribute, {
  11508. /**
  11509. * @return un-cloned attr config collections
  11510. */
  11511. getAttrs: function() {
  11512. return getAttrs(this);
  11513. },
  11514. /**
  11515. * @return un-cloned attr value collections
  11516. */
  11517. getAttrVals:function() {
  11518. var self = this,
  11519. o = {},
  11520. a,
  11521. attrs = getAttrs(self);
  11522. for (a in attrs) {
  11523. o[a] = self.get(a);
  11524. }
  11525. return o;
  11526. },
  11527. /**
  11528. * Adds an attribute with the provided configuration to the host object.
  11529. * @param {String} name attrName
  11530. * @param {Object} attrConfig The config supports the following properties:
  11531. * {
  11532. * value: 'the default value', // 最好不要使用自定义类生成的对象,这时使用 valueFn
  11533. * valueFn: function //
  11534. * setter: function
  11535. * getter: function
  11536. * }
  11537. * @param {boolean} override whether override existing attribute config ,default true
  11538. */
  11539. addAttr: function(name, attrConfig, override) {
  11540. var self = this,
  11541. attrs = getAttrs(self),
  11542. cfg = S.clone(attrConfig);
  11543. if (!attrs[name]) {
  11544. attrs[name] = cfg;
  11545. } else {
  11546. S.mix(attrs[name], cfg, override);
  11547. }
  11548. return self;
  11549. },
  11550. /**
  11551. * Configures a group of attributes, and sets initial values.
  11552. * @param {Object} attrConfigs An object with attribute name/configuration pairs.
  11553. * @param {Object} initialValues user defined initial values
  11554. */
  11555. addAttrs: function(attrConfigs, initialValues) {
  11556. var self = this;
  11557. S.each(attrConfigs, function(attrConfig, name) {
  11558. self.addAttr(name, attrConfig);
  11559. });
  11560. if (initialValues) {
  11561. self.set(initialValues);
  11562. }
  11563. return self;
  11564. },
  11565. /**
  11566. * Checks if the given attribute has been added to the host.
  11567. */
  11568. hasAttr: function(name) {
  11569. return name && getAttrs(this).hasOwnProperty(name);
  11570. },
  11571. /**
  11572. * Removes an attribute from the host object.
  11573. */
  11574. removeAttr: function(name) {
  11575. var self = this;
  11576. if (self.hasAttr(name)) {
  11577. delete getAttrs(self)[name];
  11578. delete getAttrVals(self)[name];
  11579. }
  11580. return self;
  11581. },
  11582. /**
  11583. * Sets the value of an attribute.
  11584. */
  11585. set: function(name, value, opts) {
  11586. var ret,self = this;
  11587. if (S.isPlainObject(name)) {
  11588. var all = name;
  11589. name = 0;
  11590. ret = true;
  11591. opts = value;
  11592. var attrs = [];
  11593. for (name in all) {
  11594. ret = setInternal(self, name, all[name], opts, attrs);
  11595. if (ret === false) {
  11596. break;
  11597. }
  11598. }
  11599. var attrNames = [],
  11600. prevVals = [],
  11601. newVals = [],
  11602. subAttrNames = [];
  11603. S.each(attrs, function(attr) {
  11604. prevVals.push(attr.prevVal);
  11605. newVals.push(attr.newVal);
  11606. attrNames.push(attr.attrName);
  11607. subAttrNames.push(attr.subAttrName);
  11608. });
  11609. if (attrNames.length) {
  11610. __fireAttrChange(self,
  11611. '',
  11612. '*',
  11613. prevVals,
  11614. newVals,
  11615. subAttrNames,
  11616. attrNames);
  11617. }
  11618. return ret;
  11619. }
  11620. return setInternal(self, name, value, opts);
  11621. },
  11622. /**
  11623. * internal use, no event involved, just set.
  11624. * @protected overriden by mvc/model
  11625. */
  11626. __set: function(name, value) {
  11627. var self = this,
  11628. setValue,
  11629. // if host does not have meta info corresponding to (name,value)
  11630. // then register on demand in order to collect all data meta info
  11631. // 一定要注册属性元数据,否则其他模块通过 _attrs 不能枚举到所有有效属性
  11632. // 因为属性在声明注册前可以直接设置值
  11633. attrConfig = ensureNonEmpty(getAttrs(self), name, true),
  11634. validator = attrConfig['validator'],
  11635. setter = attrConfig['setter'];
  11636. // validator check
  11637. if (validator = normalFn(self, validator)) {
  11638. if (validator.call(self, value, name) === false) {
  11639. return false;
  11640. }
  11641. }
  11642. // if setter has effect
  11643. if (setter = normalFn(self, setter)) {
  11644. setValue = setter.call(self, value, name);
  11645. }
  11646. if (setValue === INVALID) {
  11647. return false;
  11648. }
  11649. if (setValue !== undef) {
  11650. value = setValue;
  11651. }
  11652. // finally set
  11653. getAttrVals(self)[name] = value;
  11654. },
  11655. /**
  11656. * Gets the current value of the attribute.
  11657. */
  11658. get: function(name) {
  11659. var self = this,
  11660. dot = ".",
  11661. path,
  11662. attrConfig,
  11663. getter, ret;
  11664. if (name.indexOf(dot) !== -1) {
  11665. path = name.split(dot);
  11666. name = path.shift();
  11667. }
  11668. attrConfig = ensureNonEmpty(getAttrs(self), name);
  11669. getter = attrConfig['getter'];
  11670. // get user-set value or default value
  11671. //user-set value takes privilege
  11672. ret = name in getAttrVals(self) ?
  11673. getAttrVals(self)[name] :
  11674. self.__getDefAttrVal(name);
  11675. // invoke getter for this attribute
  11676. if (getter = normalFn(self, getter)) {
  11677. ret = getter.call(self, ret, name);
  11678. }
  11679. if (path) {
  11680. ret = getValueByPath(ret, path);
  11681. }
  11682. return ret;
  11683. },
  11684. /**
  11685. * get default attribute value from valueFn/value
  11686. * @private
  11687. * @param name
  11688. */
  11689. __getDefAttrVal: function(name) {
  11690. var self = this,
  11691. attrConfig = ensureNonEmpty(getAttrs(self), name),
  11692. valFn,
  11693. val;
  11694. if ((valFn = normalFn(self, attrConfig.valueFn))) {
  11695. val = valFn.call(self);
  11696. if (val !== undef) {
  11697. attrConfig.value = val;
  11698. }
  11699. delete attrConfig.valueFn;
  11700. getAttrs(self)[name] = attrConfig;
  11701. }
  11702. return attrConfig.value;
  11703. },
  11704. /**
  11705. * Resets the value of an attribute.just reset what addAttr set (not what invoker set when call new Xx(cfg))
  11706. * @param {String} name name of attribute
  11707. */
  11708. reset: function (name, opts) {
  11709. var self = this;
  11710. if (S.isString(name)) {
  11711. if (self.hasAttr(name)) {
  11712. // if attribute does not have default value, then set to undefined.
  11713. return self.set(name, self.__getDefAttrVal(name), opts);
  11714. }
  11715. else {
  11716. return self;
  11717. }
  11718. }
  11719. opts = name;
  11720. var attrs = getAttrs(self),
  11721. values = {};
  11722. // reset all
  11723. for (name in attrs) {
  11724. values[name] = self.__getDefAttrVal(name);
  11725. }
  11726. self.set(values, opts);
  11727. return self;
  11728. }
  11729. });
  11730. function capitalFirst(s) {
  11731. return s.charAt(0).toUpperCase() + s.substring(1);
  11732. }
  11733. if (undef) {
  11734. Attribute.prototype.addAttrs = undef;
  11735. }
  11736. return Attribute;
  11737. });
  11738. /**
  11739. * 2011-10-18
  11740. * get/set sub attribute value ,set("x.y",val) x 最好为 {} ,不要是 new Clz() 出来的
  11741. * add validator
  11742. */
  11743. /**
  11744. * @module Base
  11745. * @author yiminghe@gmail.com,lifesinger@gmail.com
  11746. */
  11747. KISSY.add('base/base', function (S, Attribute, Event) {
  11748. /**
  11749. * Base for class-based component
  11750. * @name Base
  11751. * @extends Event.Target
  11752. * @extends Attribute
  11753. * @class
  11754. */
  11755. function Base(config) {
  11756. var c = this.constructor;
  11757. // define
  11758. while (c) {
  11759. addAttrs(this, c['ATTRS']);
  11760. c = c.superclass ? c.superclass.constructor : null;
  11761. }
  11762. // initial
  11763. initAttrs(this, config);
  11764. }
  11765. function addAttrs(host, attrs) {
  11766. if (attrs) {
  11767. for (var attr in attrs) {
  11768. // 子类上的 ATTRS 配置优先
  11769. if (attrs.hasOwnProperty(attr)) {
  11770. // 父类后加,父类不覆盖子类的相同设置
  11771. // 属性对象会 merge a: {y:{getter:fn}}, b:{y:{value:3}}, b extends a => b {y:{value:3}}
  11772. host.addAttr(attr, attrs[attr], false);
  11773. }
  11774. }
  11775. }
  11776. }
  11777. function initAttrs(host, config) {
  11778. if (config) {
  11779. for (var attr in config) {
  11780. if (config.hasOwnProperty(attr)) {
  11781. //用户设置会调用 setter/validator 的,但不会触发属性变化事件
  11782. host.__set(attr, config[attr]);
  11783. }
  11784. }
  11785. }
  11786. }
  11787. S.augment(Base, Event.Target, Attribute);
  11788. return Base;
  11789. }, {
  11790. requires:["./attribute","event"]
  11791. });
  11792. KISSY.add("base", function(S, Base, Attribute) {
  11793. Base.Attribute = Attribute;
  11794. return Base;
  11795. }, {
  11796. requires:["base/base","base/attribute"]
  11797. });
  11798. /**
  11799. * @module cookie
  11800. * @author lifesinger@gmail.com
  11801. */
  11802. KISSY.add('cookie/base', function(S) {
  11803. var doc = document,
  11804. MILLISECONDS_OF_DAY = 24 * 60 * 60 * 1000,
  11805. encode = encodeURIComponent,
  11806. decode = decodeURIComponent;
  11807. function isNotEmptyString(val) {
  11808. return S.isString(val) && val !== '';
  11809. }
  11810. return {
  11811. /**
  11812. * 获取 cookie 值
  11813. * @return {string} 如果 name 不存在,返回 undefined
  11814. */
  11815. get: function(name) {
  11816. var ret, m;
  11817. if (isNotEmptyString(name)) {
  11818. if ((m = String(doc.cookie).match(
  11819. new RegExp('(?:^| )' + name + '(?:(?:=([^;]*))|;|$)')))) {
  11820. ret = m[1] ? decode(m[1]) : '';
  11821. }
  11822. }
  11823. return ret;
  11824. },
  11825. set: function(name, val, expires, domain, path, secure) {
  11826. var text = String(encode(val)), date = expires;
  11827. // 从当前时间开始,多少天后过期
  11828. if (typeof date === 'number') {
  11829. date = new Date();
  11830. date.setTime(date.getTime() + expires * MILLISECONDS_OF_DAY);
  11831. }
  11832. // expiration date
  11833. if (date instanceof Date) {
  11834. text += '; expires=' + date.toUTCString();
  11835. }
  11836. // domain
  11837. if (isNotEmptyString(domain)) {
  11838. text += '; domain=' + domain;
  11839. }
  11840. // path
  11841. if (isNotEmptyString(path)) {
  11842. text += '; path=' + path;
  11843. }
  11844. // secure
  11845. if (secure) {
  11846. text += '; secure';
  11847. }
  11848. //S.log(text);
  11849. doc.cookie = name + '=' + text;
  11850. },
  11851. remove: function(name, domain, path, secure) {
  11852. // 置空,并立刻过期
  11853. this.set(name, '', -1, domain, path, secure);
  11854. }
  11855. };
  11856. });
  11857. /**
  11858. * NOTES:
  11859. *
  11860. * 2010.04
  11861. * - get 方法要考虑 ie 下,
  11862. * 值为空的 cookie 为 'test3; test3=3; test3tt=2; test1=t1test3; test3', 没有等于号。
  11863. * 除了正则获取,还可以 split 字符串的方式来获取。
  11864. * - api 设计上,原本想借鉴 jQuery 的简明风格:S.cookie(name, ...), 但考虑到可扩展性,目前
  11865. * 独立成静态工具类的方式更优。
  11866. */
  11867. KISSY.add("cookie", function(S,C) {
  11868. return C;
  11869. }, {
  11870. requires:["cookie/base"]
  11871. });
  11872. KISSY.add("core", function(S, UA, DOM, Event, Node, JSON, Ajax, Anim, Base, Cookie) {
  11873. var re = {
  11874. UA:UA,
  11875. DOM:DOM,
  11876. Event:Event,
  11877. EventTarget:Event.Target,
  11878. "EventObject":Event.Object,
  11879. Node:Node,
  11880. NodeList:Node,
  11881. JSON:JSON,
  11882. "Ajax":Ajax,
  11883. "IO":Ajax,
  11884. ajax:Ajax,
  11885. io:Ajax,
  11886. jsonp:Ajax.jsonp,
  11887. Anim:Anim,
  11888. Easing:Anim.Easing,
  11889. Base:Base,
  11890. "Cookie":Cookie,
  11891. one:Node.one,
  11892. all:Node.all,
  11893. get:DOM.get,
  11894. query:DOM.query
  11895. };
  11896. S.mix(S, re);
  11897. return re;
  11898. }, {
  11899. requires:[
  11900. "ua",
  11901. "dom",
  11902. "event",
  11903. "node",
  11904. "json",
  11905. "ajax",
  11906. "anim",
  11907. "base",
  11908. "cookie"
  11909. ]
  11910. });
  11911. KISSY.use('core');