avalon.modern.js 195 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788
  1. /*==================================================
  2. Copyright (c) 2013-2015 司徒正美 and other contributors
  3. http://www.cnblogs.com/rubylouvre/
  4. https://github.com/RubyLouvre
  5. http://weibo.com/jslouvre/
  6. Released under the MIT license
  7. avalon.modern.js 1.5.5 built in 2015.11.20
  8. support IE10+ and other browsers
  9. ==================================================*/
  10. (function(global, factory) {
  11. if (typeof module === "object" && typeof module.exports === "object") {
  12. // For CommonJS and CommonJS-like environments where a proper `window`
  13. // is present, execute the factory and get avalon.
  14. // For environments that do not have a `window` with a `document`
  15. // (such as Node.js), expose a factory as module.exports.
  16. // This accentuates the need for the creation of a real `window`.
  17. // e.g. var avalon = require("avalon")(window);
  18. module.exports = global.document ? factory(global, true) : function(w) {
  19. if (!w.document) {
  20. throw new Error("Avalon requires a window with a document")
  21. }
  22. return factory(w)
  23. }
  24. } else {
  25. factory(global)
  26. }
  27. // Pass this if window is not defined yet
  28. }(typeof window !== "undefined" ? window : this, function(window, noGlobal){
  29. /*********************************************************************
  30. * 全局变量及方法 *
  31. **********************************************************************/
  32. var expose = Date.now()
  33. //http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function
  34. var DOC = window.document
  35. var head = DOC.head //HEAD元素
  36. head.insertAdjacentHTML("afterBegin", '<avalon ms-skip class="avalonHide"><style id="avalonStyle">.avalonHide{ display: none!important }</style></avalon>')
  37. var ifGroup = head.firstChild
  38. function log() {
  39. if (avalon.config.debug) {
  40. // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log
  41. console.log.apply(console, arguments)
  42. }
  43. }
  44. /**
  45. * Creates a new object without a prototype. This object is useful for lookup without having to
  46. * guard against prototypically inherited properties via hasOwnProperty.
  47. *
  48. * Related micro-benchmarks:
  49. * - http://jsperf.com/object-create2
  50. * - http://jsperf.com/proto-map-lookup/2
  51. * - http://jsperf.com/for-in-vs-object-keys2
  52. */
  53. function createMap() {
  54. return Object.create(null)
  55. }
  56. var subscribers = "$" + expose
  57. var nullObject = {} //作用类似于noop,只用于代码防御,千万不要在它上面添加属性
  58. var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach
  59. var rw20g = /\w+/g
  60. var rsvg = /^\[object SVG\w*Element\]$/
  61. var rwindow = /^\[object (?:Window|DOMWindow|global)\]$/
  62. var oproto = Object.prototype
  63. var ohasOwn = oproto.hasOwnProperty
  64. var serialize = oproto.toString
  65. var ap = Array.prototype
  66. var aslice = ap.slice
  67. var W3C = window.dispatchEvent
  68. var root = DOC.documentElement
  69. var avalonFragment = DOC.createDocumentFragment()
  70. var cinerator = DOC.createElement("div")
  71. var class2type = {}
  72. "Boolean Number String Function Array Date RegExp Object Error".replace(rword, function (name) {
  73. class2type["[object " + name + "]"] = name.toLowerCase()
  74. })
  75. function scpCompile(array){
  76. return Function.apply(noop,array)
  77. }
  78. function noop(){}
  79. function oneObject(array, val) {
  80. if (typeof array === "string") {
  81. array = array.match(rword) || []
  82. }
  83. var result = {},
  84. value = val !== void 0 ? val : 1
  85. for (var i = 0, n = array.length; i < n; i++) {
  86. result[array[i]] = value
  87. }
  88. return result
  89. }
  90. //生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
  91. var generateID = function (prefix) {
  92. prefix = prefix || "avalon"
  93. return String(Math.random() + Math.random()).replace(/\d\.\d{4}/, prefix)
  94. }
  95. function IE() {
  96. if (window.VBArray) {
  97. var mode = document.documentMode
  98. return mode ? mode : window.XMLHttpRequest ? 7 : 6
  99. } else {
  100. return NaN
  101. }
  102. }
  103. var IEVersion = IE()
  104. avalon = function (el) { //创建jQuery式的无new 实例化结构
  105. return new avalon.init(el)
  106. }
  107. /*视浏览器情况采用最快的异步回调*/
  108. avalon.nextTick = new function () {// jshint ignore:line
  109. var tickImmediate = window.setImmediate
  110. var tickObserver = window.MutationObserver
  111. if (tickImmediate) {
  112. return tickImmediate.bind(window)
  113. }
  114. var queue = []
  115. function callback() {
  116. var n = queue.length
  117. for (var i = 0; i < n; i++) {
  118. queue[i]()
  119. }
  120. queue = queue.slice(n)
  121. }
  122. if (tickObserver) {
  123. var node = document.createTextNode("avalon")
  124. new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line
  125. var bool = false
  126. return function (fn) {
  127. queue.push(fn)
  128. bool = !bool
  129. node.data = bool
  130. }
  131. }
  132. return function (fn) {
  133. setTimeout(fn, 4)
  134. }
  135. }// jshint ignore:line
  136. /*********************************************************************
  137. * avalon的静态方法定义区 *
  138. **********************************************************************/
  139. avalon.init = function (el) {
  140. this[0] = this.element = el
  141. }
  142. avalon.fn = avalon.prototype = avalon.init.prototype
  143. avalon.type = function (obj) { //取得目标的类型
  144. if (obj == null) {
  145. return String(obj)
  146. }
  147. // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function
  148. return typeof obj === "object" || typeof obj === "function" ?
  149. class2type[serialize.call(obj)] || "object" :
  150. typeof obj
  151. }
  152. var isFunction = function (fn) {
  153. return serialize.call(fn) === "[object Function]"
  154. }
  155. avalon.isFunction = isFunction
  156. avalon.isWindow = function (obj) {
  157. return rwindow.test(serialize.call(obj))
  158. }
  159. /*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/
  160. avalon.isPlainObject = function (obj) {
  161. // 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过
  162. return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto
  163. }
  164. //与jQuery.extend方法,可用于浅拷贝,深拷贝
  165. avalon.mix = avalon.fn.mix = function () {
  166. var options, name, src, copy, copyIsArray, clone,
  167. target = arguments[0] || {},
  168. i = 1,
  169. length = arguments.length,
  170. deep = false
  171. // 如果第一个参数为布尔,判定是否深拷贝
  172. if (typeof target === "boolean") {
  173. deep = target
  174. target = arguments[1] || {}
  175. i++
  176. }
  177. //确保接受方为一个复杂的数据类型
  178. if (typeof target !== "object" && !isFunction(target)) {
  179. target = {}
  180. }
  181. //如果只有一个参数,那么新成员添加于mix所在的对象上
  182. if (i === length) {
  183. target = this
  184. i--
  185. }
  186. for (; i < length; i++) {
  187. //只处理非空参数
  188. if ((options = arguments[i]) != null) {
  189. for (name in options) {
  190. src = target[name]
  191. copy = options[name]
  192. // 防止环引用
  193. if (target === copy) {
  194. continue
  195. }
  196. if (deep && copy && (avalon.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
  197. if (copyIsArray) {
  198. copyIsArray = false
  199. clone = src && Array.isArray(src) ? src : []
  200. } else {
  201. clone = src && avalon.isPlainObject(src) ? src : {}
  202. }
  203. target[name] = avalon.mix(deep, clone, copy)
  204. } else if (copy !== void 0) {
  205. target[name] = copy
  206. }
  207. }
  208. }
  209. }
  210. return target
  211. }
  212. function _number(a, len) { //用于模拟slice, splice的效果
  213. a = Math.floor(a) || 0
  214. return a < 0 ? Math.max(len + a, 0) : Math.min(a, len);
  215. }
  216. avalon.mix({
  217. rword: rword,
  218. subscribers: subscribers,
  219. version: 1.55,
  220. ui: {},
  221. log: log,
  222. slice: function (nodes, start, end) {
  223. return aslice.call(nodes, start, end)
  224. },
  225. noop: noop,
  226. /*如果不用Error对象封装一下,str在控制台下可能会乱码*/
  227. error: function (str, e) {
  228. throw new (e || Error)(str)// jshint ignore:line
  229. },
  230. /*将一个以空格或逗号隔开的字符串或数组,转换成一个键值都为1的对象*/
  231. oneObject: oneObject,
  232. /* avalon.range(10)
  233. => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  234. avalon.range(1, 11)
  235. => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  236. avalon.range(0, 30, 5)
  237. => [0, 5, 10, 15, 20, 25]
  238. avalon.range(0, -10, -1)
  239. => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
  240. avalon.range(0)
  241. => []*/
  242. range: function (start, end, step) { // 用于生成整数数组
  243. step || (step = 1)
  244. if (end == null) {
  245. end = start || 0
  246. start = 0
  247. }
  248. var index = -1,
  249. length = Math.max(0, Math.ceil((end - start) / step)),
  250. result = new Array(length)
  251. while (++index < length) {
  252. result[index] = start
  253. start += step
  254. }
  255. return result
  256. },
  257. eventHooks: {},
  258. /*绑定事件*/
  259. bind: function (el, type, fn, phase) {
  260. var hooks = avalon.eventHooks
  261. var hook = hooks[type]
  262. if (typeof hook === "object") {
  263. type = hook.type || type
  264. phase = hook.phase || !!phase
  265. fn = hook.fn ? hook.fn(el, fn) : fn
  266. }
  267. el.addEventListener(type, fn, phase)
  268. return fn
  269. },
  270. /*卸载事件*/
  271. unbind: function (el, type, fn, phase) {
  272. var hooks = avalon.eventHooks
  273. var hook = hooks[type]
  274. var callback = fn || noop
  275. if (typeof hook === "object") {
  276. type = hook.type || type
  277. phase = hook.phase || !!phase
  278. }
  279. el.removeEventListener(type, callback, phase)
  280. },
  281. /*读写删除元素节点的样式*/
  282. css: function (node, name, value) {
  283. if (node instanceof avalon) {
  284. node = node[0]
  285. }
  286. var prop = /[_-]/.test(name) ? camelize(name) : name, fn
  287. name = avalon.cssName(prop) || prop
  288. if (value === void 0 || typeof value === "boolean") { //获取样式
  289. fn = cssHooks[prop + ":get"] || cssHooks["@:get"]
  290. if (name === "background") {
  291. name = "backgroundColor"
  292. }
  293. var val = fn(node, name)
  294. return value === true ? parseFloat(val) || 0 : val
  295. } else if (value === "") { //请除样式
  296. node.style[name] = ""
  297. } else { //设置样式
  298. if (value == null || value !== value) {
  299. return
  300. }
  301. if (isFinite(value) && !avalon.cssNumber[prop]) {
  302. value += "px"
  303. }
  304. fn = cssHooks[prop + ":set"] || cssHooks["@:set"]
  305. fn(node, name, value)
  306. }
  307. },
  308. /*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/
  309. each: function (obj, fn) {
  310. if (obj) { //排除null, undefined
  311. var i = 0
  312. if (isArrayLike(obj)) {
  313. for (var n = obj.length; i < n; i++) {
  314. if (fn(i, obj[i]) === false)
  315. break
  316. }
  317. } else {
  318. for (i in obj) {
  319. if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) {
  320. break
  321. }
  322. }
  323. }
  324. }
  325. },
  326. //收集元素的data-{{prefix}}-*属性,并转换为对象
  327. getWidgetData: function (elem, prefix) {
  328. var raw = avalon(elem).data()
  329. var result = {}
  330. for (var i in raw) {
  331. if (i.indexOf(prefix) === 0) {
  332. result[i.replace(prefix, "").replace(/\w/, function (a) {
  333. return a.toLowerCase()
  334. })] = raw[i]
  335. }
  336. }
  337. return result
  338. },
  339. Array: {
  340. /*只有当前数组不存在此元素时只添加它*/
  341. ensure: function (target, item) {
  342. if (target.indexOf(item) === -1) {
  343. return target.push(item)
  344. }
  345. },
  346. /*移除数组中指定位置的元素,返回布尔表示成功与否*/
  347. removeAt: function (target, index) {
  348. return !!target.splice(index, 1).length
  349. },
  350. /*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/
  351. remove: function (target, item) {
  352. var index = target.indexOf(item)
  353. if (~index)
  354. return avalon.Array.removeAt(target, index)
  355. return false
  356. }
  357. }
  358. })
  359. var bindingHandlers = avalon.bindingHandlers = {}
  360. var bindingExecutors = avalon.bindingExecutors = {}
  361. var directives = avalon.directives = {}
  362. avalon.directive = function (name, obj) {
  363. bindingHandlers[name] = obj.init = (obj.init || noop)
  364. bindingExecutors[name] = obj.update = (obj.update || noop)
  365. return directives[name] = obj
  366. }
  367. /*判定是否类数组,如节点集合,纯数组,arguments与拥有非负整数的length属性的纯JS对象*/
  368. function isArrayLike(obj) {
  369. if (obj && typeof obj === "object") {
  370. var n = obj.length,
  371. str = serialize.call(obj)
  372. if (/(Array|List|Collection|Map|Arguments)\]$/.test(str)) {
  373. return true
  374. } else if (str === "[object Object]" && n === (n >>> 0)) {
  375. return true //由于ecma262v5能修改对象属性的enumerable,因此不能用propertyIsEnumerable来判定了
  376. }
  377. }
  378. return false
  379. }
  380. // https://github.com/rsms/js-lru
  381. var Cache = new function() {// jshint ignore:line
  382. function LRU(maxLength) {
  383. this.size = 0
  384. this.limit = maxLength
  385. this.head = this.tail = void 0
  386. this._keymap = {}
  387. }
  388. var p = LRU.prototype
  389. p.put = function(key, value) {
  390. var entry = {
  391. key: key,
  392. value: value
  393. }
  394. this._keymap[key] = entry
  395. if (this.tail) {
  396. this.tail.newer = entry
  397. entry.older = this.tail
  398. } else {
  399. this.head = entry
  400. }
  401. this.tail = entry
  402. if (this.size === this.limit) {
  403. this.shift()
  404. } else {
  405. this.size++
  406. }
  407. return value
  408. }
  409. p.shift = function() {
  410. var entry = this.head
  411. if (entry) {
  412. this.head = this.head.newer
  413. this.head.older =
  414. entry.newer =
  415. entry.older =
  416. this._keymap[entry.key] = void 0
  417. delete this._keymap[entry.key] //#1029
  418. }
  419. }
  420. p.get = function(key) {
  421. var entry = this._keymap[key]
  422. if (entry === void 0)
  423. return
  424. if (entry === this.tail) {
  425. return entry.value
  426. }
  427. // HEAD--------------TAIL
  428. // <.older .newer>
  429. // <--- add direction --
  430. // A B C <D> E
  431. if (entry.newer) {
  432. if (entry === this.head) {
  433. this.head = entry.newer
  434. }
  435. entry.newer.older = entry.older // C <-- E.
  436. }
  437. if (entry.older) {
  438. entry.older.newer = entry.newer // C. --> E
  439. }
  440. entry.newer = void 0 // D --x
  441. entry.older = this.tail // D. --> E
  442. if (this.tail) {
  443. this.tail.newer = entry // E. <-- D
  444. }
  445. this.tail = entry
  446. return entry.value
  447. }
  448. return LRU
  449. }// jshint ignore:line
  450. /*********************************************************************
  451. * DOM 底层补丁 *
  452. **********************************************************************/
  453. //safari5+是把contains方法放在Element.prototype上而不是Node.prototype
  454. if (!DOC.contains) {
  455. Node.prototype.contains = function (arg) {
  456. return !!(this.compareDocumentPosition(arg) & 16)
  457. }
  458. }
  459. avalon.contains = function (root, el) {
  460. try {
  461. while ((el = el.parentNode))
  462. if (el === root)
  463. return true
  464. return false
  465. } catch (e) {
  466. return false
  467. }
  468. }
  469. if (window.SVGElement) {
  470. var svgns = "http://www.w3.org/2000/svg"
  471. var svg = DOC.createElementNS(svgns, "svg")
  472. svg.innerHTML = '<circle cx="50" cy="50" r="40" fill="red" />'
  473. if (!rsvg.test(svg.firstChild)) {// #409
  474. /* jshint ignore:start */
  475. function enumerateNode(node, targetNode) {
  476. if (node && node.childNodes) {
  477. var nodes = node.childNodes
  478. for (var i = 0, el; el = nodes[i++]; ) {
  479. if (el.tagName) {
  480. var svg = DOC.createElementNS(svgns,
  481. el.tagName.toLowerCase())
  482. // copy attrs
  483. ap.forEach.call(el.attributes, function (attr) {
  484. svg.setAttribute(attr.name, attr.value)
  485. })
  486. // 递归处理子节点
  487. enumerateNode(el, svg)
  488. targetNode.appendChild(svg)
  489. }
  490. }
  491. }
  492. }
  493. /* jshint ignore:end */
  494. Object.defineProperties(SVGElement.prototype, {
  495. "outerHTML": {//IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性
  496. enumerable: true,
  497. configurable: true,
  498. get: function () {
  499. return new XMLSerializer().serializeToString(this)
  500. },
  501. set: function (html) {
  502. var tagName = this.tagName.toLowerCase(),
  503. par = this.parentNode,
  504. frag = avalon.parseHTML(html)
  505. // 操作的svg,直接插入
  506. if (tagName === "svg") {
  507. par.insertBefore(frag, this)
  508. // svg节点的子节点类似
  509. } else {
  510. var newFrag = DOC.createDocumentFragment()
  511. enumerateNode(frag, newFrag)
  512. par.insertBefore(newFrag, this)
  513. }
  514. par.removeChild(this)
  515. }
  516. },
  517. "innerHTML": {
  518. enumerable: true,
  519. configurable: true,
  520. get: function () {
  521. var s = this.outerHTML
  522. var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i")
  523. var rclose = new RegExp("<\/" + this.nodeName + ">$", "i")
  524. return s.replace(ropen, "").replace(rclose, "")
  525. },
  526. set: function (html) {
  527. if (avalon.clearHTML) {
  528. avalon.clearHTML(this)
  529. var frag = avalon.parseHTML(html)
  530. enumerateNode(frag, this)
  531. }
  532. }
  533. }
  534. })
  535. }
  536. }
  537. //========================= event binding ====================
  538. var eventHooks = avalon.eventHooks
  539. //针对firefox, chrome修正mouseenter, mouseleave(chrome30+)
  540. if (!("onmouseenter" in root)) {
  541. avalon.each({
  542. mouseenter: "mouseover",
  543. mouseleave: "mouseout"
  544. }, function (origType, fixType) {
  545. eventHooks[origType] = {
  546. type: fixType,
  547. fn: function (elem, fn) {
  548. return function (e) {
  549. var t = e.relatedTarget
  550. if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) {
  551. delete e.type
  552. e.type = origType
  553. return fn.call(elem, e)
  554. }
  555. }
  556. }
  557. }
  558. })
  559. }
  560. //针对IE9+, w3c修正animationend
  561. avalon.each({
  562. AnimationEvent: "animationend",
  563. WebKitAnimationEvent: "webkitAnimationEnd"
  564. }, function (construct, fixType) {
  565. if (window[construct] && !eventHooks.animationend) {
  566. eventHooks.animationend = {
  567. type: fixType
  568. }
  569. }
  570. })
  571. if (DOC.onmousewheel === void 0) {
  572. /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120
  573. firefox DOMMouseScroll detail 下3 上-3
  574. firefox wheel detlaY 下3 上-3
  575. IE9-11 wheel deltaY 下40 上-40
  576. chrome wheel deltaY 下100 上-100 */
  577. eventHooks.mousewheel = {
  578. type: "wheel",
  579. fn: function (elem, fn) {
  580. return function (e) {
  581. e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120
  582. e.wheelDeltaX = 0
  583. Object.defineProperty(e, "type", {
  584. value: "mousewheel"
  585. })
  586. fn.call(elem, e)
  587. }
  588. }
  589. }
  590. }
  591. /*********************************************************************
  592. * 配置系统 *
  593. **********************************************************************/
  594. function kernel(settings) {
  595. for (var p in settings) {
  596. if (!ohasOwn.call(settings, p))
  597. continue
  598. var val = settings[p]
  599. if (typeof kernel.plugins[p] === "function") {
  600. kernel.plugins[p](val)
  601. } else if (typeof kernel[p] === "object") {
  602. avalon.mix(kernel[p], val)
  603. } else {
  604. kernel[p] = val
  605. }
  606. }
  607. return this
  608. }
  609. var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g
  610. function escapeRegExp(target) {
  611. //http://stevenlevithan.com/regex/xregexp/
  612. //将字符串安全格式化为正则表达式的源码
  613. return (target + "").replace(rregexp, "\\$&")
  614. }
  615. var plugins = {
  616. interpolate: function (array) {
  617. openTag = array[0]
  618. closeTag = array[1]
  619. if (openTag === closeTag) {
  620. throw new SyntaxError("openTag!==closeTag")
  621. var test = openTag + "test" + closeTag
  622. cinerator.innerHTML = test
  623. if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("&lt;") > -1) {
  624. throw new SyntaxError("此定界符不合法")
  625. }
  626. cinerator.innerHTML = ""
  627. }
  628. kernel.openTag = openTag
  629. kernel.closeTag = closeTag
  630. var o = escapeRegExp(openTag),
  631. c = escapeRegExp(closeTag)
  632. rexpr = new RegExp(o + "(.*?)" + c)
  633. rexprg = new RegExp(o + "(.*?)" + c, "g")
  634. rbind = new RegExp(o + ".*?" + c + "|\\sms-")
  635. }
  636. }
  637. kernel.async =true
  638. kernel.debug = true
  639. kernel.plugins = plugins
  640. kernel.plugins['interpolate'](["{{", "}}"])
  641. kernel.paths = {}
  642. kernel.shim = {}
  643. kernel.maxRepeatSize = 100
  644. avalon.config = kernel
  645. function $watch(expr, binding) {
  646. var $events = this.$events || (this.$events = {})
  647. var queue = $events[expr] || ($events[expr] = [])
  648. if (typeof binding === "function") {
  649. var backup = binding
  650. backup.uniqueNumber = Math.random()
  651. binding = {
  652. element: root,
  653. type: "user-watcher",
  654. handler: noop,
  655. vmodels: [this],
  656. expr: expr,
  657. uniqueNumber: backup.uniqueNumber
  658. }
  659. binding.wildcard = /\*/.test(expr)
  660. }
  661. if (!binding.update) {
  662. if (/\w\.*\B/.test(expr)) {
  663. binding.getter = noop
  664. var host = this
  665. binding.update = function () {
  666. var args = this.fireArgs || []
  667. if (args[2])
  668. binding.handler.apply(host, args)
  669. delete this.fireArgs
  670. }
  671. queue.sync = true
  672. avalon.Array.ensure(queue, binding)
  673. } else {
  674. avalon.injectBinding(binding)
  675. }
  676. if (backup) {
  677. binding.handler = backup
  678. }
  679. } else if (!binding.oneTime) {
  680. avalon.Array.ensure(queue, binding)
  681. }
  682. return function () {
  683. binding.update = binding.getter = binding.handler = noop
  684. binding.element = DOC.createElement("a")
  685. }
  686. }
  687. function $emit(key, args) {
  688. var event = this.$events
  689. if (event && event[key]) {
  690. if (args) {
  691. args[2] = key
  692. }
  693. var arr = event[key]
  694. notifySubscribers(arr, args)
  695. var parent = this.$up
  696. if (parent) {
  697. if (this.$pathname) {
  698. $emit.call(parent, this.$pathname + "." + key, args)//以确切的值往上冒泡
  699. }
  700. $emit.call(parent, "*." + key, args)//以模糊的值往上冒泡
  701. }
  702. } else {
  703. parent = this.$up
  704. if(this.$ups ){
  705. for(var i in this.$ups){
  706. $emit.call(this.$ups[i], i+"."+key, args)//以确切的值往上冒泡
  707. }
  708. return
  709. }
  710. if (parent) {
  711. var p = this.$pathname
  712. if (p === "")
  713. p = "*"
  714. var path = p + "." + key
  715. arr = path.split(".")
  716. if (arr.indexOf("*") === -1) {
  717. $emit.call(parent, path, args)//以确切的值往上冒泡
  718. arr[1] = "*"
  719. $emit.call(parent, arr.join("."), args)//以模糊的值往上冒泡
  720. } else {
  721. $emit.call(parent, path, args)//以确切的值往上冒泡
  722. }
  723. }
  724. }
  725. }
  726. function collectDependency(el, key) {
  727. do {
  728. if (el.$watch) {
  729. var e = el.$events || (el.$events = {})
  730. var array = e[key] || (e[key] = [])
  731. dependencyDetection.collectDependency(array)
  732. return
  733. }
  734. el = el.$up
  735. if (el) {
  736. key = el.$pathname + "." + key
  737. } else {
  738. break
  739. }
  740. } while (true)
  741. }
  742. function notifySubscribers(subs, args) {
  743. if (!subs)
  744. return
  745. if (new Date() - beginTime > 444 && typeof subs[0] === "object") {
  746. rejectDisposeQueue()
  747. }
  748. var users = [], renders = []
  749. for (var i = 0, sub; sub = subs[i++]; ) {
  750. if (sub.type === "user-watcher") {
  751. users.push(sub)
  752. } else {
  753. renders.push(sub)
  754. }
  755. }
  756. if (kernel.async) {
  757. buffer.render()//1
  758. for (i = 0; sub = renders[i++]; ) {
  759. if (sub.update) {
  760. var uuid = getUid(sub)
  761. if (!buffer.queue[uuid]) {
  762. buffer.queue[uuid] = 1
  763. buffer.queue.push(sub)
  764. }
  765. }
  766. }
  767. } else {
  768. for (i = 0; sub = renders[i++]; ) {
  769. if (sub.update) {
  770. sub.update()//最小化刷新DOM树
  771. }
  772. }
  773. }
  774. for (i = 0; sub = users[i++]; ) {
  775. if (args && args[2] === sub.expr || sub.wildcard) {
  776. sub.fireArgs = args
  777. }
  778. sub.update()
  779. }
  780. }
  781. //avalon最核心的方法的两个方法之一(另一个是avalon.scan),返回一个ViewModel(VM)
  782. var VMODELS = avalon.vmodels = {} //所有vmodel都储存在这里
  783. avalon.define = function (source) {
  784. var $id = source.$id
  785. if (!$id) {
  786. log("warning: vm必须指定$id")
  787. }
  788. var vmodel = modelFactory(source)
  789. vmodel.$id = $id
  790. return VMODELS[$id] = vmodel
  791. }
  792. //一些不需要被监听的属性
  793. var $$skipArray = oneObject("$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$ups,$track,$accessors")
  794. //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
  795. //标准浏览器使用__defineGetter__, __defineSetter__实现
  796. function modelFactory(source, options) {
  797. options = options || {}
  798. options.watch = true
  799. return observeObject(source, options)
  800. }
  801. //监听对象属性值的变化(注意,数组元素不是数组的属性),通过对劫持当前对象的访问器实现
  802. //监听对象或数组的结构变化, 对对象的键值对进行增删重排, 或对数组的进行增删重排,都属于这范畴
  803. // 通过比较前后代理VM顺序实现
  804. function Component() {
  805. }
  806. function observeObject(source, options) {
  807. if (!source || (source.$id && source.$accessors) || (source.nodeName && source.nodeType > 0)) {
  808. return source
  809. }
  810. //source为原对象,不能是元素节点或null
  811. //options,可选,配置对象,里面有old, force, watch这三个属性
  812. options = options || nullObject
  813. var force = options.force || nullObject
  814. var old = options.old
  815. var oldAccessors = old && old.$accessors || nullObject
  816. var $vmodel = new Component() //要返回的对象, 它在IE6-8下可能被偷龙转凤
  817. var accessors = {} //监控属性
  818. var hasOwn = {}
  819. var skip = []
  820. var simple = []
  821. var $skipArray = {}
  822. if (source.$skipArray) {
  823. $skipArray = oneObject(source.$skipArray)
  824. delete source.$skipArray
  825. }
  826. //处理计算属性
  827. var computed = source.$computed
  828. if (computed) {
  829. delete source.$computed
  830. for (var name in computed) {
  831. hasOwn[name] = true;
  832. (function (key, value) {
  833. var old
  834. accessors[key] = {
  835. get: function () {
  836. return old = value.get.call(this)
  837. },
  838. set: function (x) {
  839. if (typeof value.set === "function") {
  840. var older = old
  841. value.set.call(this, x)
  842. var newer = this[key]
  843. if (this.$fire && (newer !== older)) {
  844. this.$fire(key, newer, older)
  845. }
  846. }
  847. },
  848. enumerable: true,
  849. configurable: true
  850. }
  851. })(name, computed[name])// jshint ignore:line
  852. }
  853. }
  854. for (name in source) {
  855. var value = source[name]
  856. if (!$$skipArray[name])
  857. hasOwn[name] = true
  858. if (typeof value === "function" || (value && value.nodeName && value.nodeType > 0) ||
  859. (!force[name] && (name.charAt(0) === "$" || $$skipArray[name] || $skipArray[name]))) {
  860. skip.push(name)
  861. } else if (isComputed(value)) {
  862. log("warning:计算属性建议放在$computed对象中统一定义");
  863. (function (key, value) {
  864. var old
  865. accessors[key] = {
  866. get: function () {
  867. return old = value.get.call(this)
  868. },
  869. set: function (x) {
  870. if (typeof value.set === "function") {
  871. var older = old
  872. value.set.call(this, x)
  873. var newer = this[key]
  874. if (this.$fire && (newer !== older)) {
  875. this.$fire(key, newer, older)
  876. }
  877. }
  878. },
  879. enumerable: true,
  880. configurable: true
  881. }
  882. })(name, value)// jshint ignore:line
  883. } else {
  884. simple.push(name)
  885. if (oldAccessors[name]) {
  886. accessors[name] = oldAccessors[name]
  887. } else {
  888. accessors[name] = makeGetSet(name, value)
  889. }
  890. }
  891. }
  892. accessors["$model"] = $modelDescriptor
  893. $vmodel = Object.defineProperties($vmodel, accessors, source)
  894. function trackBy(name) {
  895. return hasOwn[name] === true
  896. }
  897. skip.forEach(function (name) {
  898. $vmodel[name] = source[name]
  899. })
  900. /* jshint ignore:start */
  901. hideProperty($vmodel, "$ups", null)
  902. hideProperty($vmodel, "$id", "anonymous")
  903. hideProperty($vmodel, "$up", old ? old.$up : null)
  904. hideProperty($vmodel, "$track", Object.keys(hasOwn))
  905. hideProperty($vmodel, "$active", false)
  906. hideProperty($vmodel, "$pathname", old ? old.$pathname : "")
  907. hideProperty($vmodel, "$accessors", accessors)
  908. hideProperty($vmodel, "hasOwnProperty", trackBy)
  909. if (options.watch) {
  910. hideProperty($vmodel, "$watch", function () {
  911. return $watch.apply($vmodel, arguments)
  912. })
  913. hideProperty($vmodel, "$fire", function (path, a) {
  914. if (path.indexOf("all!") === 0) {
  915. var ee = path.slice(4)
  916. for (var i in avalon.vmodels) {
  917. var v = avalon.vmodels[i]
  918. v.$fire && v.$fire.apply(v, [ee, a])
  919. }
  920. } else {
  921. $emit.call($vmodel, path, [a])
  922. }
  923. })
  924. }
  925. /* jshint ignore:end */
  926. //必须设置了$active,$events
  927. simple.forEach(function (name) {
  928. var oldVal = old && old[name]
  929. var val = $vmodel[name] = source[name]
  930. if (val && typeof val === "object") {
  931. val.$up = $vmodel
  932. val.$pathname = name
  933. }
  934. $emit.call($vmodel, name,[val,oldVal])
  935. })
  936. for (name in computed) {
  937. value = $vmodel[name]
  938. }
  939. $vmodel.$active = true
  940. return $vmodel
  941. }
  942. /*
  943. 新的VM拥有如下私有属性
  944. $id: vm.id
  945. $events: 放置$watch回调与绑定对象
  946. $watch: 增强版$watch
  947. $fire: 触发$watch回调
  948. $track:一个数组,里面包含用户定义的所有键名
  949. $active:boolean,false时防止依赖收集
  950. $model:返回一个纯净的JS对象
  951. $accessors:放置所有读写器的数据描述对象
  952. $up:返回其上级对象
  953. $pathname:返回此对象在上级对象的名字,注意,数组元素的$pathname为空字符串
  954. =============================
  955. $skipArray:用于指定不可监听的属性,但VM生成是没有此属性的
  956. */
  957. function isComputed(val) {//speed up!
  958. if (val && typeof val === "object") {
  959. for (var i in val) {
  960. if (i !== "get" && i !== "set") {
  961. return false
  962. }
  963. }
  964. return typeof val.get === "function"
  965. }
  966. }
  967. function makeGetSet(key, value) {
  968. var childVm, value = NaN
  969. return {
  970. get: function () {
  971. if (this.$active) {
  972. collectDependency(this, key)
  973. }
  974. return value
  975. },
  976. set: function (newVal) {
  977. if (value === newVal)
  978. return
  979. var oldValue = value
  980. childVm = observe(newVal, value)
  981. if (childVm) {
  982. value = childVm
  983. } else {
  984. childVm = void 0
  985. value = newVal
  986. }
  987. if (Object(childVm) === childVm) {
  988. childVm.$pathname = key
  989. childVm.$up = this
  990. }
  991. if (this.$active) {
  992. $emit.call(this, key, [value, oldValue])
  993. }
  994. },
  995. enumerable: true,
  996. configurable: true
  997. }
  998. }
  999. function observe(obj, old, hasReturn, watch) {
  1000. if (Array.isArray(obj)) {
  1001. return observeArray(obj, old, watch)
  1002. } else if (avalon.isPlainObject(obj)) {
  1003. if (old && typeof old === 'object') {
  1004. var keys = Object.keys(obj)
  1005. var keys2 = Object.keys(old)
  1006. if (keys.join(";") === keys2.join(";")) {
  1007. for (var i in obj) {
  1008. if (obj.hasOwnProperty(i)) {
  1009. old[i] = obj[i]
  1010. }
  1011. }
  1012. return old
  1013. }
  1014. old.$active = false
  1015. }
  1016. return observeObject(obj, {
  1017. old: old,
  1018. watch: watch
  1019. })
  1020. }
  1021. if (hasReturn) {
  1022. return obj
  1023. }
  1024. }
  1025. function observeArray(array, old, watch) {
  1026. if (old) {
  1027. var args = [0, old.length].concat(array)
  1028. old.splice.apply(old, args)
  1029. return old
  1030. } else {
  1031. for (var i in newProto) {
  1032. array[i] = newProto[i]
  1033. }
  1034. hideProperty(array, "$up", null)
  1035. hideProperty(array, "$pathname", "")
  1036. hideProperty(array, "$track", createTrack(array.length))
  1037. array._ = observeObject({
  1038. length: NaN
  1039. }, {
  1040. watch: true
  1041. })
  1042. array._.length = array.length
  1043. array._.$watch("length", function (a, b) {
  1044. $emit.call(array.$up, array.$pathname + ".length", [a, b])
  1045. })
  1046. if (watch) {
  1047. hideProperty(array, "$watch", function () {
  1048. return $watch.apply(array, arguments)
  1049. })
  1050. }
  1051. Object.defineProperty(array, "$model", $modelDescriptor)
  1052. for (var j = 0, n = array.length; j < n; j++) {
  1053. var el = array[j] = observe(array[j], 0, 1, 1)
  1054. if (Object(el) === el) {//#1077
  1055. el.$up = array
  1056. }
  1057. }
  1058. return array
  1059. }
  1060. }
  1061. function hideProperty(host, name, value) {
  1062. Object.defineProperty(host, name, {
  1063. value: value,
  1064. writable: true,
  1065. enumerable: false,
  1066. configurable: true
  1067. })
  1068. }
  1069. function toJson(val) {
  1070. var xtype = avalon.type(val)
  1071. if (xtype === "array") {
  1072. var array = []
  1073. for (var i = 0; i < val.length; i++) {
  1074. array[i] = toJson(val[i])
  1075. }
  1076. return array
  1077. } else if (xtype === "object") {
  1078. var obj = {}
  1079. for (i in val) {
  1080. if (val.hasOwnProperty(i)) {
  1081. var value = val[i]
  1082. obj[i] = value && value.nodeType ? value : toJson(value)
  1083. }
  1084. }
  1085. return obj
  1086. }
  1087. return val
  1088. }
  1089. var $modelDescriptor = {
  1090. get: function () {
  1091. return toJson(this)
  1092. },
  1093. set: noop,
  1094. enumerable: false,
  1095. configurable: true
  1096. }
  1097. /*********************************************************************
  1098. * 监控数组(与ms-each, ms-repeat配合使用) *
  1099. **********************************************************************/
  1100. var arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice']
  1101. var arrayProto = Array.prototype
  1102. var newProto = {
  1103. notify: function () {
  1104. $emit.call(this.$up, this.$pathname)
  1105. },
  1106. set: function (index, val) {
  1107. if (((index >>> 0) === index) && this[index] !== val) {
  1108. if (index > this.length) {
  1109. throw Error(index + "set方法的第一个参数不能大于原数组长度")
  1110. }
  1111. $emit.call(this.$up, this.$pathname + ".*", [val, this[index]])
  1112. this.splice(index, 1, val)
  1113. }
  1114. },
  1115. contains: function (el) { //判定是否包含
  1116. return this.indexOf(el) !== -1
  1117. },
  1118. ensure: function (el) {
  1119. if (!this.contains(el)) { //只有不存在才push
  1120. this.push(el)
  1121. }
  1122. return this
  1123. },
  1124. pushArray: function (arr) {
  1125. return this.push.apply(this, arr)
  1126. },
  1127. remove: function (el) { //移除第一个等于给定值的元素
  1128. return this.removeAt(this.indexOf(el))
  1129. },
  1130. removeAt: function (index) { //移除指定索引上的元素
  1131. if ((index >>> 0) === index) {
  1132. return this.splice(index, 1)
  1133. }
  1134. return []
  1135. },
  1136. size: function () { //取得数组长度,这个函数可以同步视图,length不能
  1137. return this._.length
  1138. },
  1139. removeAll: function (all) { //移除N个元素
  1140. if (Array.isArray(all)) {
  1141. for (var i = this.length - 1; i >= 0; i--) {
  1142. if (all.indexOf(this[i]) !== -1) {
  1143. _splice.call(this.$track, i, 1)
  1144. _splice.call(this, i, 1)
  1145. }
  1146. }
  1147. } else if (typeof all === "function") {
  1148. for (i = this.length - 1; i >= 0; i--) {
  1149. var el = this[i]
  1150. if (all(el, i)) {
  1151. _splice.call(this.$track, i, 1)
  1152. _splice.call(this, i, 1)
  1153. }
  1154. }
  1155. } else {
  1156. _splice.call(this.$track, 0, this.length)
  1157. _splice.call(this, 0, this.length)
  1158. }
  1159. if (!W3C) {
  1160. this.$model = toJson(this)
  1161. }
  1162. this.notify()
  1163. this._.length = this.length
  1164. },
  1165. clear: function () {
  1166. return this.removeAll()
  1167. }
  1168. }
  1169. var _splice = arrayProto.splice
  1170. arrayMethods.forEach(function (method) {
  1171. var original = arrayProto[method]
  1172. newProto[method] = function () {
  1173. // 继续尝试劫持数组元素的属性
  1174. var args = []
  1175. for (var i = 0, n = arguments.length; i < n; i++) {
  1176. args[i] = observe(arguments[i], 0, 1, 1)
  1177. }
  1178. var result = original.apply(this, args)
  1179. addTrack(this.$track, method, args)
  1180. if (!W3C) {
  1181. this.$model = toJson(this)
  1182. }
  1183. this.notify()
  1184. this._.length = this.length
  1185. return result
  1186. }
  1187. })
  1188. "sort,reverse".replace(rword, function (method) {
  1189. newProto[method] = function () {
  1190. var oldArray = this.concat() //保持原来状态的旧数组
  1191. var newArray = this
  1192. var mask = Math.random()
  1193. var indexes = []
  1194. var hasSort = false
  1195. arrayProto[method].apply(newArray, arguments) //排序
  1196. for (var i = 0, n = oldArray.length; i < n; i++) {
  1197. var neo = newArray[i]
  1198. var old = oldArray[i]
  1199. if (neo === old) {
  1200. indexes.push(i)
  1201. } else {
  1202. var index = oldArray.indexOf(neo)
  1203. indexes.push(index)//得到新数组的每个元素在旧数组对应的位置
  1204. oldArray[index] = mask //屏蔽已经找过的元素
  1205. hasSort = true
  1206. }
  1207. }
  1208. if (hasSort) {
  1209. sortByIndex(this.$track, indexes)
  1210. if (!W3C) {
  1211. this.$model = toJson(this)
  1212. }
  1213. this.notify()
  1214. }
  1215. return this
  1216. }
  1217. })
  1218. function sortByIndex(array, indexes) {
  1219. var map = {};
  1220. for (var i = 0, n = indexes.length; i < n; i++) {
  1221. map[i] = array[i]
  1222. var j = indexes[i]
  1223. if (j in map) {
  1224. array[i] = map[j]
  1225. delete map[j]
  1226. } else {
  1227. array[i] = array[j]
  1228. }
  1229. }
  1230. }
  1231. function createTrack(n) {
  1232. var ret = []
  1233. for (var i = 0; i < n; i++) {
  1234. ret[i] = generateID("$proxy$each")
  1235. }
  1236. return ret
  1237. }
  1238. function addTrack(track, method, args) {
  1239. switch (method) {
  1240. case 'push':
  1241. case 'unshift':
  1242. args = createTrack(args.length)
  1243. break
  1244. case 'splice':
  1245. if (args.length > 2) {
  1246. // 0, 5, a, b, c --> 0, 2, 0
  1247. // 0, 5, a, b, c, d, e, f, g--> 0, 0, 3
  1248. var del = args[1]
  1249. var add = args.length - 2
  1250. // args = [args[0], Math.max(del - add, 0)].concat(createTrack(Math.max(add - del, 0)))
  1251. args = [args[0], args[1]].concat(createTrack(args.length - 2))
  1252. }
  1253. break
  1254. }
  1255. Array.prototype[method].apply(track, args)
  1256. }
  1257. /*********************************************************************
  1258. * 依赖调度系统 *
  1259. **********************************************************************/
  1260. //检测两个对象间的依赖关系
  1261. var dependencyDetection = (function () {
  1262. var outerFrames = []
  1263. var currentFrame
  1264. return {
  1265. begin: function (binding) {
  1266. //accessorObject为一个拥有callback的对象
  1267. outerFrames.push(currentFrame)
  1268. currentFrame = binding
  1269. },
  1270. end: function () {
  1271. currentFrame = outerFrames.pop()
  1272. },
  1273. collectDependency: function (array) {
  1274. if (currentFrame) {
  1275. //被dependencyDetection.begin调用
  1276. currentFrame.callback(array)
  1277. }
  1278. }
  1279. };
  1280. })()
  1281. //将绑定对象注入到其依赖项的订阅数组中
  1282. var roneval = /^on$/
  1283. function returnRandom() {
  1284. return new Date() - 0
  1285. }
  1286. avalon.injectBinding = function (binding) {
  1287. binding.handler = binding.handler || directives[binding.type].update || noop
  1288. binding.update = function () {
  1289. var begin = false
  1290. if (!binding.getter) {
  1291. begin = true
  1292. dependencyDetection.begin({
  1293. callback: function (array) {
  1294. injectDependency(array, binding)
  1295. }
  1296. })
  1297. binding.getter = parseExpr(binding.expr, binding.vmodels, binding)
  1298. binding.observers.forEach(function (a) {
  1299. a.v.$watch(a.p, binding)
  1300. })
  1301. delete binding.observers
  1302. }
  1303. try {
  1304. var args = binding.fireArgs, a, b
  1305. delete binding.fireArgs
  1306. if (!args) {
  1307. if (binding.type === "on") {
  1308. a = binding.getter + ""
  1309. } else {
  1310. a = binding.getter.apply(0, binding.args)
  1311. }
  1312. } else {
  1313. a = args[0]
  1314. b = args[1]
  1315. }
  1316. b = typeof b === "undefined" ? binding.oldValue : b
  1317. if (binding._filters) {
  1318. a = filters.$filter.apply(0, [a].concat(binding._filters))
  1319. }
  1320. if (binding.signature) {
  1321. var xtype = avalon.type(a)
  1322. if (xtype !== "array" && xtype !== "object") {
  1323. throw Error("warning:" + binding.expr + "只能是对象或数组")
  1324. }
  1325. binding.xtype = xtype
  1326. var vtrack = getProxyIds(binding.proxies || [], xtype)
  1327. var mtrack = a.$track || (xtype === "array" ? createTrack(a.length) :
  1328. Object.keys(a))
  1329. binding.track = mtrack
  1330. if (vtrack !== mtrack.join(";")) {
  1331. binding.handler(a, b)
  1332. binding.oldValue = 1
  1333. }
  1334. } else if (Array.isArray(a) ? a.length !== (b && b.length) : false) {
  1335. binding.handler(a, b)
  1336. binding.oldValue = a.concat()
  1337. } else if (!("oldValue" in binding) || a !== b) {
  1338. binding.handler(a, b)
  1339. binding.oldValue = a
  1340. }
  1341. } catch (e) {
  1342. delete binding.getter
  1343. log("warning:exception throwed in [avalon.injectBinding] ", e)
  1344. var node = binding.element
  1345. if (node && node.nodeType === 3) {
  1346. node.nodeValue = openTag + (binding.oneTime ? "::" : "") + binding.expr + closeTag
  1347. }
  1348. } finally {
  1349. begin && dependencyDetection.end()
  1350. }
  1351. }
  1352. binding.update()
  1353. }
  1354. //将依赖项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组
  1355. function injectDependency(list, binding) {
  1356. if (binding.oneTime)
  1357. return
  1358. if (list && avalon.Array.ensure(list, binding) && binding.element) {
  1359. injectDisposeQueue(binding, list)
  1360. if (new Date() - beginTime > 444) {
  1361. rejectDisposeQueue()
  1362. }
  1363. }
  1364. }
  1365. function getProxyIds(a, isArray) {
  1366. var ret = []
  1367. for (var i = 0, el; el = a[i++]; ) {
  1368. ret.push(isArray ? el.$id : el.$key)
  1369. }
  1370. return ret.join(";")
  1371. }
  1372. /*********************************************************************
  1373. * 定时GC回收机制 *
  1374. **********************************************************************/
  1375. var disposeCount = 0
  1376. var disposeQueue = avalon.$$subscribers = []
  1377. var beginTime = new Date()
  1378. var oldInfo = {}
  1379. function getUid(data) { //IE9+,标准浏览器
  1380. if (!data.uniqueNumber) {
  1381. var elem = data.element
  1382. if (elem) {
  1383. if (elem.nodeType !== 1) {
  1384. //如果是注释节点,则data.pos不存在,当一个元素下有两个注释节点就会出问题
  1385. data.uniqueNumber = data.type + "-" + getUid(elem.parentNode) + "-" + (++disposeCount)
  1386. } else {
  1387. data.uniqueNumber = data.name + "-" + getUid(elem)
  1388. }
  1389. } else {
  1390. data.uniqueNumber = ++disposeCount
  1391. }
  1392. }
  1393. return data.uniqueNumber
  1394. }
  1395. //添加到回收列队中
  1396. function injectDisposeQueue(data, list) {
  1397. var lists = data.lists || (data.lists = [])
  1398. var uuid = getUid(data)
  1399. avalon.Array.ensure(lists, list)
  1400. list.$uuid = list.$uuid || generateID()
  1401. if (!disposeQueue[uuid]) {
  1402. disposeQueue[uuid] = 1
  1403. disposeQueue.push(data)
  1404. }
  1405. }
  1406. function rejectDisposeQueue(data) {
  1407. var i = disposeQueue.length
  1408. var n = i
  1409. var allTypes = []
  1410. var iffishTypes = {}
  1411. var newInfo = {}
  1412. //对页面上所有绑定对象进行分门别类, 只检测个数发生变化的类型
  1413. while (data = disposeQueue[--i]) {
  1414. var type = data.type
  1415. if (newInfo[type]) {
  1416. newInfo[type]++
  1417. } else {
  1418. newInfo[type] = 1
  1419. allTypes.push(type)
  1420. }
  1421. }
  1422. var diff = false
  1423. allTypes.forEach(function (type) {
  1424. if (oldInfo[type] !== newInfo[type]) {
  1425. iffishTypes[type] = 1
  1426. diff = true
  1427. }
  1428. })
  1429. i = n
  1430. if (diff) {
  1431. while (data = disposeQueue[--i]) {
  1432. if (data.element === null) {
  1433. disposeQueue.splice(i, 1)
  1434. continue
  1435. }
  1436. if (iffishTypes[data.type] && shouldDispose(data.element)) { //如果它没有在DOM树
  1437. disposeQueue.splice(i, 1)
  1438. delete disposeQueue[data.uniqueNumber]
  1439. var lists = data.lists
  1440. for (var k = 0, list; list = lists[k++]; ) {
  1441. avalon.Array.remove(lists, list)
  1442. avalon.Array.remove(list, data)
  1443. }
  1444. disposeData(data)
  1445. }
  1446. }
  1447. }
  1448. oldInfo = newInfo
  1449. beginTime = new Date()
  1450. }
  1451. function disposeData(data) {
  1452. delete disposeQueue[data.uniqueNumber] // 先清除,不然无法回收了
  1453. data.element = null
  1454. data.rollback && data.rollback()
  1455. for (var key in data) {
  1456. data[key] = null
  1457. }
  1458. }
  1459. function shouldDispose(el) {
  1460. try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错
  1461. var fireError = el.parentNode.nodeType
  1462. } catch (e) {
  1463. return true
  1464. }
  1465. if (el.ifRemove) {
  1466. // 如果节点被放到ifGroup,才移除
  1467. if (!root.contains(el.ifRemove) && (ifGroup === el.parentNode)) {
  1468. el.parentNode && el.parentNode.removeChild(el)
  1469. return true
  1470. }
  1471. }
  1472. return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !avalon.contains(root, el))
  1473. }
  1474. /************************************************************************
  1475. * HTML处理(parseHTML, innerHTML, clearHTML) *
  1476. **************************************************************************/
  1477. //parseHTML的辅助变量
  1478. var tagHooks = new function() {// jshint ignore:line
  1479. avalon.mix(this, {
  1480. option: DOC.createElement("select"),
  1481. thead: DOC.createElement("table"),
  1482. td: DOC.createElement("tr"),
  1483. area: DOC.createElement("map"),
  1484. tr: DOC.createElement("tbody"),
  1485. col: DOC.createElement("colgroup"),
  1486. legend: DOC.createElement("fieldset"),
  1487. _default: DOC.createElement("div"),
  1488. "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg")
  1489. })
  1490. this.optgroup = this.option
  1491. this.tbody = this.tfoot = this.colgroup = this.caption = this.thead
  1492. this.th = this.td
  1493. }// jshint ignore:line
  1494. String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) {
  1495. tagHooks[tag] = tagHooks.g //处理SVG
  1496. })
  1497. var rtagName = /<([\w:]+)/
  1498. var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
  1499. var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"])
  1500. var script = DOC.createElement("script")
  1501. var rhtml = /<|&#?\w+;/
  1502. avalon.parseHTML = function(html) {
  1503. var fragment = avalonFragment.cloneNode(false)
  1504. if (typeof html !== "string" ) {
  1505. return fragment
  1506. }
  1507. if (!rhtml.test(html)) {
  1508. fragment.appendChild(DOC.createTextNode(html))
  1509. return fragment
  1510. }
  1511. html = html.replace(rxhtml, "<$1></$2>").trim()
  1512. var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(),
  1513. //取得其标签名
  1514. wrapper = tagHooks[tag] || tagHooks._default,
  1515. firstChild
  1516. wrapper.innerHTML = html
  1517. var els = wrapper.getElementsByTagName("script")
  1518. if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性
  1519. for (var i = 0, el; el = els[i++]; ) {
  1520. if (scriptTypes[el.type]) {
  1521. var neo = script.cloneNode(false) //FF不能省略参数
  1522. ap.forEach.call(el.attributes, function(attr) {
  1523. neo.setAttribute(attr.name, attr.value)
  1524. })// jshint ignore:line
  1525. neo.text = el.text
  1526. el.parentNode.replaceChild(neo, el)
  1527. }
  1528. }
  1529. }
  1530. while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上!
  1531. fragment.appendChild(firstChild)
  1532. }
  1533. return fragment
  1534. }
  1535. avalon.innerHTML = function(node, html) {
  1536. var a = this.parseHTML(html)
  1537. this.clearHTML(node).appendChild(a)
  1538. }
  1539. avalon.clearHTML = function(node) {
  1540. node.textContent = ""
  1541. while (node.firstChild) {
  1542. node.removeChild(node.firstChild)
  1543. }
  1544. return node
  1545. }
  1546. /*********************************************************************
  1547. * avalon的原型方法定义区 *
  1548. **********************************************************************/
  1549. function hyphen(target) {
  1550. //转换为连字符线风格
  1551. return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase()
  1552. }
  1553. function camelize(target) {
  1554. //转换为驼峰风格
  1555. if (target.indexOf("-") < 0 && target.indexOf("_") < 0) {
  1556. return target //提前判断,提高getStyle等的效率
  1557. }
  1558. return target.replace(/[-_][^-_]/g, function (match) {
  1559. return match.charAt(1).toUpperCase()
  1560. })
  1561. }
  1562. "add,remove".replace(rword, function (method) {
  1563. avalon.fn[method + "Class"] = function (cls) {
  1564. var el = this[0]
  1565. //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26
  1566. if (cls && typeof cls === "string" && el && el.nodeType === 1) {
  1567. cls.replace(/\S+/g, function (c) {
  1568. el.classList[method](c)
  1569. })
  1570. }
  1571. return this
  1572. }
  1573. })
  1574. avalon.fn.mix({
  1575. hasClass: function (cls) {
  1576. var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0
  1577. return el.nodeType === 1 && el.classList.contains(cls)
  1578. },
  1579. toggleClass: function (value, stateVal) {
  1580. var className, i = 0
  1581. var classNames = String(value).split(/\s+/)
  1582. var isBool = typeof stateVal === "boolean"
  1583. while ((className = classNames[i++])) {
  1584. var state = isBool ? stateVal : !this.hasClass(className)
  1585. this[state ? "addClass" : "removeClass"](className)
  1586. }
  1587. return this
  1588. },
  1589. attr: function (name, value) {
  1590. if (arguments.length === 2) {
  1591. this[0].setAttribute(name, value)
  1592. return this
  1593. } else {
  1594. return this[0].getAttribute(name)
  1595. }
  1596. },
  1597. data: function (name, value) {
  1598. name = "data-" + hyphen(name || "")
  1599. switch (arguments.length) {
  1600. case 2:
  1601. this.attr(name, value)
  1602. return this
  1603. case 1:
  1604. var val = this.attr(name)
  1605. return parseData(val)
  1606. case 0:
  1607. var ret = {}
  1608. ap.forEach.call(this[0].attributes, function (attr) {
  1609. if (attr) {
  1610. name = attr.name
  1611. if (!name.indexOf("data-")) {
  1612. name = camelize(name.slice(5))
  1613. ret[name] = parseData(attr.value)
  1614. }
  1615. }
  1616. })
  1617. return ret
  1618. }
  1619. },
  1620. removeData: function (name) {
  1621. name = "data-" + hyphen(name)
  1622. this[0].removeAttribute(name)
  1623. return this
  1624. },
  1625. css: function (name, value) {
  1626. if (avalon.isPlainObject(name)) {
  1627. for (var i in name) {
  1628. avalon.css(this, i, name[i])
  1629. }
  1630. } else {
  1631. var ret = avalon.css(this, name, value)
  1632. }
  1633. return ret !== void 0 ? ret : this
  1634. },
  1635. position: function () {
  1636. var offsetParent, offset,
  1637. elem = this[0],
  1638. parentOffset = {
  1639. top: 0,
  1640. left: 0
  1641. };
  1642. if (!elem) {
  1643. return
  1644. }
  1645. if (this.css("position") === "fixed") {
  1646. offset = elem.getBoundingClientRect()
  1647. } else {
  1648. offsetParent = this.offsetParent() //得到真正的offsetParent
  1649. offset = this.offset() // 得到正确的offsetParent
  1650. if (offsetParent[0].tagName !== "HTML") {
  1651. parentOffset = offsetParent.offset()
  1652. }
  1653. parentOffset.top += avalon.css(offsetParent[0], "borderTopWidth", true)
  1654. parentOffset.left += avalon.css(offsetParent[0], "borderLeftWidth", true)
  1655. // Subtract offsetParent scroll positions
  1656. parentOffset.top -= offsetParent.scrollTop()
  1657. parentOffset.left -= offsetParent.scrollLeft()
  1658. }
  1659. return {
  1660. top: offset.top - parentOffset.top - avalon.css(elem, "marginTop", true),
  1661. left: offset.left - parentOffset.left - avalon.css(elem, "marginLeft", true)
  1662. }
  1663. },
  1664. offsetParent: function () {
  1665. var offsetParent = this[0].offsetParent
  1666. while (offsetParent && avalon.css(offsetParent, "position") === "static") {
  1667. offsetParent = offsetParent.offsetParent;
  1668. }
  1669. return avalon(offsetParent || root)
  1670. },
  1671. bind: function (type, fn, phase) {
  1672. if (this[0]) { //此方法不会链
  1673. return avalon.bind(this[0], type, fn, phase)
  1674. }
  1675. },
  1676. unbind: function (type, fn, phase) {
  1677. if (this[0]) {
  1678. avalon.unbind(this[0], type, fn, phase)
  1679. }
  1680. return this
  1681. },
  1682. val: function (value) {
  1683. var node = this[0]
  1684. if (node && node.nodeType === 1) {
  1685. var get = arguments.length === 0
  1686. var access = get ? ":get" : ":set"
  1687. var fn = valHooks[getValType(node) + access]
  1688. if (fn) {
  1689. var val = fn(node, value)
  1690. } else if (get) {
  1691. return (node.value || "").replace(/\r/g, "")
  1692. } else {
  1693. node.value = value
  1694. }
  1695. }
  1696. return get ? val : this
  1697. }
  1698. })
  1699. if (root.dataset) {
  1700. avalon.fn.data = function (name, val) {
  1701. name = name && camelize(name)
  1702. var dataset = this[0].dataset
  1703. switch (arguments.length) {
  1704. case 2:
  1705. dataset[name] = val
  1706. return this
  1707. case 1:
  1708. val = dataset[name]
  1709. return parseData(val)
  1710. case 0:
  1711. var ret = createMap()
  1712. for (name in dataset) {
  1713. ret[name] = parseData(dataset[name])
  1714. }
  1715. return ret
  1716. }
  1717. }
  1718. }
  1719. var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/
  1720. avalon.parseJSON = JSON.parse
  1721. function parseData(data) {
  1722. try {
  1723. if (typeof data === "object")
  1724. return data
  1725. data = data === "true" ? true :
  1726. data === "false" ? false :
  1727. data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data
  1728. } catch (e) {
  1729. }
  1730. return data
  1731. }
  1732. avalon.fireDom = function (elem, type, opts) {
  1733. var hackEvent = DOC.createEvent("Events");
  1734. hackEvent.initEvent(type, true, true)
  1735. avalon.mix(hackEvent, opts)
  1736. elem.dispatchEvent(hackEvent)
  1737. }
  1738. avalon.each({
  1739. scrollLeft: "pageXOffset",
  1740. scrollTop: "pageYOffset"
  1741. }, function (method, prop) {
  1742. avalon.fn[method] = function (val) {
  1743. var node = this[0] || {},
  1744. win = getWindow(node),
  1745. top = method === "scrollTop"
  1746. if (!arguments.length) {
  1747. return win ? win[prop] : node[method]
  1748. } else {
  1749. if (win) {
  1750. win.scrollTo(!top ? val : win[prop], top ? val : win[prop])
  1751. } else {
  1752. node[method] = val
  1753. }
  1754. }
  1755. }
  1756. })
  1757. function getWindow(node) {
  1758. return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false
  1759. }
  1760. //=============================css相关==================================
  1761. var cssHooks = avalon.cssHooks = createMap()
  1762. var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15的支持
  1763. var cssMap = {
  1764. "float": "cssFloat"
  1765. }
  1766. avalon.cssNumber = oneObject("animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom")
  1767. avalon.cssName = function (name, host, camelCase) {
  1768. if (cssMap[name]) {
  1769. return cssMap[name]
  1770. }
  1771. host = host || root.style
  1772. for (var i = 0, n = prefixes.length; i < n; i++) {
  1773. camelCase = camelize(prefixes[i] + name)
  1774. if (camelCase in host) {
  1775. return (cssMap[name] = camelCase)
  1776. }
  1777. }
  1778. return null
  1779. }
  1780. cssHooks["@:set"] = function (node, name, value) {
  1781. node.style[name] = value
  1782. }
  1783. cssHooks["@:get"] = function (node, name) {
  1784. if (!node || !node.style) {
  1785. throw new Error("getComputedStyle要求传入一个节点 " + node)
  1786. }
  1787. var ret, computed = getComputedStyle(node)
  1788. if (computed) {
  1789. ret = name === "filter" ? computed.getPropertyValue(name) : computed[name]
  1790. if (ret === "") {
  1791. ret = node.style[name] //其他浏览器需要我们手动取内联样式
  1792. }
  1793. }
  1794. return ret
  1795. }
  1796. cssHooks["opacity:get"] = function (node) {
  1797. var ret = cssHooks["@:get"](node, "opacity")
  1798. return ret === "" ? "1" : ret
  1799. }
  1800. "top,left".replace(rword, function (name) {
  1801. cssHooks[name + ":get"] = function (node) {
  1802. var computed = cssHooks["@:get"](node, name)
  1803. return /px$/.test(computed) ? computed :
  1804. avalon(node).position()[name] + "px"
  1805. }
  1806. })
  1807. var cssShow = {
  1808. position: "absolute",
  1809. visibility: "hidden",
  1810. display: "block"
  1811. }
  1812. var rdisplayswap = /^(none|table(?!-c[ea]).+)/
  1813. function showHidden(node, array) {
  1814. //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html
  1815. if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0
  1816. var styles = getComputedStyle(node, null)
  1817. if (rdisplayswap.test(styles["display"])) {
  1818. var obj = {
  1819. node: node
  1820. }
  1821. for (var name in cssShow) {
  1822. obj[name] = styles[name]
  1823. node.style[name] = cssShow[name]
  1824. }
  1825. array.push(obj)
  1826. }
  1827. var parent = node.parentNode
  1828. if (parent && parent.nodeType === 1) {
  1829. showHidden(parent, array)
  1830. }
  1831. }
  1832. }
  1833. "Width,Height".replace(rword, function (name) { //fix 481
  1834. var method = name.toLowerCase(),
  1835. clientProp = "client" + name,
  1836. scrollProp = "scroll" + name,
  1837. offsetProp = "offset" + name
  1838. cssHooks[method + ":get"] = function (node, which, override) {
  1839. var boxSizing = -4
  1840. if (typeof override === "number") {
  1841. boxSizing = override
  1842. }
  1843. which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"]
  1844. var ret = node[offsetProp] // border-box 0
  1845. if (boxSizing === 2) { // margin-box 2
  1846. return ret + avalon.css(node, "margin" + which[0], true) + avalon.css(node, "margin" + which[1], true)
  1847. }
  1848. if (boxSizing < 0) { // padding-box -2
  1849. ret = ret - avalon.css(node, "border" + which[0] + "Width", true) - avalon.css(node, "border" + which[1] + "Width", true)
  1850. }
  1851. if (boxSizing === -4) { // content-box -4
  1852. ret = ret - avalon.css(node, "padding" + which[0], true) - avalon.css(node, "padding" + which[1], true)
  1853. }
  1854. return ret
  1855. }
  1856. cssHooks[method + "&get"] = function (node) {
  1857. var hidden = [];
  1858. showHidden(node, hidden);
  1859. var val = cssHooks[method + ":get"](node)
  1860. for (var i = 0, obj; obj = hidden[i++]; ) {
  1861. node = obj.node
  1862. for (var n in obj) {
  1863. if (typeof obj[n] === "string") {
  1864. node.style[n] = obj[n]
  1865. }
  1866. }
  1867. }
  1868. return val;
  1869. }
  1870. avalon.fn[method] = function (value) { //会忽视其display
  1871. var node = this[0]
  1872. if (arguments.length === 0) {
  1873. if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替
  1874. return node["inner" + name]
  1875. }
  1876. if (node.nodeType === 9) { //取得页面尺寸
  1877. var doc = node.documentElement
  1878. //FF chrome html.scrollHeight< body.scrollHeight
  1879. //IE 标准模式 : html.scrollHeight> body.scrollHeight
  1880. //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点?
  1881. return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp])
  1882. }
  1883. return cssHooks[method + "&get"](node)
  1884. } else {
  1885. return this.css(method, value)
  1886. }
  1887. }
  1888. avalon.fn["inner" + name] = function () {
  1889. return cssHooks[method + ":get"](this[0], void 0, -2)
  1890. }
  1891. avalon.fn["outer" + name] = function (includeMargin) {
  1892. return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0)
  1893. }
  1894. })
  1895. avalon.fn.offset = function () { //取得距离页面左右角的坐标
  1896. var node = this[0]
  1897. try {
  1898. var rect = node.getBoundingClientRect()
  1899. // Make sure element is not hidden (display: none) or disconnected
  1900. // https://github.com/jquery/jquery/pull/2043/files#r23981494
  1901. if (rect.width || rect.height || node.getClientRects().length) {
  1902. var doc = node.ownerDocument
  1903. var root = doc.documentElement
  1904. var win = doc.defaultView
  1905. return {
  1906. top: rect.top + win.pageYOffset - root.clientTop,
  1907. left: rect.left + win.pageXOffset - root.clientLeft
  1908. }
  1909. }
  1910. } catch (e) {
  1911. return {
  1912. left: 0,
  1913. top: 0
  1914. }
  1915. }
  1916. }
  1917. //=============================val相关=======================
  1918. function getValType(elem) {
  1919. var ret = elem.tagName.toLowerCase()
  1920. return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret
  1921. }
  1922. var valHooks = {
  1923. "select:get": function (node, value) {
  1924. var option, options = node.options,
  1925. index = node.selectedIndex,
  1926. one = node.type === "select-one" || index < 0,
  1927. values = one ? null : [],
  1928. max = one ? index + 1 : options.length,
  1929. i = index < 0 ? max : one ? index : 0
  1930. for (; i < max; i++) {
  1931. option = options[i]
  1932. //旧式IE在reset后不会改变selected,需要改用i === index判定
  1933. //我们过滤所有disabled的option元素,但在safari5下,如果设置select为disable,那么其所有孩子都disable
  1934. //因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况
  1935. if ((option.selected || i === index) && !option.disabled) {
  1936. value = option.value
  1937. if (one) {
  1938. return value
  1939. }
  1940. //收集所有selected值组成数组返回
  1941. values.push(value)
  1942. }
  1943. }
  1944. return values
  1945. },
  1946. "select:set": function (node, values, optionSet) {
  1947. values = [].concat(values) //强制转换为数组
  1948. for (var i = 0, el; el = node.options[i++]; ) {
  1949. if ((el.selected = values.indexOf(el.value) > -1)) {
  1950. optionSet = true
  1951. }
  1952. }
  1953. if (!optionSet) {
  1954. node.selectedIndex = -1
  1955. }
  1956. }
  1957. }
  1958. var keyMap = {}
  1959. var keys = ["break,case,catch,continue,debugger,default,delete,do,else,false",
  1960. "finally,for,function,if,in,instanceof,new,null,return,switch,this",
  1961. "throw,true,try,typeof,var,void,while,with", /* 关键字*/
  1962. "abstract,boolean,byte,char,class,const,double,enum,export,extends",
  1963. "final,float,goto,implements,import,int,interface,long,native",
  1964. "package,private,protected,public,short,static,super,synchronized",
  1965. "throws,transient,volatile", /*保留字*/
  1966. "arguments,let,yield,undefined"].join(",")
  1967. keys.replace(/\w+/g, function (a) {
  1968. keyMap[a] = true
  1969. })
  1970. var ridentStart = /[a-z_$]/i
  1971. var rwhiteSpace = /[\s\uFEFF\xA0]/
  1972. function getIdent(input, lastIndex) {
  1973. var result = []
  1974. var subroutine = !!lastIndex
  1975. lastIndex = lastIndex || 0
  1976. //将表达式中的标识符抽取出来
  1977. var state = "unknown"
  1978. var variable = ""
  1979. for (var i = 0; i < input.length; i++) {
  1980. var c = input.charAt(i)
  1981. if (c === "'" || c === '"') {//字符串开始
  1982. if (state === "unknown") {
  1983. state = c
  1984. } else if (state === c) {//字符串结束
  1985. state = "unknown"
  1986. }
  1987. } else if (c === "\\") {
  1988. if (state === "'" || state === '"') {
  1989. i++
  1990. }
  1991. } else if (ridentStart.test(c)) {//碰到标识符
  1992. if (state === "unknown") {
  1993. state = "variable"
  1994. variable = c
  1995. } else if (state === "maybePath") {
  1996. variable = result.pop()
  1997. variable += "." + c
  1998. state = "variable"
  1999. } else if (state === "variable") {
  2000. variable += c
  2001. }
  2002. } else if (/\w/.test(c)) {
  2003. if (state === "variable") {
  2004. variable += c
  2005. }
  2006. } else if (c === ".") {
  2007. if (state === "variable") {
  2008. if (variable) {
  2009. result.push(variable)
  2010. variable = ""
  2011. state = "maybePath"
  2012. }
  2013. }
  2014. } else if (c === "[") {
  2015. if (state === "variable" || state === "maybePath") {
  2016. if (variable) {//如果前面存在变量,收集它
  2017. result.push(variable)
  2018. variable = ""
  2019. }
  2020. var lastLength = result.length
  2021. var last = result[lastLength - 1]
  2022. var innerResult = getIdent(input.slice(i), i)
  2023. if (innerResult.length) {//如果括号中存在变量,那么这里添加通配符
  2024. result[lastLength - 1] = last + ".*"
  2025. result = innerResult.concat(result)
  2026. } else { //如果括号中的东西是确定的,直接转换为其子属性
  2027. var content = input.slice(i + 1, innerResult.i)
  2028. try {
  2029. var text = (scpCompile(["return " + content]))()
  2030. result[lastLength - 1] = last + "." + text
  2031. } catch (e) {
  2032. }
  2033. }
  2034. state = "maybePath"//]后面可能还接东西
  2035. i = innerResult.i
  2036. }
  2037. } else if (c === "]") {
  2038. if (subroutine) {
  2039. result.i = i + lastIndex
  2040. addVar(result, variable)
  2041. return result
  2042. }
  2043. } else if (rwhiteSpace.test(c) && c !== "\r" && c !== "\n") {
  2044. if (state === "variable") {
  2045. if (addVar(result, variable)) {
  2046. state = "maybePath" // aaa . bbb 这样的情况
  2047. }
  2048. variable = ""
  2049. }
  2050. } else {
  2051. addVar(result, variable)
  2052. state = "unknown"
  2053. variable = ""
  2054. }
  2055. }
  2056. addVar(result, variable)
  2057. return result
  2058. }
  2059. function addVar(array, element) {
  2060. if (element && !keyMap[element]) {
  2061. array.push(element)
  2062. return true
  2063. }
  2064. }
  2065. function addAssign(vars, vmodel, name, binding) {
  2066. var ret = [],
  2067. prefix = " = " + name + "."
  2068. for (var i = vars.length, prop; prop = vars[--i]; ) {
  2069. var arr = prop.split("."), a
  2070. var first = arr[0]
  2071. while (a = arr.shift()) {
  2072. if (vmodel.hasOwnProperty(a)) {
  2073. ret.push(first + prefix + first)
  2074. binding.observers.push({
  2075. v: vmodel,
  2076. p: prop
  2077. })
  2078. vars.splice(i, 1)
  2079. }
  2080. }
  2081. }
  2082. return ret
  2083. }
  2084. var rproxy = /(\$proxy\$[a-z]+)\d+$/
  2085. var variablePool = new Cache(218)
  2086. //缓存求值函数,以便多次利用
  2087. var evaluatorPool = new Cache(128)
  2088. function getVars(expr) {
  2089. expr = expr.trim()
  2090. var ret = variablePool.get(expr)
  2091. if (ret) {
  2092. return ret.concat()
  2093. }
  2094. var array = getIdent(expr)
  2095. var uniq = {}
  2096. var result = []
  2097. for (var i = 0, el; el = array[i++]; ) {
  2098. if (!uniq[el]) {
  2099. uniq[el] = 1
  2100. result.push(el)
  2101. }
  2102. }
  2103. return variablePool.put(expr, result).concat()
  2104. }
  2105. function parseExpr(expr, vmodels, binding) {
  2106. var filters = binding.filters
  2107. if (typeof filters === "string" && filters.trim() && !binding._filters) {
  2108. binding._filters = parseFilter(filters.trim())
  2109. }
  2110. var vars = getVars(expr)
  2111. var expose = new Date() - 0
  2112. var assigns = []
  2113. var names = []
  2114. var args = []
  2115. binding.observers = []
  2116. for (var i = 0, sn = vmodels.length; i < sn; i++) {
  2117. if (vars.length) {
  2118. var name = "vm" + expose + "_" + i
  2119. names.push(name)
  2120. args.push(vmodels[i])
  2121. assigns.push.apply(assigns, addAssign(vars, vmodels[i], name, binding))
  2122. }
  2123. }
  2124. binding.args = args
  2125. var dataType = binding.type
  2126. var exprId = vmodels.map(function (el) {
  2127. return String(el.$id).replace(rproxy, "$1")
  2128. }) + expr + dataType
  2129. var getter = evaluatorPool.get(exprId) //直接从缓存,免得重复生成
  2130. if (getter) {
  2131. if (dataType === "duplex") {
  2132. var setter = evaluatorPool.get(exprId + "setter")
  2133. binding.setter = setter.apply(setter, binding.args)
  2134. }
  2135. return binding.getter = getter
  2136. }
  2137. if (!assigns.length) {
  2138. assigns.push("fix" + expose)
  2139. }
  2140. if (dataType === "duplex") {
  2141. var nameOne = {}
  2142. assigns.forEach(function (a) {
  2143. var arr = a.split("=")
  2144. nameOne[arr[0].trim()] = arr[1].trim()
  2145. })
  2146. expr = expr.replace(/[\$\w]+/, function (a) {
  2147. return nameOne[a] ? nameOne[a] : a
  2148. })
  2149. /* jshint ignore:start */
  2150. var fn2 = scpCompile(names.concat("'use strict';" +
  2151. "return function(vvv){" + expr + " = vvv\n}\n"))
  2152. /* jshint ignore:end */
  2153. evaluatorPool.put(exprId + "setter", fn2)
  2154. binding.setter = fn2.apply(fn2, binding.args)
  2155. }
  2156. if (dataType === "on") { //事件绑定
  2157. if (expr.indexOf("(") === -1) {
  2158. expr += ".call(this, $event)"
  2159. } else {
  2160. expr = expr.replace("(", ".call(this,")
  2161. }
  2162. names.push("$event")
  2163. expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;")
  2164. var lastIndex = expr.lastIndexOf("\nreturn")
  2165. var header = expr.slice(0, lastIndex)
  2166. var footer = expr.slice(lastIndex)
  2167. expr = header + "\n" + footer
  2168. } else {
  2169. expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;")
  2170. }
  2171. /* jshint ignore:start */
  2172. getter = scpCompile(names.concat("'use strict';\nvar " +
  2173. assigns.join(",\n") + expr))
  2174. /* jshint ignore:end */
  2175. return evaluatorPool.put(exprId, getter)
  2176. }
  2177. //========
  2178. function normalizeExpr(code) {
  2179. var hasExpr = rexpr.test(code) //比如ms-class="width{{w}}"的情况
  2180. if (hasExpr) {
  2181. var array = scanExpr(code)
  2182. if (array.length === 1) {
  2183. return array[0].expr
  2184. }
  2185. return array.map(function (el) {
  2186. return el.type ? "(" + el.expr + ")" : quote(el.expr)
  2187. }).join(" + ")
  2188. } else {
  2189. return code
  2190. }
  2191. }
  2192. avalon.normalizeExpr = normalizeExpr
  2193. avalon.parseExprProxy = parseExpr
  2194. var rthimRightParentheses = /\)\s*$/
  2195. var rthimOtherParentheses = /\)\s*\|/g
  2196. var rquoteFilterName = /\|\s*([$\w]+)/g
  2197. var rpatchBracket = /"\s*\["/g
  2198. var rthimLeftParentheses = /"\s*\(/g
  2199. function parseFilter(filters) {
  2200. filters = filters
  2201. .replace(rthimRightParentheses, "")//处理最后的小括号
  2202. .replace(rthimOtherParentheses, function () {//处理其他小括号
  2203. return "],|"
  2204. })
  2205. .replace(rquoteFilterName, function (a, b) { //处理|及它后面的过滤器的名字
  2206. return "[" + quote(b)
  2207. })
  2208. .replace(rpatchBracket, function () {
  2209. return '"],["'
  2210. })
  2211. .replace(rthimLeftParentheses, function () {
  2212. return '",'
  2213. }) + "]"
  2214. /* jshint ignore:start */
  2215. return scpCompile(["return [" + filters + "]"])()
  2216. /* jshint ignore:end */
  2217. }
  2218. /*********************************************************************
  2219. * 编译系统 *
  2220. **********************************************************************/
  2221. var quote = JSON.stringify
  2222. /*********************************************************************
  2223. * 扫描系统 *
  2224. **********************************************************************/
  2225. avalon.scan = function (elem, vmodel) {
  2226. elem = elem || root
  2227. var vmodels = vmodel ? [].concat(vmodel) : []
  2228. scanTag(elem, vmodels)
  2229. }
  2230. //http://www.w3.org/TR/html5/syntax.html#void-elements
  2231. var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase())
  2232. function checkScan(elem, callback, innerHTML) {
  2233. var id = setTimeout(function () {
  2234. var currHTML = elem.innerHTML
  2235. clearTimeout(id)
  2236. if (currHTML === innerHTML) {
  2237. callback()
  2238. } else {
  2239. checkScan(elem, callback, currHTML)
  2240. }
  2241. })
  2242. }
  2243. function createSignalTower(elem, vmodel) {
  2244. var id = elem.getAttribute("avalonctrl") || vmodel.$id
  2245. elem.setAttribute("avalonctrl", id)
  2246. if (vmodel.$events) {
  2247. vmodel.$events.expr = elem.tagName + '[avalonctrl="' + id + '"]'
  2248. }
  2249. }
  2250. var getBindingCallback = function (elem, name, vmodels) {
  2251. var callback = elem.getAttribute(name)
  2252. if (callback) {
  2253. for (var i = 0, vm; vm = vmodels[i++]; ) {
  2254. if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") {
  2255. return vm[callback]
  2256. }
  2257. }
  2258. }
  2259. }
  2260. function executeBindings(bindings, vmodels) {
  2261. for (var i = 0, binding; binding = bindings[i++]; ) {
  2262. binding.vmodels = vmodels
  2263. directives[binding.type].init(binding)
  2264. avalon.injectBinding(binding)
  2265. if (binding.getter && binding.element.nodeType === 1) { //移除数据绑定,防止被二次解析
  2266. //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/avalon/issues/99
  2267. binding.element.removeAttribute(binding.name)
  2268. }
  2269. }
  2270. bindings.length = 0
  2271. }
  2272. //https://github.com/RubyLouvre/avalon/issues/636
  2273. var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) {
  2274. var node = elem.firstChild, text
  2275. while (node) {
  2276. var aaa = node.nextSibling
  2277. if (node.nodeType === 3) {
  2278. if (text) {
  2279. text.nodeValue += node.nodeValue
  2280. elem.removeChild(node)
  2281. } else {
  2282. text = node
  2283. }
  2284. } else {
  2285. text = null
  2286. }
  2287. node = aaa
  2288. }
  2289. } : 0
  2290. var roneTime = /^\s*::/
  2291. var rmsAttr = /ms-(\w+)-?(.*)/
  2292. var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit")
  2293. var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled,href,src")
  2294. function bindingSorter(a, b) {
  2295. return a.priority - b.priority
  2296. }
  2297. var rnoCollect = /^(ms-\S+|data-\S+|on[a-z]+|id|style|class)$/
  2298. var ronattr = /^on\-[\w-]+$/
  2299. function getOptionsFromTag(elem, vmodels) {
  2300. var attributes = elem.attributes
  2301. var ret = {}
  2302. for (var i = 0, attr; attr = attributes[i++]; ) {
  2303. var name = attr.name
  2304. if (attr.specified && !rnoCollect.test(name)) {
  2305. var camelizeName = camelize(attr.name)
  2306. if (/^on\-[\w-]+$/.test(name)) {
  2307. ret[camelizeName] = getBindingCallback(elem, name, vmodels)
  2308. } else {
  2309. ret[camelizeName] = parseData(attr.value)
  2310. }
  2311. }
  2312. }
  2313. return ret
  2314. }
  2315. function scanAttr(elem, vmodels, match) {
  2316. var scanNode = true
  2317. if (vmodels.length) {
  2318. var attributes = elem.attributes
  2319. var bindings = []
  2320. var uniq = {}
  2321. for (var i = 0, attr; attr = attributes[i++]; ) {
  2322. var name = attr.name
  2323. if (uniq[name]) {//IE8下ms-repeat,ms-with BUG
  2324. continue
  2325. }
  2326. uniq[name] = 1
  2327. if (attr.specified) {
  2328. if (match = name.match(rmsAttr)) {
  2329. //如果是以指定前缀命名的
  2330. var type = match[1]
  2331. var param = match[2] || ""
  2332. var value = attr.value
  2333. if (events[type]) {
  2334. param = type
  2335. type = "on"
  2336. } else if (obsoleteAttrs[type]) {
  2337. param = type
  2338. type = "attr"
  2339. name = "ms-" + type + "-" + param
  2340. log("warning!请改用" + name + "代替" + attr.name + "!")
  2341. }
  2342. if (directives[type]) {
  2343. var newValue = value.replace(roneTime, "")
  2344. var oneTime = value !== newValue
  2345. var binding = {
  2346. type: type,
  2347. param: param,
  2348. element: elem,
  2349. name: name,
  2350. expr: newValue,
  2351. oneTime: oneTime,
  2352. priority: (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, "")) || 0)
  2353. }
  2354. if (type === "html" || type === "text") {
  2355. var filters = getToken(value).filters
  2356. binding.expr = binding.expr.replace(filters, "")
  2357. binding.filters = filters.replace(rhasHtml, function () {
  2358. binding.type = "html"
  2359. binding.group = 1
  2360. return ""
  2361. }).trim() // jshint ignore:line
  2362. } else if (type === "duplex") {
  2363. var hasDuplex = name
  2364. } else if (name === "ms-if-loop") {
  2365. binding.priority += 100
  2366. } else if (name === "ms-attr-value") {
  2367. var hasAttrValue = name
  2368. }
  2369. bindings.push(binding)
  2370. }
  2371. }
  2372. }
  2373. }
  2374. if (bindings.length) {
  2375. bindings.sort(bindingSorter)
  2376. if (hasDuplex && hasAttrValue && elem.type === "text") {
  2377. log("warning!一个控件不能同时定义ms-attr-value与" + hasDuplex)
  2378. }
  2379. for (i = 0; binding = bindings[i]; i++) {
  2380. type = binding.type
  2381. if (rnoscanAttrBinding.test(type)) {
  2382. return executeBindings(bindings.slice(0, i + 1), vmodels)
  2383. } else if (scanNode) {
  2384. scanNode = !rnoscanNodeBinding.test(type)
  2385. }
  2386. }
  2387. executeBindings(bindings, vmodels)
  2388. }
  2389. }
  2390. if (scanNode && !stopScan[elem.tagName]) {
  2391. mergeTextNodes && mergeTextNodes(elem)
  2392. scanNodeList(elem, vmodels) //扫描子孙元素
  2393. }
  2394. }
  2395. var rnoscanAttrBinding = /^if|widget|repeat$/
  2396. var rnoscanNodeBinding = /^each|with|html|include$/
  2397. function scanNodeList(parent, vmodels) {
  2398. var nodes = avalon.slice(parent.childNodes)
  2399. scanNodeArray(nodes, vmodels)
  2400. }
  2401. function scanNodeArray(nodes, vmodels) {
  2402. for (var i = 0, node; node = nodes[i++]; ) {
  2403. switch (node.nodeType) {
  2404. case 1:
  2405. var elem = node
  2406. if (!elem.msResolved && elem.parentNode && elem.parentNode.nodeType === 1) {
  2407. var library = isWidget(elem)
  2408. if (library) {
  2409. var widget = elem.localName ? elem.localName.replace(library + ":", "") : elem.nodeName
  2410. var fullName = library + ":" + camelize(widget)
  2411. componentQueue.push({
  2412. library: library,
  2413. element: elem,
  2414. fullName: fullName,
  2415. widget: widget,
  2416. vmodels: vmodels,
  2417. name: "widget"
  2418. })
  2419. if (avalon.components[fullName]) {
  2420. (function (name) {//确保所有ms-attr-name扫描完再处理
  2421. setTimeout(function () {
  2422. avalon.component(name)
  2423. })
  2424. })(fullName)
  2425. }
  2426. }
  2427. }
  2428. scanTag(node, vmodels) //扫描元素节点
  2429. if (node.msHasEvent) {
  2430. avalon.fireDom(node, "datasetchanged", {
  2431. bubble: node.msHasEvent
  2432. })
  2433. }
  2434. break
  2435. case 3:
  2436. if (rexpr.test(node.nodeValue)) {
  2437. scanText(node, vmodels, i) //扫描文本节点
  2438. }
  2439. break
  2440. }
  2441. }
  2442. }
  2443. function scanTag(elem, vmodels, node) {
  2444. //扫描顺序 ms-skip(0) --> ms-important(1) --> ms-controller(2) --> ms-if(10) --> ms-repeat(100)
  2445. //--> ms-if-loop(110) --> ms-attr(970) ...--> ms-each(1400)-->ms-with(1500)--〉ms-duplex(2000)垫后
  2446. var a = elem.getAttribute("ms-skip")
  2447. var b = elem.getAttributeNode("ms-important")
  2448. var c = elem.getAttributeNode("ms-controller")
  2449. if (typeof a === "string") {
  2450. return
  2451. } else if (node = b || c) {
  2452. var newVmodel = avalon.vmodels[node.value]
  2453. if (!newVmodel) {
  2454. return
  2455. }
  2456. //ms-important不包含父VM,ms-controller相反
  2457. vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels)
  2458. elem.removeAttribute(node.name) //removeAttributeNode不会刷新[ms-controller]样式规则
  2459. elem.classList.remove(node.name)
  2460. createSignalTower(elem, newVmodel)
  2461. }
  2462. scanAttr(elem, vmodels) //扫描特性节点
  2463. if (newVmodel) {
  2464. setTimeout(function () {
  2465. newVmodel.$fire("ms-scan-end", elem)
  2466. })
  2467. }
  2468. }
  2469. var rhasHtml = /\|\s*html(?:\b|$)/,
  2470. r11a = /\|\|/g,
  2471. rlt = /&lt;/g,
  2472. rgt = /&gt;/g,
  2473. rstringLiteral = /(['"])(\\\1|.)+?\1/g
  2474. function getToken(value) {
  2475. if (value.indexOf("|") > 0) {
  2476. var scapegoat = value.replace(rstringLiteral, function (_) {
  2477. return Array(_.length + 1).join("1") // jshint ignore:line
  2478. })
  2479. var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或
  2480. if (index > -1) {
  2481. return {
  2482. type: "text",
  2483. filters: value.slice(index).trim(),
  2484. expr: value.slice(0, index)
  2485. }
  2486. }
  2487. }
  2488. return {
  2489. type: "text",
  2490. expr: value,
  2491. filters: ""
  2492. }
  2493. }
  2494. function scanExpr(str) {
  2495. var tokens = [],
  2496. value, start = 0,
  2497. stop
  2498. do {
  2499. stop = str.indexOf(openTag, start)
  2500. if (stop === -1) {
  2501. break
  2502. }
  2503. value = str.slice(start, stop)
  2504. if (value) { // {{ 左边的文本
  2505. tokens.push({
  2506. expr: value
  2507. })
  2508. }
  2509. start = stop + openTag.length
  2510. stop = str.indexOf(closeTag, start)
  2511. if (stop === -1) {
  2512. break
  2513. }
  2514. value = str.slice(start, stop)
  2515. if (value) { //处理{{ }}插值表达式
  2516. tokens.push(getToken(value, start))
  2517. }
  2518. start = stop + closeTag.length
  2519. } while (1)
  2520. value = str.slice(start)
  2521. if (value) { //}} 右边的文本
  2522. tokens.push({
  2523. expr: value
  2524. })
  2525. }
  2526. return tokens
  2527. }
  2528. function scanText(textNode, vmodels, index) {
  2529. var bindings = [],
  2530. tokens = scanExpr(textNode.data)
  2531. if (tokens.length) {
  2532. for (var i = 0, token; token = tokens[i++];) {
  2533. var node = DOC.createTextNode(token.expr) //将文本转换为文本节点,并替换原来的文本节点
  2534. if (token.type) {
  2535. token.expr = token.expr.replace(roneTime, function () {
  2536. token.oneTime = true
  2537. return ""
  2538. }) // jshint ignore:line
  2539. token.element = node
  2540. token.filters = token.filters.replace(rhasHtml, function () {
  2541. token.type = "html"
  2542. return ""
  2543. }) // jshint ignore:line
  2544. token.pos = index * 1000 + i
  2545. bindings.push(token) //收集带有插值表达式的文本
  2546. }
  2547. avalonFragment.appendChild(node)
  2548. }
  2549. textNode.parentNode.replaceChild(avalonFragment, textNode)
  2550. if (bindings.length)
  2551. executeBindings(bindings, vmodels)
  2552. }
  2553. }
  2554. //使用来自游戏界的双缓冲技术,减少对视图的冗余刷新
  2555. var Buffer = function () {
  2556. this.queue = []
  2557. }
  2558. Buffer.prototype = {
  2559. render: function (isAnimate) {
  2560. if (!this.locked) {
  2561. this.locked = isAnimate ? root.offsetHeight + 10 : 1
  2562. var me = this
  2563. avalon.nextTick(function () {
  2564. me.flush()
  2565. })
  2566. }
  2567. },
  2568. flush: function () {
  2569. for (var i = 0, sub; sub = this.queue[i++]; ) {
  2570. sub.update && sub.update()
  2571. }
  2572. this.locked = 0
  2573. this.queue = []
  2574. }
  2575. }
  2576. var buffer = new Buffer()
  2577. var componentQueue = []
  2578. var widgetList = []
  2579. var componentHooks = {
  2580. $construct: function () {
  2581. return avalon.mix.apply(null, arguments)
  2582. },
  2583. $ready: noop,
  2584. $init: noop,
  2585. $dispose: noop,
  2586. $container: null,
  2587. $childReady: noop,
  2588. $replace: false,
  2589. $extend: null,
  2590. $$template: function (str) {
  2591. return str
  2592. }
  2593. }
  2594. avalon.components = {}
  2595. avalon.component = function (name, opts) {
  2596. if (opts) {
  2597. avalon.components[name] = avalon.mix({}, componentHooks, opts)
  2598. }
  2599. for (var i = 0, obj; obj = componentQueue[i]; i++) {
  2600. if (name === obj.fullName) {
  2601. componentQueue.splice(i, 1)
  2602. i--;
  2603. (function (host, hooks, elem, widget) {
  2604. //如果elem已从Document里移除,直接返回
  2605. //issuse : https://github.com/RubyLouvre/avalon2/issues/40
  2606. if (!avalon.contains(DOC, elem)) {
  2607. avalon.Array.remove(componentQueue, host)
  2608. return
  2609. }
  2610. var dependencies = 1
  2611. var library = host.library
  2612. var global = avalon.libraries[library] || componentHooks
  2613. //===========收集各种配置=======
  2614. if (elem.getAttribute("ms-attr-identifier")) {
  2615. //如果还没有解析完,就延迟一下 #1155
  2616. return
  2617. }
  2618. var elemOpts = getOptionsFromTag(elem, host.vmodels)
  2619. var vmOpts = getOptionsFromVM(host.vmodels, elemOpts.config || host.fullName)
  2620. var $id = elemOpts.$id || elemOpts.identifier || generateID(widget)
  2621. delete elemOpts.config
  2622. delete elemOpts.$id
  2623. delete elemOpts.identifier
  2624. var componentDefinition = {}
  2625. var parentHooks = avalon.components[hooks.$extend]
  2626. if (parentHooks) {
  2627. avalon.mix(true, componentDefinition, parentHooks)
  2628. componentDefinition = parentHooks.$construct.call(elem, componentDefinition, {}, {})
  2629. } else {
  2630. avalon.mix(true, componentDefinition, hooks)
  2631. }
  2632. componentDefinition = avalon.components[name].$construct.call(elem, componentDefinition, vmOpts, elemOpts)
  2633. componentDefinition.$refs = {}
  2634. componentDefinition.$id = $id
  2635. //==========构建VM=========
  2636. var keepSlot = componentDefinition.$slot
  2637. var keepReplace = componentDefinition.$replace
  2638. var keepContainer = componentDefinition.$container
  2639. var keepTemplate = componentDefinition.$template
  2640. delete componentDefinition.$slot
  2641. delete componentDefinition.$replace
  2642. delete componentDefinition.$container
  2643. delete componentDefinition.$construct
  2644. var vmodel = avalon.define(componentDefinition) || {}
  2645. elem.msResolved = 1
  2646. vmodel.$init(vmodel, elem)
  2647. global.$init(vmodel, elem)
  2648. var nodes = elem.childNodes
  2649. //收集插入点
  2650. var slots = {}, snode
  2651. for (var s = 0, el; el = nodes[s++]; ) {
  2652. var type = el.nodeType === 1 && el.getAttribute("slot") || keepSlot
  2653. if (type) {
  2654. if (slots[type]) {
  2655. slots[type].push(el)
  2656. } else {
  2657. slots[type] = [el]
  2658. }
  2659. }
  2660. }
  2661. if (vmodel.$$template) {
  2662. avalon.clearHTML(elem)
  2663. elem.innerHTML = vmodel.$$template(keepTemplate)
  2664. }
  2665. for (s in slots) {
  2666. if (vmodel.hasOwnProperty(s)) {
  2667. var ss = slots[s]
  2668. if (ss.length) {
  2669. var fragment = avalonFragment.cloneNode(true)
  2670. for (var ns = 0; snode = ss[ns++]; ) {
  2671. fragment.appendChild(snode)
  2672. }
  2673. vmodel[s] = fragment
  2674. }
  2675. slots[s] = null
  2676. }
  2677. }
  2678. slots = null
  2679. var child = elem.children[0] || elem.firstChild
  2680. if (keepReplace) {
  2681. elem.parentNode.replaceChild(child, elem)
  2682. child.msResolved = 1
  2683. var cssText = elem.style.cssText
  2684. var className = elem.className
  2685. elem = host.element = child
  2686. elem.style.cssText = cssText
  2687. if (className) {
  2688. avalon(elem).addClass(className)
  2689. }
  2690. }
  2691. if (keepContainer) {
  2692. keepContainer.appendChild(elem)
  2693. }
  2694. avalon.fireDom(elem, "datasetchanged",
  2695. {library: library, vm: vmodel, childReady: 1})
  2696. var children = 0
  2697. var removeFn = avalon.bind(elem, "datasetchanged", function (e) {
  2698. if (e.childReady && e.library === library) {
  2699. dependencies += e.childReady
  2700. if (vmodel !== e.vm) {
  2701. vmodel.$refs[e.vm.$id] = e.vm
  2702. if (e.childReady === -1) {
  2703. children++
  2704. vmodel.$childReady(vmodel, elem, e)
  2705. }
  2706. e.stopPropagation()
  2707. }
  2708. }
  2709. if (dependencies === 0) {
  2710. var id1 = setTimeout(function () {
  2711. clearTimeout(id1)
  2712. vmodel.$ready(vmodel, elem, host.vmodels)
  2713. global.$ready(vmodel, elem, host.vmodels)
  2714. }, children ? Math.max(children * 17, 100) : 17)
  2715. avalon.unbind(elem, "datasetchanged", removeFn)
  2716. //==================
  2717. host.rollback = function () {
  2718. try {
  2719. vmodel.$dispose(vmodel, elem)
  2720. global.$dispose(vmodel, elem)
  2721. } catch (e) {
  2722. }
  2723. delete avalon.vmodels[vmodel.$id]
  2724. }
  2725. injectDisposeQueue(host, widgetList)
  2726. if (window.chrome) {
  2727. elem.addEventListener("DOMNodeRemovedFromDocument", function () {
  2728. setTimeout(rejectDisposeQueue)
  2729. })
  2730. }
  2731. }
  2732. })
  2733. scanTag(elem, [vmodel].concat(host.vmodels))
  2734. avalon.vmodels[vmodel.$id] = vmodel
  2735. if (!elem.childNodes.length) {
  2736. avalon.fireDom(elem, "datasetchanged", {library: library, vm: vmodel, childReady: -1})
  2737. } else {
  2738. var id2 = setTimeout(function () {
  2739. clearTimeout(id2)
  2740. avalon.fireDom(elem, "datasetchanged", {library: library, vm: vmodel, childReady: -1})
  2741. }, 17)
  2742. }
  2743. })(obj, avalon.components[name], obj.element, obj.widget)// jshint ignore:line
  2744. }
  2745. }
  2746. }
  2747. function getOptionsFromVM(vmodels, pre) {
  2748. if (pre) {
  2749. for (var i = 0, v; v = vmodels[i++]; ) {
  2750. if (v.hasOwnProperty(pre) && typeof v[pre] === "object") {
  2751. var vmOptions = v[pre]
  2752. return vmOptions.$model || vmOptions
  2753. break
  2754. }
  2755. }
  2756. }
  2757. return {}
  2758. }
  2759. avalon.libraries = []
  2760. avalon.library = function (name, opts) {
  2761. if (DOC.namespaces) {
  2762. DOC.namespaces.add(name, 'http://www.w3.org/1999/xhtml');
  2763. }
  2764. avalon.libraries[name] = avalon.mix({
  2765. $init: noop,
  2766. $ready: noop,
  2767. $dispose: noop
  2768. }, opts || {})
  2769. }
  2770. avalon.library("ms")
  2771. /*
  2772. broswer nodeName scopeName localName
  2773. IE9 ONI:BUTTON oni button
  2774. IE10 ONI:BUTTON undefined oni:button
  2775. IE8 button oni undefined
  2776. chrome ONI:BUTTON undefined oni:button
  2777. */
  2778. function isWidget(el) { //如果为自定义标签,返回UI库的名字
  2779. if (el.scopeName && el.scopeName !== "HTML") {
  2780. return el.scopeName
  2781. }
  2782. var fullName = el.nodeName.toLowerCase()
  2783. var index = fullName.indexOf(":")
  2784. if (index > 0) {
  2785. return fullName.slice(0, index)
  2786. }
  2787. }
  2788. //各种MVVM框架在大型表格下的性能测试
  2789. // https://github.com/RubyLouvre/avalon/issues/859
  2790. var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls",
  2791. "declare,disabled,defer,defaultChecked,defaultSelected",
  2792. "contentEditable,isMap,loop,multiple,noHref,noResize,noShade",
  2793. "open,readOnly,selected"
  2794. ].join(",")
  2795. var boolMap = {}
  2796. bools.replace(rword, function (name) {
  2797. boolMap[name.toLowerCase()] = name
  2798. })
  2799. var propMap = {//属性名映射
  2800. "accept-charset": "acceptCharset",
  2801. "char": "ch",
  2802. "charoff": "chOff",
  2803. "class": "className",
  2804. "for": "htmlFor",
  2805. "http-equiv": "httpEquiv"
  2806. }
  2807. var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan",
  2808. "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight",
  2809. "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign"
  2810. ].join(",")
  2811. anomaly.replace(rword, function (name) {
  2812. propMap[name.toLowerCase()] = name
  2813. })
  2814. var attrDir = avalon.directive("attr", {
  2815. init: function (binding) {
  2816. //{{aaa}} --> aaa
  2817. //{{aaa}}/bbb.html --> (aaa) + "/bbb.html"
  2818. binding.expr = normalizeExpr(binding.expr.trim())
  2819. if (binding.type === "include") {
  2820. var elem = binding.element
  2821. effectBinding(elem, binding)
  2822. binding.includeRendered = getBindingCallback(elem, "data-include-rendered", binding.vmodels)
  2823. binding.includeLoaded = getBindingCallback(elem, "data-include-loaded", binding.vmodels)
  2824. var outer = binding.includeReplace = !!avalon(elem).data("includeReplace")
  2825. if (avalon(elem).data("includeCache")) {
  2826. binding.templateCache = {}
  2827. }
  2828. binding.start = DOC.createComment("ms-include")
  2829. binding.end = DOC.createComment("ms-include-end")
  2830. if (outer) {
  2831. binding.element = binding.end
  2832. binding._element = elem
  2833. elem.parentNode.insertBefore(binding.start, elem)
  2834. elem.parentNode.insertBefore(binding.end, elem.nextSibling)
  2835. } else {
  2836. elem.insertBefore(binding.start, elem.firstChild)
  2837. elem.appendChild(binding.end)
  2838. }
  2839. }
  2840. },
  2841. update: function (val) {
  2842. var elem = this.element
  2843. var attrName = this.param
  2844. if (attrName === "href" || attrName === "src") {
  2845. if (typeof val === "string" && !root.hasAttribute) {
  2846. val = val.replace(/&amp;/g, "&") //处理IE67自动转义的问题
  2847. }
  2848. elem[attrName] = val
  2849. if (window.chrome && elem.tagName === "EMBED") {
  2850. var parent = elem.parentNode //#525 chrome1-37下embed标签动态设置src不能发生请求
  2851. var comment = document.createComment("ms-src")
  2852. parent.replaceChild(comment, elem)
  2853. parent.replaceChild(elem, comment)
  2854. }
  2855. } else {
  2856. // ms-attr-class="xxx" vm.xxx="aaa bbb ccc"将元素的className设置为aaa bbb ccc
  2857. // ms-attr-class="xxx" vm.xxx=false 清空元素的所有类名
  2858. // ms-attr-name="yyy" vm.yyy="ooo" 为元素设置name属性
  2859. var toRemove = (val === false) || (val === null) || (val === void 0)
  2860. if (!W3C && propMap[attrName]) { //旧式IE下需要进行名字映射
  2861. attrName = propMap[attrName]
  2862. }
  2863. var bool = boolMap[attrName]
  2864. if (typeof elem[bool] === "boolean") {
  2865. elem[bool] = !!val //布尔属性必须使用el.xxx = true|false方式设值
  2866. if (!val) { //如果为false, IE全系列下相当于setAttribute(xxx,''),会影响到样式,需要进一步处理
  2867. toRemove = true
  2868. }
  2869. }
  2870. if (toRemove) {
  2871. return elem.removeAttribute(attrName)
  2872. }
  2873. //SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy
  2874. var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : attrName in elem.cloneNode(false)
  2875. if (isInnate) {
  2876. elem[attrName] = val + ""
  2877. } else {
  2878. elem.setAttribute(attrName, val)
  2879. }
  2880. }
  2881. }
  2882. })
  2883. //这几个指令都可以使用插值表达式,如ms-src="aaa/{{b}}/{{c}}.html"
  2884. "title,alt,src,value,css,include,href".replace(rword, function (name) {
  2885. directives[name] = attrDir
  2886. })
  2887. //根据VM的属性值或表达式的值切换类名,ms-class="xxx yyy zzz:flag"
  2888. //http://www.cnblogs.com/rubylouvre/archive/2012/12/17/2818540.html
  2889. avalon.directive("class", {
  2890. init: function (binding) {
  2891. var oldStyle = binding.param
  2892. var method = binding.type
  2893. if (!oldStyle || isFinite(oldStyle)) {
  2894. binding.param = "" //去掉数字
  2895. directives.effect.init(binding)
  2896. } else {
  2897. log('ms-' + method + '-xxx="yyy"这种用法已经过时,请使用ms-' + method + '="xxx:yyy"')
  2898. binding.expr = '[' + quote(oldStyle) + "," + binding.expr + "]"
  2899. binding.oldStyle = oldStyle
  2900. }
  2901. if (method === "hover" || method === "active") { //确保只绑定一次
  2902. if (!binding.hasBindEvent) {
  2903. var elem = binding.element
  2904. var $elem = avalon(elem)
  2905. var activate = "mouseenter" //在移出移入时切换类名
  2906. var abandon = "mouseleave"
  2907. if (method === "active") { //在聚焦失焦中切换类名
  2908. elem.tabIndex = elem.tabIndex || -1
  2909. activate = "mousedown"
  2910. abandon = "mouseup"
  2911. var fn0 = $elem.bind("mouseleave", function () {
  2912. binding.toggleClass && $elem.removeClass(binding.newClass)
  2913. })
  2914. }
  2915. }
  2916. var fn1 = $elem.bind(activate, function () {
  2917. binding.toggleClass && $elem.addClass(binding.newClass)
  2918. })
  2919. var fn2 = $elem.bind(abandon, function () {
  2920. binding.toggleClass && $elem.removeClass(binding.newClass)
  2921. })
  2922. binding.rollback = function () {
  2923. $elem.unbind("mouseleave", fn0)
  2924. $elem.unbind(activate, fn1)
  2925. $elem.unbind(abandon, fn2)
  2926. }
  2927. binding.hasBindEvent = true
  2928. }
  2929. },
  2930. update: function (arr) {
  2931. var binding = this
  2932. var $elem = avalon(this.element)
  2933. binding.newClass = arr[0]
  2934. binding.toggleClass = !!arr[1]
  2935. if (binding.oldClass && binding.newClass !== binding.oldClass) {
  2936. $elem.removeClass(binding.oldClass)
  2937. }
  2938. binding.oldClass = binding.newClass
  2939. if (binding.type === "class") {
  2940. if (binding.oldStyle) {
  2941. $elem.toggleClass(binding.oldStyle, !!arr[1])
  2942. } else {
  2943. $elem.toggleClass(binding.newClass, binding.toggleClass)
  2944. }
  2945. }
  2946. }
  2947. })
  2948. "hover,active".replace(rword, function (name) {
  2949. directives[name] = directives["class"]
  2950. })
  2951. //ms-controller绑定已经在scanTag 方法中实现
  2952. avalon.directive("css", {
  2953. init: directives.attr.init,
  2954. update: function (val) {
  2955. avalon(this.element).css(this.param, val)
  2956. }
  2957. })
  2958. avalon.directive("data", {
  2959. priority: 100,
  2960. update: function (val) {
  2961. var elem = this.element
  2962. var key = "data-" + this.param
  2963. if (val && typeof val === "object") {
  2964. elem[key] = val
  2965. } else {
  2966. elem.setAttribute(key, String(val))
  2967. }
  2968. }
  2969. })
  2970. //双工绑定
  2971. var rduplexType = /^(?:checkbox|radio)$/
  2972. var rduplexParam = /^(?:radio|checked)$/
  2973. var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/
  2974. var duplexBinding = avalon.directive("duplex", {
  2975. priority: 2000,
  2976. init: function (binding, hasCast) {
  2977. var elem = binding.element
  2978. var vmodels = binding.vmodels
  2979. binding.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop
  2980. var params = []
  2981. var casting = oneObject("string,number,boolean,checked")
  2982. if (elem.type === "radio" && binding.param === "") {
  2983. binding.param = "checked"
  2984. }
  2985. binding.param.replace(rw20g, function (name) {
  2986. if (rduplexType.test(elem.type) && rduplexParam.test(name)) {
  2987. if (name === "radio")
  2988. log("ms-duplex-radio已经更名为ms-duplex-checked")
  2989. name = "checked"
  2990. binding.isChecked = true
  2991. binding.xtype = "radio"
  2992. }
  2993. if (name === "bool") {
  2994. name = "boolean"
  2995. log("ms-duplex-bool已经更名为ms-duplex-boolean")
  2996. } else if (name === "text") {
  2997. name = "string"
  2998. log("ms-duplex-text已经更名为ms-duplex-string")
  2999. }
  3000. if (casting[name]) {
  3001. hasCast = true
  3002. }
  3003. avalon.Array.ensure(params, name)
  3004. })
  3005. if (!hasCast) {
  3006. params.push("string")
  3007. }
  3008. binding.param = params.join("-")
  3009. if (!binding.xtype) {
  3010. binding.xtype = elem.tagName === "SELECT" ? "select" :
  3011. elem.type === "checkbox" ? "checkbox" :
  3012. elem.type === "radio" ? "radio" :
  3013. /^change/.test(elem.getAttribute("data-duplex-event")) ? "change" :
  3014. "input"
  3015. }
  3016. //===================绑定事件======================
  3017. var bound = binding.bound = function (type, callback) {
  3018. elem.addEventListener(type, callback, false)
  3019. var old = binding.rollback
  3020. binding.rollback = function () {
  3021. elem.avalonSetter = null
  3022. avalon.unbind(elem, type, callback)
  3023. old && old()
  3024. }
  3025. }
  3026. function callback(value) {
  3027. binding.changed.call(this, value, binding)
  3028. }
  3029. var composing = false
  3030. function compositionStart() {
  3031. composing = true
  3032. }
  3033. function compositionEnd() {
  3034. composing = false
  3035. }
  3036. var updateVModel = function (e) {
  3037. var val = elem.value //防止递归调用形成死循环
  3038. if (composing || val === binding.oldValue || binding.pipe === null) //处理中文输入法在minlengh下引发的BUG
  3039. return
  3040. var lastValue = binding.pipe(val, binding, "get")
  3041. binding.oldValue = val
  3042. binding.setter(lastValue)
  3043. callback.call(elem, lastValue)
  3044. }
  3045. switch (binding.xtype) {
  3046. case "radio":
  3047. bound("click", function () {
  3048. var lastValue = binding.pipe(elem.value, binding, "get")
  3049. binding.setter(lastValue)
  3050. callback.call(elem, lastValue)
  3051. })
  3052. break
  3053. case "checkbox":
  3054. bound("change", function () {
  3055. var method = elem.checked ? "ensure" : "remove"
  3056. var array = binding.getter.apply(0, binding.vmodels)
  3057. if (!Array.isArray(array)) {
  3058. log("ms-duplex应用于checkbox上要对应一个数组")
  3059. array = [array]
  3060. }
  3061. var val = binding.pipe(elem.value, binding, "get")
  3062. avalon.Array[method](array, val)
  3063. callback.call(elem, array)
  3064. })
  3065. break
  3066. case "change":
  3067. bound("change", updateVModel)
  3068. break
  3069. case "input":
  3070. bound("input", updateVModel)
  3071. bound("keyup", updateVModel)
  3072. if (!IEVersion) {
  3073. bound("compositionstart", compositionStart)
  3074. bound("compositionend", compositionEnd)
  3075. bound("DOMAutoComplete", updateVModel)
  3076. }
  3077. break
  3078. case "select":
  3079. bound("change", function () {
  3080. var val = avalon(elem).val() //字符串或字符串数组
  3081. if (Array.isArray(val)) {
  3082. val = val.map(function (v) {
  3083. return binding.pipe(v, binding, "get")
  3084. })
  3085. } else {
  3086. val = binding.pipe(val, binding, "get")
  3087. }
  3088. if (val + "" !== binding.oldValue) {
  3089. try {
  3090. binding.setter(val)
  3091. } catch (ex) {
  3092. log(ex)
  3093. }
  3094. }
  3095. })
  3096. bound("datasetchanged", function (e) {
  3097. if (e.bubble === "selectDuplex") {
  3098. var value = binding._value
  3099. var curValue = Array.isArray(value) ? value.map(String) : value + ""
  3100. avalon(elem).val(curValue)
  3101. elem.oldValue = curValue + ""
  3102. callback.call(elem, curValue)
  3103. }
  3104. })
  3105. break
  3106. }
  3107. if (binding.xtype === "input" && !rnoduplexInput.test(elem.type)) {
  3108. if (elem.type !== "hidden") {
  3109. bound("focus", function () {
  3110. elem.msFocus = true
  3111. })
  3112. bound("blur", function () {
  3113. elem.msFocus = false
  3114. })
  3115. }
  3116. elem.avalonSetter = updateVModel //#765
  3117. watchValueInTimer(function () {
  3118. if (root.contains(elem)) {
  3119. if (!elem.msFocus) {
  3120. updateVModel()
  3121. }
  3122. } else if (!elem.msRetain) {
  3123. return false
  3124. }
  3125. })
  3126. }
  3127. },
  3128. update: function (value) {
  3129. var elem = this.element, binding = this, curValue
  3130. if (!this.init) {
  3131. for (var i in avalon.vmodels) {
  3132. var v = avalon.vmodels[i]
  3133. v.$fire("avalon-ms-duplex-init", binding)
  3134. }
  3135. var cpipe = binding.pipe || (binding.pipe = pipe)
  3136. cpipe(null, binding, "init")
  3137. this.init = 1
  3138. }
  3139. switch (this.xtype) {
  3140. case "input":
  3141. case "change":
  3142. curValue = this.pipe(value, this, "set") //fix #673
  3143. if (curValue !== this.oldValue) {
  3144. var fixCaret = false
  3145. if (elem.msFocus) {
  3146. try {
  3147. var start = elem.selectionStart
  3148. var end = elem.selectionEnd
  3149. if (start === end) {
  3150. var pos = start
  3151. fixCaret = true
  3152. }
  3153. } catch (e) {
  3154. }
  3155. }
  3156. elem.value = this.oldValue = curValue
  3157. if (fixCaret && !elem.readOnly) {
  3158. elem.selectionStart = elem.selectionEnd = pos
  3159. }
  3160. }
  3161. break
  3162. case "radio":
  3163. curValue = binding.isChecked ? !!value : value + "" === elem.value
  3164. elem.checked = curValue
  3165. break
  3166. case "checkbox":
  3167. var array = [].concat(value) //强制转换为数组
  3168. curValue = this.pipe(elem.value, this, "get")
  3169. elem.checked = array.indexOf(curValue) > -1
  3170. break
  3171. case "select":
  3172. //必须变成字符串后才能比较
  3173. binding._value = value
  3174. if (!elem.msHasEvent) {
  3175. elem.msHasEvent = "selectDuplex"
  3176. //必须等到其孩子准备好才触发
  3177. } else {
  3178. avalon.fireDom(elem, "datasetchanged", {
  3179. bubble: elem.msHasEvent
  3180. })
  3181. }
  3182. break
  3183. }
  3184. }
  3185. })
  3186. function fixNull(val) {
  3187. return val == null ? "" : val
  3188. }
  3189. avalon.duplexHooks = {
  3190. checked: {
  3191. get: function (val, binding) {
  3192. return !binding.oldValue
  3193. }
  3194. },
  3195. string: {
  3196. get: function (val) { //同步到VM
  3197. return val
  3198. },
  3199. set: fixNull
  3200. },
  3201. "boolean": {
  3202. get: function (val) {
  3203. return val === "true"
  3204. },
  3205. set: fixNull
  3206. },
  3207. number: {
  3208. get: function (val, binding) {
  3209. var number = parseFloat(val)
  3210. if (-val === -number) {
  3211. return number
  3212. }
  3213. var arr = /strong|medium|weak/.exec(binding.element.getAttribute("data-duplex-number")) || ["medium"]
  3214. switch (arr[0]) {
  3215. case "strong":
  3216. return 0
  3217. case "medium":
  3218. return val === "" ? "" : 0
  3219. case "weak":
  3220. return val
  3221. }
  3222. },
  3223. set: fixNull
  3224. }
  3225. }
  3226. function pipe(val, binding, action, e) {
  3227. binding.param.replace(rw20g, function (name) {
  3228. var hook = avalon.duplexHooks[name]
  3229. if (hook && typeof hook[action] === "function") {
  3230. val = hook[action](val, binding)
  3231. }
  3232. })
  3233. return val
  3234. }
  3235. var TimerID, ribbon = []
  3236. avalon.tick = function (fn) {
  3237. if (ribbon.push(fn) === 1) {
  3238. TimerID = setInterval(ticker, 60)
  3239. }
  3240. }
  3241. function ticker() {
  3242. for (var n = ribbon.length - 1; n >= 0; n--) {
  3243. var el = ribbon[n]
  3244. if (el() === false) {
  3245. ribbon.splice(n, 1)
  3246. }
  3247. }
  3248. if (!ribbon.length) {
  3249. clearInterval(TimerID)
  3250. }
  3251. }
  3252. var watchValueInTimer = noop
  3253. new function () { // jshint ignore:line
  3254. try { //#272 IE9-IE11, firefox
  3255. var setters = {}
  3256. var aproto = HTMLInputElement.prototype
  3257. var bproto = HTMLTextAreaElement.prototype
  3258. function newSetter(value) { // jshint ignore:line
  3259. setters[this.tagName].call(this, value)
  3260. if (!this.msFocus && this.avalonSetter) {
  3261. this.avalonSetter()
  3262. }
  3263. }
  3264. var inputProto = HTMLInputElement.prototype
  3265. Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错
  3266. setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set
  3267. Object.defineProperty(aproto, "value", {
  3268. set: newSetter
  3269. })
  3270. setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set
  3271. Object.defineProperty(bproto, "value", {
  3272. set: newSetter
  3273. })
  3274. } catch (e) {
  3275. //在chrome 43中 ms-duplex终于不需要使用定时器实现双向绑定了
  3276. // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype
  3277. // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1
  3278. watchValueInTimer = avalon.tick
  3279. }
  3280. } // jshint ignore:line
  3281. avalon.directive("effect", {
  3282. priority: 5,
  3283. init: function (binding) {
  3284. var text = binding.expr,
  3285. className,
  3286. rightExpr
  3287. var colonIndex = text.replace(rexprg, function (a) {
  3288. return a.replace(/./g, "0")
  3289. }).indexOf(":") //取得第一个冒号的位置
  3290. if (colonIndex === -1) { // 比如 ms-class/effect="aaa bbb ccc" 的情况
  3291. className = text
  3292. rightExpr = true
  3293. } else { // 比如 ms-class/effect-1="ui-state-active:checked" 的情况
  3294. className = text.slice(0, colonIndex)
  3295. rightExpr = text.slice(colonIndex + 1)
  3296. }
  3297. if (!rexpr.test(text)) {
  3298. className = quote(className)
  3299. } else {
  3300. className = normalizeExpr(className)
  3301. }
  3302. binding.expr = "[" + className + "," + rightExpr + "]"
  3303. },
  3304. update: function (arr) {
  3305. var name = arr[0]
  3306. var elem = this.element
  3307. if (elem.getAttribute("data-effect-name") === name) {
  3308. return
  3309. } else {
  3310. elem.removeAttribute("data-effect-driver")
  3311. }
  3312. var inlineStyles = elem.style
  3313. var computedStyles = window.getComputedStyle ? window.getComputedStyle(elem) : null
  3314. var useAni = false
  3315. if (computedStyles && (supportTransition || supportAnimation)) {
  3316. //如果支持CSS动画
  3317. var duration = inlineStyles[transitionDuration] || computedStyles[transitionDuration]
  3318. if (duration && duration !== '0s') {
  3319. elem.setAttribute("data-effect-driver", "t")
  3320. useAni = true
  3321. }
  3322. if (!useAni) {
  3323. duration = inlineStyles[animationDuration] || computedStyles[animationDuration]
  3324. if (duration && duration !== '0s') {
  3325. elem.setAttribute("data-effect-driver", "a")
  3326. useAni = true
  3327. }
  3328. }
  3329. }
  3330. if (!useAni) {
  3331. if (avalon.effects[name]) {
  3332. elem.setAttribute("data-effect-driver", "j")
  3333. useAni = true
  3334. }
  3335. }
  3336. if (useAni) {
  3337. elem.setAttribute("data-effect-name", name)
  3338. }
  3339. }
  3340. })
  3341. avalon.effects = {}
  3342. avalon.effect = function (name, callbacks) {
  3343. avalon.effects[name] = callbacks
  3344. }
  3345. var supportTransition = false
  3346. var supportAnimation = false
  3347. var transitionEndEvent
  3348. var animationEndEvent
  3349. var transitionDuration = avalon.cssName("transition-duration")
  3350. var animationDuration = avalon.cssName("animation-duration")
  3351. new function () {// jshint ignore:line
  3352. var checker = {
  3353. 'TransitionEvent': 'transitionend',
  3354. 'WebKitTransitionEvent': 'webkitTransitionEnd',
  3355. 'OTransitionEvent': 'oTransitionEnd',
  3356. 'otransitionEvent': 'otransitionEnd'
  3357. }
  3358. var tran
  3359. //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4
  3360. for (var name in checker) {
  3361. if (window[name]) {
  3362. tran = checker[name]
  3363. break;
  3364. }
  3365. try {
  3366. var a = document.createEvent(name);
  3367. tran = checker[name]
  3368. break;
  3369. } catch (e) {
  3370. }
  3371. }
  3372. if (typeof tran === "string") {
  3373. supportTransition = true
  3374. transitionEndEvent = tran
  3375. }
  3376. //大致上有两种选择
  3377. //IE10+, Firefox 16+ & Opera 12.1+: animationend
  3378. //Chrome/Safari: webkitAnimationEnd
  3379. //http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animat ions.aspx
  3380. //IE10也可以使用MSAnimationEnd监听,但是回调里的事件 type依然为animationend
  3381. // el.addEventListener("MSAnimationEnd", function(e) {
  3382. // alert(e.type)// animationend!!!
  3383. // })
  3384. checker = {
  3385. 'AnimationEvent': 'animationend',
  3386. 'WebKitAnimationEvent': 'webkitAnimationEnd'
  3387. }
  3388. var ani;
  3389. for (name in checker) {
  3390. if (window[name]) {
  3391. ani = checker[name];
  3392. break;
  3393. }
  3394. }
  3395. if (typeof ani === "string") {
  3396. supportTransition = true
  3397. animationEndEvent = ani
  3398. }
  3399. }()
  3400. var effectPool = []//重复利用动画实例
  3401. function effectFactory(el, opts) {
  3402. if (!el || el.nodeType !== 1) {
  3403. return null
  3404. }
  3405. if (opts) {
  3406. var name = opts.effectName
  3407. var driver = opts.effectDriver
  3408. } else {
  3409. name = el.getAttribute("data-effect-name")
  3410. driver = el.getAttribute("data-effect-driver")
  3411. }
  3412. if (!name || !driver) {
  3413. return null
  3414. }
  3415. var instance = effectPool.pop() || new Effect()
  3416. instance.el = el
  3417. instance.driver = driver
  3418. instance.useCss = driver !== "j"
  3419. if (instance.useCss) {
  3420. opts && avalon(el).addClass(opts.effectClass)
  3421. instance.cssEvent = driver === "t" ? transitionEndEvent : animationEndEvent
  3422. }
  3423. instance.name = name
  3424. instance.callbacks = avalon.effects[name] || {}
  3425. return instance
  3426. }
  3427. function effectBinding(elem, binding) {
  3428. var name = elem.getAttribute("data-effect-name")
  3429. if (name) {
  3430. binding.effectName = name
  3431. binding.effectDriver = elem.getAttribute("data-effect-driver")
  3432. var stagger = +elem.getAttribute("data-effect-stagger")
  3433. binding.effectLeaveStagger = +elem.getAttribute("data-effect-leave-stagger") || stagger
  3434. binding.effectEnterStagger = +elem.getAttribute("data-effect-enter-stagger") || stagger
  3435. binding.effectClass = elem.className || NaN
  3436. }
  3437. }
  3438. function upperFirstChar(str) {
  3439. return str.replace(/^[\S]/g, function (m) {
  3440. return m.toUpperCase()
  3441. })
  3442. }
  3443. var effectBuffer = new Buffer()
  3444. function Effect() {
  3445. }// 动画实例,做成类的形式,是为了共用所有原型方法
  3446. Effect.prototype = {
  3447. contrustor: Effect,
  3448. enterClass: function () {
  3449. return getEffectClass(this, "enter")
  3450. },
  3451. leaveClass: function () {
  3452. return getEffectClass(this, "leave")
  3453. },
  3454. // 共享一个函数
  3455. actionFun: function (name, before, after) {
  3456. if (document.hidden) {
  3457. return
  3458. }
  3459. var me = this
  3460. var el = me.el
  3461. var isLeave = name === "leave"
  3462. name = isLeave ? "leave" : "enter"
  3463. var oppositeName = isLeave ? "enter" : "leave"
  3464. callEffectHook(me, "abort" + upperFirstChar(oppositeName))
  3465. callEffectHook(me, "before" + upperFirstChar(name))
  3466. if (!isLeave)
  3467. before(el) //  这里可能做插入DOM树的操作,因此必须在修改类名前执行
  3468. var cssCallback = function (cancel) {
  3469. el.removeEventListener(me.cssEvent, me.cssCallback)
  3470. if (isLeave) {
  3471. before(el) //这里可能做移出DOM树操作,因此必须位于动画之后
  3472. avalon(el).removeClass(me.cssClass)
  3473. } else {
  3474. if (me.driver === "a") {
  3475. avalon(el).removeClass(me.cssClass)
  3476. }
  3477. }
  3478. if (cancel !== true) {
  3479. callEffectHook(me, "after" + upperFirstChar(name))
  3480. after && after(el)
  3481. }
  3482. me.dispose()
  3483. }
  3484. if (me.useCss) {
  3485. if (me.cssCallback) { //如果leave动画还没有完成,立即完成
  3486. me.cssCallback(true)
  3487. }
  3488. me.cssClass = getEffectClass(me, name)
  3489. me.cssCallback = cssCallback
  3490. me.update = function () {
  3491. el.addEventListener(me.cssEvent, me.cssCallback)
  3492. if (!isLeave && me.driver === "t") {//transtion延迟触发
  3493. avalon(el).removeClass(me.cssClass)
  3494. }
  3495. }
  3496. avalon(el).addClass(me.cssClass)//animation会立即触发
  3497. effectBuffer.render(true)
  3498. effectBuffer.queue.push(me)
  3499. } else {
  3500. callEffectHook(me, name, cssCallback)
  3501. }
  3502. },
  3503. enter: function (before, after) {
  3504. this.actionFun.apply(this, ["enter"].concat(avalon.slice(arguments)))
  3505. },
  3506. leave: function (before, after) {
  3507. this.actionFun.apply(this, ["leave"].concat(avalon.slice(arguments)))
  3508. },
  3509. dispose: function () {//销毁与回收到池子中
  3510. this.update = this.cssCallback = null
  3511. if (effectPool.unshift(this) > 100) {
  3512. effectPool.pop()
  3513. }
  3514. }
  3515. }
  3516. function getEffectClass(instance, type) {
  3517. var a = instance.callbacks[type + "Class"]
  3518. if (typeof a === "string")
  3519. return a
  3520. if (typeof a === "function")
  3521. return a()
  3522. return instance.name + "-" + type
  3523. }
  3524. function callEffectHook(effect, name, cb) {
  3525. var hook = effect.callbacks[name]
  3526. if (hook) {
  3527. hook.call(effect, effect.el, cb)
  3528. }
  3529. }
  3530. var applyEffect = function (el, dir/*[before, [after, [opts]]]*/) {
  3531. var args = aslice.call(arguments, 0)
  3532. if (typeof args[2] !== "function") {
  3533. args.splice(2, 0, noop)
  3534. }
  3535. if (typeof args[3] !== "function") {
  3536. args.splice(3, 0, noop)
  3537. }
  3538. var before = args[2]
  3539. var after = args[3]
  3540. var opts = args[4]
  3541. var effect = effectFactory(el, opts)
  3542. if (!effect) {
  3543. before()
  3544. after()
  3545. return false
  3546. } else {
  3547. var method = dir ? 'enter' : 'leave'
  3548. effect[method](before, after)
  3549. }
  3550. }
  3551. avalon.mix(avalon.effect, {
  3552. apply: applyEffect,
  3553. append: function (el, parent, after, opts) {
  3554. return applyEffect(el, 1, function () {
  3555. parent.appendChild(el)
  3556. }, after, opts)
  3557. },
  3558. before: function (el, target, after, opts) {
  3559. return applyEffect(el, 1, function () {
  3560. target.parentNode.insertBefore(el, target)
  3561. }, after, opts)
  3562. },
  3563. remove: function (el, parent, after, opts) {
  3564. return applyEffect(el, 0, function () {
  3565. if (el.parentNode === parent)
  3566. parent.removeChild(el)
  3567. }, after, opts)
  3568. }
  3569. })
  3570. avalon.directive("html", {
  3571. update: function (val) {
  3572. var binding = this
  3573. var elem = this.element
  3574. var isHtmlFilter = elem.nodeType !== 1
  3575. var parent = isHtmlFilter ? elem.parentNode : elem
  3576. if (!parent)
  3577. return
  3578. val = val == null ? "" : val
  3579. if (elem.nodeType === 3) {
  3580. var signature = generateID("html")
  3581. parent.insertBefore(DOC.createComment(signature), elem)
  3582. binding.element = DOC.createComment(signature + ":end")
  3583. parent.replaceChild(binding.element, elem)
  3584. elem = binding.element
  3585. }
  3586. if (typeof val !== "object") {//string, number, boolean
  3587. var fragment = avalon.parseHTML(String(val))
  3588. } else if (val.nodeType === 11) { //将val转换为文档碎片
  3589. fragment = val
  3590. } else if (val.nodeType === 1 || val.item) {
  3591. var nodes = val.nodeType === 1 ? val.childNodes : val.item
  3592. fragment = avalonFragment.cloneNode(true)
  3593. while (nodes[0]) {
  3594. fragment.appendChild(nodes[0])
  3595. }
  3596. }
  3597. nodes = avalon.slice(fragment.childNodes)
  3598. //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空
  3599. if (isHtmlFilter) {
  3600. var endValue = elem.nodeValue.slice(0, -4)
  3601. while (true) {
  3602. var node = elem.previousSibling
  3603. if (!node || node.nodeType === 8 && node.nodeValue === endValue) {
  3604. break
  3605. } else {
  3606. parent.removeChild(node)
  3607. }
  3608. }
  3609. parent.insertBefore(fragment, elem)
  3610. } else {
  3611. avalon.clearHTML(elem).appendChild(fragment)
  3612. }
  3613. scanNodeArray(nodes, binding.vmodels)
  3614. }
  3615. })
  3616. avalon.directive("if", {
  3617. priority: 10,
  3618. update: function (val) {
  3619. var binding = this
  3620. var elem = this.element
  3621. var stamp = binding.stamp = +new Date()
  3622. var par
  3623. var after = function () {
  3624. if (stamp !== binding.stamp)
  3625. return
  3626. binding.recoverNode = null
  3627. }
  3628. if (binding.recoverNode)
  3629. binding.recoverNode() // 还原现场,有移动节点的都需要还原现场
  3630. try {
  3631. if (!elem.parentNode)
  3632. return
  3633. par = elem.parentNode
  3634. } catch (e) {
  3635. return
  3636. }
  3637. if (val) { //插回DOM树
  3638. function alway() {// jshint ignore:line
  3639. if (elem.getAttribute(binding.name)) {
  3640. elem.removeAttribute(binding.name)
  3641. scanAttr(elem, binding.vmodels)
  3642. }
  3643. binding.rollback = null
  3644. }
  3645. if (elem.nodeType === 8) {
  3646. var keep = binding.keep
  3647. var hasEffect = avalon.effect.apply(keep, 1, function () {
  3648. if (stamp !== binding.stamp)
  3649. return
  3650. elem.parentNode.replaceChild(keep, elem)
  3651. elem = binding.element = keep //这时可能为null
  3652. if (keep.getAttribute("_required")) {//#1044
  3653. elem.required = true
  3654. elem.removeAttribute("_required")
  3655. }
  3656. if (elem.querySelectorAll) {
  3657. avalon.each(elem.querySelectorAll("[_required=true]"), function (el) {
  3658. el.required = true
  3659. el.removeAttribute("_required")
  3660. })
  3661. }
  3662. alway()
  3663. }, after)
  3664. hasEffect = hasEffect === false
  3665. }
  3666. if (!hasEffect)
  3667. alway()
  3668. } else { //移出DOM树,并用注释节点占据原位置
  3669. if (elem.nodeType === 1) {
  3670. if (elem.required === true) {
  3671. elem.required = false
  3672. elem.setAttribute("_required", "true")
  3673. }
  3674. try {// 如果不支持querySelectorAll或:required,可以直接无视
  3675. avalon.each(elem.querySelectorAll(":required"), function (el) {
  3676. elem.required = false
  3677. el.setAttribute("_required", "true")
  3678. })
  3679. } catch (e) {
  3680. }
  3681. var node = binding.element = DOC.createComment("ms-if"),
  3682. pos = elem.nextSibling
  3683. binding.recoverNode = function () {
  3684. binding.recoverNode = null
  3685. if (node.parentNode !== par) {
  3686. par.insertBefore(node, pos)
  3687. binding.keep = elem
  3688. }
  3689. }
  3690. avalon.effect.apply(elem, 0, function () {
  3691. binding.recoverNode = null
  3692. if (stamp !== binding.stamp)
  3693. return
  3694. elem.parentNode.replaceChild(node, elem)
  3695. binding.keep = elem //元素节点
  3696. ifGroup.appendChild(elem)
  3697. binding.rollback = function () {
  3698. if (elem.parentNode === ifGroup) {
  3699. ifGroup.removeChild(elem)
  3700. }
  3701. }
  3702. }, after)
  3703. }
  3704. }
  3705. }
  3706. })
  3707. //ms-important绑定已经在scanTag 方法中实现
  3708. var rnoscripts = /<noscript.*?>(?:[\s\S]+?)<\/noscript>/img
  3709. var rnoscriptText = /<noscript.*?>([\s\S]+?)<\/noscript>/im
  3710. var getXHR = function () {
  3711. return new window.XMLHttpRequest() // jshint ignore:line
  3712. }
  3713. //将所有远程加载的模板,以字符串形式存放到这里
  3714. var templatePool = avalon.templateCache = {}
  3715. function getTemplateContainer(binding, id, text) {
  3716. var div = binding.templateCache && binding.templateCache[id]
  3717. if (div) {
  3718. var dom = DOC.createDocumentFragment(),
  3719. firstChild
  3720. while (firstChild = div.firstChild) {
  3721. dom.appendChild(firstChild)
  3722. }
  3723. return dom
  3724. }
  3725. return avalon.parseHTML(text)
  3726. }
  3727. function nodesToFrag(nodes) {
  3728. var frag = DOC.createDocumentFragment()
  3729. for (var i = 0, len = nodes.length; i < len; i++) {
  3730. frag.appendChild(nodes[i])
  3731. }
  3732. return frag
  3733. }
  3734. avalon.directive("include", {
  3735. init: directives.attr.init,
  3736. update: function (val) {
  3737. var binding = this
  3738. var elem = this.element
  3739. var vmodels = binding.vmodels
  3740. var rendered = binding.includeRendered
  3741. var effectClass = binding.effectName && binding.effectClass // 是否开启动画
  3742. var templateCache = binding.templateCache // 是否data-include-cache
  3743. var outer = binding.includeReplace // 是否data-include-replace
  3744. var loaded = binding.includeLoaded
  3745. var target = outer ? elem.parentNode : elem
  3746. var _ele = binding._element // data-include-replace binding.element === binding.end
  3747. binding.recoverNodes = binding.recoverNodes || avalon.noop
  3748. var scanTemplate = function (text) {
  3749. var _stamp = binding._stamp = +(new Date()) // 过滤掉频繁操作
  3750. if (loaded) {
  3751. var newText = loaded.apply(target, [text].concat(vmodels))
  3752. if (typeof newText === "string")
  3753. text = newText
  3754. }
  3755. if (rendered) {
  3756. checkScan(target, function () {
  3757. rendered.call(target)
  3758. }, NaN)
  3759. }
  3760. var lastID = binding.includeLastID || "_default" // 默认
  3761. binding.includeLastID = val
  3762. var leaveEl = templateCache && templateCache[lastID] || DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素
  3763. if (effectClass) {
  3764. leaveEl.className = effectClass
  3765. target.insertBefore(leaveEl, binding.start) // 插入到start之前,防止被错误的移动
  3766. }
  3767. // cache or animate,移动节点
  3768. (templateCache || {})[lastID] = leaveEl
  3769. var fragOnDom = binding.recoverNodes() // 恢复动画中的节点
  3770. if (fragOnDom) {
  3771. target.insertBefore(fragOnDom, binding.end)
  3772. }
  3773. while (true) {
  3774. var node = binding.start.nextSibling
  3775. if (node && node !== leaveEl && node !== binding.end) {
  3776. leaveEl.appendChild(node)
  3777. } else {
  3778. break
  3779. }
  3780. }
  3781. // 元素退场
  3782. avalon.effect.remove(leaveEl, target, function () {
  3783. if (templateCache) { // write cache
  3784. if (_stamp === binding._stamp)
  3785. ifGroup.appendChild(leaveEl)
  3786. }
  3787. }, binding)
  3788. var enterEl = target,
  3789. before = avalon.noop,
  3790. after = avalon.noop
  3791. var fragment = getTemplateContainer(binding, val, text)
  3792. var nodes = avalon.slice(fragment.childNodes)
  3793. if (outer && effectClass) {
  3794. enterEl = _ele
  3795. enterEl.innerHTML = "" // 清空
  3796. enterEl.setAttribute("ms-skip", "true")
  3797. target.insertBefore(enterEl, binding.end.nextSibling) // 插入到bingding.end之后避免被错误的移动
  3798. before = function () {
  3799. enterEl.insertBefore(fragment, null) // 插入节点
  3800. }
  3801. after = function () {
  3802. binding.recoverNodes = avalon.noop
  3803. if (_stamp === binding._stamp) {
  3804. fragment = nodesToFrag(nodes)
  3805. target.insertBefore(fragment, binding.end) // 插入真实element
  3806. scanNodeArray(nodes, vmodels)
  3807. }
  3808. if (enterEl.parentNode === target)
  3809. target.removeChild(enterEl) // 移除入场动画元素
  3810. }
  3811. binding.recoverNodes = function () {
  3812. binding.recoverNodes = avalon.noop
  3813. return nodesToFrag(nodes)
  3814. }
  3815. } else {
  3816. before = function () {// 新添加元素的动画 
  3817. target.insertBefore(fragment, binding.end)
  3818. scanNodeArray(nodes, vmodels)
  3819. }
  3820. }
  3821. avalon.effect.apply(enterEl, "enter", before, after)
  3822. }
  3823. if (binding.param === "src") {
  3824. if (typeof templatePool[val] === "string") {
  3825. avalon.nextTick(function () {
  3826. scanTemplate(templatePool[val])
  3827. })
  3828. } else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中发出许多相同的请求
  3829. templatePool[val].push(scanTemplate)
  3830. } else {
  3831. var xhr = getXHR()
  3832. xhr.onload = function () {
  3833. var text = xhr.responseText
  3834. for (var f = 0, fn; fn = templatePool[val][f++]; ) {
  3835. fn(text)
  3836. }
  3837. templatePool[val] = text
  3838. }
  3839. xhr.onerror = function () {
  3840. log("ms-include load [" + val + "] error")
  3841. }
  3842. templatePool[val] = [scanTemplate]
  3843. xhr.open("GET", val, true)
  3844. if ("withCredentials" in xhr) {
  3845. xhr.withCredentials = true
  3846. }
  3847. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
  3848. xhr.send(null)
  3849. }
  3850. } else {
  3851. //IE系列与够新的标准浏览器支持通过ID取得元素(firefox14+)
  3852. //http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/
  3853. var el = val && val.nodeType === 1 ? val : DOC.getElementById(val)
  3854. if (el) {
  3855. avalon.nextTick(function () {
  3856. scanTemplate(el.value || el.innerText || el.innerHTML)
  3857. })
  3858. }
  3859. }
  3860. }
  3861. })
  3862. var rdash = /\(([^)]*)\)/
  3863. var onDir = avalon.directive("on", {
  3864. priority: 3000,
  3865. init: function (binding) {
  3866. var value = binding.expr
  3867. binding.type = "on"
  3868. var eventType = binding.param.replace(/-\d+$/, "") // ms-on-mousemove-10
  3869. if (typeof onDir[eventType + "Hook"] === "function") {
  3870. onDir[eventType + "Hook"](binding)
  3871. }
  3872. if (value.indexOf("(") > 0 && value.indexOf(")") > -1) {
  3873. var matched = (value.match(rdash) || ["", ""])[1].trim()
  3874. if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理
  3875. value = value.replace(rdash, "")
  3876. }
  3877. }
  3878. binding.expr = value
  3879. },
  3880. update: function (callback) {
  3881. var binding = this
  3882. var elem = this.element
  3883. callback = function (e) {
  3884. var fn = binding.getter || noop
  3885. return fn.apply(this, binding.args.concat(e))
  3886. }
  3887. var eventType = binding.param.replace(/-\d+$/, "") // ms-on-mousemove-10
  3888. if (eventType === "scan") {
  3889. callback.call(elem, {
  3890. type: eventType
  3891. })
  3892. } else if (typeof binding.specialBind === "function") {
  3893. binding.specialBind(elem, callback)
  3894. } else {
  3895. var removeFn = avalon.bind(elem, eventType, callback)
  3896. }
  3897. binding.rollback = function () {
  3898. if (typeof binding.specialUnbind === "function") {
  3899. binding.specialUnbind()
  3900. } else {
  3901. avalon.unbind(elem, eventType, removeFn)
  3902. }
  3903. }
  3904. }
  3905. })
  3906. avalon.directive("repeat", {
  3907. priority: 90,
  3908. init: function (binding) {
  3909. var type = binding.type
  3910. binding.cache = {} //用于存放代理VM
  3911. binding.enterCount = 0
  3912. var elem = binding.element
  3913. if (elem.nodeType === 1) {
  3914. elem.removeAttribute(binding.name)
  3915. effectBinding(elem, binding)
  3916. binding.param = binding.param || "el"
  3917. binding.sortedCallback = getBindingCallback(elem, "data-with-sorted", binding.vmodels)
  3918. var rendered = getBindingCallback(elem, "data-" + type + "-rendered", binding.vmodels)
  3919. var signature = generateID(type)
  3920. var start = DOC.createComment(signature + ":start")
  3921. var end = binding.element = DOC.createComment(signature + ":end")
  3922. binding.signature = signature
  3923. binding.start = start
  3924. binding.template = avalonFragment.cloneNode(false)
  3925. if (type === "repeat") {
  3926. var parent = elem.parentNode
  3927. parent.replaceChild(end, elem)
  3928. parent.insertBefore(start, end)
  3929. binding.template.appendChild(elem)
  3930. } else {
  3931. while (elem.firstChild) {
  3932. binding.template.appendChild(elem.firstChild)
  3933. }
  3934. elem.appendChild(start)
  3935. elem.appendChild(end)
  3936. parent = elem
  3937. }
  3938. binding.element = end
  3939. if (rendered) {
  3940. var removeFn = avalon.bind(parent, "datasetchanged", function () {
  3941. rendered.apply(parent, parent.args)
  3942. avalon.unbind(parent, "datasetchanged", removeFn)
  3943. parent.msRendered = rendered
  3944. })
  3945. }
  3946. }
  3947. },
  3948. update: function (value, oldValue) {
  3949. var binding = this
  3950. var xtype = this.xtype
  3951. this.enterCount += 1
  3952. var init = !oldValue
  3953. if (init) {
  3954. binding.$outer = {}
  3955. var check0 = "$key"
  3956. var check1 = "$val"
  3957. if (xtype === "array") {
  3958. check0 = "$first"
  3959. check1 = "$last"
  3960. }
  3961. for (var i = 0, v; v = binding.vmodels[i++]; ) {
  3962. if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) {
  3963. binding.$outer = v
  3964. break
  3965. }
  3966. }
  3967. }
  3968. var track = this.track
  3969. if (binding.sortedCallback) { //如果有回调,则让它们排序
  3970. var keys2 = binding.sortedCallback.call(parent, track)
  3971. if (keys2 && Array.isArray(keys2)) {
  3972. track = keys2
  3973. }
  3974. }
  3975. var action = "move"
  3976. binding.$repeat = value
  3977. var fragments = []
  3978. var transation = init && avalonFragment.cloneNode(false)
  3979. var proxies = []
  3980. var param = this.param
  3981. var retain = avalon.mix({}, this.cache)
  3982. var elem = this.element
  3983. var length = track.length
  3984. var parent = elem.parentNode
  3985. for (i = 0; i < length; i++) {
  3986. var keyOrId = track[i] //array为随机数, object 为keyName
  3987. var proxy = retain[keyOrId]
  3988. if (!proxy) {
  3989. proxy = getProxyVM(this)
  3990. proxy.$up = null
  3991. if (xtype === "array") {
  3992. action = "add"
  3993. proxy.$id = keyOrId
  3994. var valueItem = value[i]
  3995. proxy[param] = valueItem //index
  3996. if(Object(valueItem) === valueItem){
  3997. valueItem.$ups = valueItem.$ups || {}
  3998. valueItem.$ups[param] = proxy
  3999. }
  4000. } else {
  4001. action = "append"
  4002. proxy.$key = keyOrId
  4003. proxy.$val = value[keyOrId] //key
  4004. }
  4005. this.cache[keyOrId] = proxy
  4006. var node = proxy.$anchor || (proxy.$anchor = elem.cloneNode(false))
  4007. node.nodeValue = this.signature
  4008. shimController(binding, transation, proxy, fragments, init && !binding.effectDriver)
  4009. decorateProxy(proxy, binding, xtype)
  4010. } else {
  4011. // if (xtype === "array") {
  4012. // proxy[param] = value[i]
  4013. // }
  4014. fragments.push({})
  4015. retain[keyOrId] = true
  4016. }
  4017. //重写proxy
  4018. if (this.enterCount === 1) {// 防止多次进入,导致位置不对
  4019. proxy.$active = false
  4020. proxy.$oldIndex = proxy.$index
  4021. proxy.$active = true
  4022. proxy.$index = i
  4023. }
  4024. if (xtype === "array") {
  4025. proxy.$first = i === 0
  4026. proxy.$last = i === length - 1
  4027. // proxy[param] = value[i]
  4028. } else {
  4029. proxy.$val = toJson(value[keyOrId]) // 这里是处理vm.object = newObject的情况
  4030. }
  4031. proxies.push(proxy)
  4032. }
  4033. this.proxies = proxies
  4034. if (init && !binding.effectDriver) {
  4035. parent.insertBefore(transation, elem)
  4036. fragments.forEach(function (fragment) {
  4037. scanNodeArray(fragment.nodes || [], fragment.vmodels)
  4038. //if(fragment.vmodels.length > 2)
  4039. fragment.nodes = fragment.vmodels = null
  4040. })// jshint ignore:line
  4041. } else {
  4042. var staggerIndex = binding.staggerIndex = 0
  4043. for (keyOrId in retain) {
  4044. if (retain[keyOrId] !== true) {
  4045. action = "del"
  4046. removeItem(retain[keyOrId].$anchor, binding)
  4047. // avalon.log("删除", keyOrId)
  4048. // 相当于delete binding.cache[key]
  4049. proxyRecycler(this.cache, keyOrId, param)
  4050. retain[keyOrId] = null
  4051. }
  4052. }
  4053. // console.log(effectEnterStagger)
  4054. for (i = 0; i < length; i++) {
  4055. proxy = proxies[i]
  4056. keyOrId = xtype === "array" ? proxy.$id : proxy.$key
  4057. var pre = proxies[i - 1]
  4058. var preEl = pre ? pre.$anchor : binding.start
  4059. if (!retain[keyOrId]) {//如果还没有插入到DOM树
  4060. (function (fragment, preElement) {
  4061. var nodes = fragment.nodes
  4062. var vmodels = fragment.vmodels
  4063. if (nodes) {
  4064. staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () {
  4065. parent.insertBefore(fragment.content, preElement.nextSibling)
  4066. scanNodeArray(nodes, vmodels)
  4067. animateRepeat(nodes, 1, binding)
  4068. }, staggerIndex)
  4069. }
  4070. fragment.nodes = fragment.vmodels = null
  4071. })(fragments[i], preEl)// jshint ignore:line
  4072. // avalon.log("插入")
  4073. } else if (proxy.$index !== proxy.$oldIndex) {
  4074. (function (proxy2, preElement) {
  4075. staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () {
  4076. var curNode = removeItem(proxy2.$anchor)// 如果位置被挪动了
  4077. var inserted = avalon.slice(curNode.childNodes)
  4078. parent.insertBefore(curNode, preElement.nextSibling)
  4079. animateRepeat(inserted, 1, binding)
  4080. }, staggerIndex)
  4081. })(proxy, preEl)// jshint ignore:line
  4082. // avalon.log("移动", proxy.$oldIndex, "-->", proxy.$index)
  4083. }
  4084. }
  4085. }
  4086. if (!value.$track) {//如果是非监控对象,那么就将其$events清空,阻止其持续监听
  4087. for (keyOrId in this.cache) {
  4088. proxyRecycler(this.cache, keyOrId, param)
  4089. }
  4090. }
  4091. //repeat --> duplex
  4092. (function (args) {
  4093. parent.args = args
  4094. if (parent.msRendered) {//第一次事件触发,以后直接调用
  4095. parent.msRendered.apply(parent, args)
  4096. }
  4097. })(kernel.newWatch ? arguments : [action]);
  4098. var id = setTimeout(function () {
  4099. clearTimeout(id)
  4100. //触发上层的select回调及自己的rendered回调
  4101. avalon.fireDom(parent, "datasetchanged", {
  4102. bubble: parent.msHasEvent
  4103. })
  4104. })
  4105. this.enterCount -= 1
  4106. }
  4107. })
  4108. "with,each".replace(rword, function (name) {
  4109. directives[name] = avalon.mix({}, directives.repeat, {
  4110. priority: 1400
  4111. })
  4112. })
  4113. function animateRepeat(nodes, isEnter, binding) {
  4114. for (var i = 0, node; node = nodes[i++]; ) {
  4115. if (node.className === binding.effectClass) {
  4116. avalon.effect.apply(node, isEnter, noop, noop, binding)
  4117. }
  4118. }
  4119. }
  4120. function mayStaggerAnimate(staggerTime, callback, index) {
  4121. if (staggerTime) {
  4122. setTimeout(callback, (++index) * staggerTime)
  4123. } else {
  4124. callback()
  4125. }
  4126. return index
  4127. }
  4128. function removeItem(node, binding) {
  4129. var fragment = avalonFragment.cloneNode(false)
  4130. var last = node
  4131. var breakText = last.nodeValue
  4132. var staggerIndex = binding && Math.max(+binding.staggerIndex, 0)
  4133. var nodes = avalon.slice(last.parentNode.childNodes)
  4134. var index = nodes.indexOf(last)
  4135. while (true) {
  4136. var pre = nodes[--index] //node.previousSibling
  4137. if (!pre || String(pre.nodeValue).indexOf(breakText) === 0) {
  4138. break
  4139. }
  4140. if (binding && (pre.className === binding.effectClass)) {
  4141. node = pre;
  4142. (function (cur) {
  4143. binding.staggerIndex = mayStaggerAnimate(binding.effectLeaveStagger, function () {
  4144. avalon.effect.apply(cur, 0, noop, function () {
  4145. fragment.appendChild(cur)
  4146. }, binding)
  4147. }, staggerIndex)
  4148. })(pre);// jshint ignore:line
  4149. } else {
  4150. fragment.insertBefore(pre, fragment.firstChild)
  4151. }
  4152. }
  4153. fragment.appendChild(last)
  4154. return fragment
  4155. }
  4156. function shimController(data, transation, proxy, fragments, init) {
  4157. var content = data.template.cloneNode(true)
  4158. var nodes = avalon.slice(content.childNodes)
  4159. content.appendChild(proxy.$anchor)
  4160. init && transation.appendChild(content)
  4161. var nv = [proxy].concat(data.vmodels)
  4162. var fragment = {
  4163. nodes: nodes,
  4164. vmodels: nv,
  4165. content: content
  4166. }
  4167. fragments.push(fragment)
  4168. }
  4169. // {} --> {xx: 0, yy: 1, zz: 2} add
  4170. // {xx: 0, yy: 1, zz: 2} --> {xx: 0, yy: 1, zz: 2, uu: 3}
  4171. // [xx: 0, yy: 1, zz: 2} --> {xx: 0, zz: 1, yy: 2}
  4172. function getProxyVM(binding) {
  4173. var agent = binding.xtype === "object" ? withProxyAgent : eachProxyAgent
  4174. var proxy = agent(binding)
  4175. var node = proxy.$anchor || (proxy.$anchor = binding.element.cloneNode(false))
  4176. node.nodeValue = binding.signature
  4177. proxy.$outer = binding.$outer
  4178. return proxy
  4179. }
  4180. var eachProxyPool = []
  4181. function eachProxyAgent(data, proxy) {
  4182. var itemName = data.param || "el"
  4183. for (var i = 0, n = eachProxyPool.length; i < n; i++) {
  4184. var candidate = eachProxyPool[i]
  4185. if (candidate && candidate.hasOwnProperty(itemName)) {
  4186. eachProxyPool.splice(i, 1)
  4187. proxy = candidate
  4188. break
  4189. }
  4190. }
  4191. if (!proxy) {
  4192. proxy = eachProxyFactory(itemName)
  4193. }
  4194. return proxy
  4195. }
  4196. function eachProxyFactory(itemName) {
  4197. var source = {
  4198. $outer: {},
  4199. $index: 0,
  4200. $oldIndex: 0,
  4201. $anchor: null,
  4202. //-----
  4203. $first: false,
  4204. $last: false,
  4205. $remove: avalon.noop
  4206. }
  4207. source[itemName] = NaN
  4208. var force = {
  4209. $last: 1,
  4210. $first: 1,
  4211. $index: 1
  4212. }
  4213. force[itemName] = 1
  4214. var proxy = modelFactory(source, {
  4215. force: force
  4216. })
  4217. proxy.$id = generateID("$proxy$each")
  4218. return proxy
  4219. }
  4220. function decorateProxy(proxy, binding, type) {
  4221. if (type === "array") {
  4222. proxy.$remove = function () {
  4223. binding.$repeat.removeAt(proxy.$index)
  4224. }
  4225. var param = binding.param
  4226. proxy.$watch(param, function (a) {
  4227. var index = proxy.$index
  4228. binding.$repeat[index] = a
  4229. })
  4230. } else {
  4231. proxy.$watch("$val", function fn(a) {
  4232. binding.$repeat[proxy.$key] = a
  4233. })
  4234. }
  4235. }
  4236. var withProxyPool = []
  4237. function withProxyAgent() {
  4238. return withProxyPool.pop() || withProxyFactory()
  4239. }
  4240. function withProxyFactory() {
  4241. var proxy = modelFactory({
  4242. $key: "",
  4243. $val: NaN,
  4244. $index: 0,
  4245. $oldIndex: 0,
  4246. $outer: {},
  4247. $anchor: null
  4248. }, {
  4249. force: {
  4250. $key: 1,
  4251. $val: 1,
  4252. $index: 1
  4253. }
  4254. })
  4255. proxy.$id = generateID("$proxy$with")
  4256. return proxy
  4257. }
  4258. function proxyRecycler(cache, key, param) {
  4259. var proxy = cache[key]
  4260. if (proxy) {
  4261. var proxyPool = proxy.$id.indexOf("$proxy$each") === 0 ? eachProxyPool : withProxyPool
  4262. proxy.$outer = {}
  4263. for (var i in proxy.$events) {
  4264. var a = proxy.$events[i]
  4265. if (Array.isArray(a)) {
  4266. a.length = 0
  4267. if (i === param) {
  4268. proxy[param] = NaN
  4269. } else if (i === "$val") {
  4270. proxy.$val = NaN
  4271. }
  4272. }
  4273. }
  4274. if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) {
  4275. proxyPool.pop()
  4276. }
  4277. delete cache[key]
  4278. }
  4279. }
  4280. /*********************************************************************
  4281. * 各种指令 *
  4282. **********************************************************************/
  4283. //ms-skip绑定已经在scanTag 方法中实现
  4284. avalon.directive("text", {
  4285. update: function (val) {
  4286. var elem = this.element
  4287. val = val == null ? "" : val //不在页面上显示undefined null
  4288. if (elem.nodeType === 3) { //绑定在文本节点上
  4289. try { //IE对游离于DOM树外的节点赋值会报错
  4290. elem.data = val
  4291. } catch (e) {
  4292. }
  4293. } else { //绑定在特性节点上
  4294. elem.textContent = val
  4295. }
  4296. }
  4297. })
  4298. function parseDisplay(nodeName, val) {
  4299. //用于取得此类标签的默认display值
  4300. var key = "_" + nodeName
  4301. if (!parseDisplay[key]) {
  4302. var node = DOC.createElement(nodeName)
  4303. root.appendChild(node)
  4304. if (W3C) {
  4305. val = getComputedStyle(node, null).display
  4306. } else {
  4307. val = node.currentStyle.display
  4308. }
  4309. root.removeChild(node)
  4310. parseDisplay[key] = val
  4311. }
  4312. return parseDisplay[key]
  4313. }
  4314. avalon.parseDisplay = parseDisplay
  4315. avalon.directive("visible", {
  4316. init: function (binding) {
  4317. effectBinding(binding.element, binding)
  4318. },
  4319. update: function (val) {
  4320. var binding = this, elem = this.element, stamp
  4321. var noEffect = !this.effectName
  4322. if (!this.stamp) {
  4323. stamp = this.stamp = +new Date
  4324. if (val) {
  4325. elem.style.display = binding.display || ""
  4326. if (avalon(elem).css("display") === "none") {
  4327. elem.style.display = binding.display = parseDisplay(elem.nodeName)
  4328. }
  4329. } else {
  4330. elem.style.display = "none"
  4331. }
  4332. return
  4333. }
  4334. stamp = this.stamp = +new Date
  4335. if (val) {
  4336. avalon.effect.apply(elem, 1, function () {
  4337. if (stamp !== binding.stamp)
  4338. return
  4339. var driver = elem.getAttribute("data-effect-driver") || "a"
  4340. if (noEffect) {//不用动画时走这里
  4341. elem.style.display = binding.display || ""
  4342. }
  4343. // "a", "t"
  4344. if (driver === "a" || driver === "t") {
  4345. if (avalon(elem).css("display") === "none") {
  4346. elem.style.display = binding.display || parseDisplay(elem.nodeName)
  4347. }
  4348. }
  4349. })
  4350. } else {
  4351. avalon.effect.apply(elem, 0, function () {
  4352. if (stamp !== binding.stamp)
  4353. return
  4354. elem.style.display = "none"
  4355. })
  4356. }
  4357. }
  4358. })
  4359. /*********************************************************************
  4360. * 自带过滤器 *
  4361. **********************************************************************/
  4362. var rscripts = /<script[^>]*>([\S\s]*?)<\/script\s*>/gim
  4363. var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g
  4364. var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig
  4365. var rsanitize = {
  4366. a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig,
  4367. img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig,
  4368. form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig
  4369. }
  4370. var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g
  4371. var rnoalphanumeric = /([^\#-~| |!])/g;
  4372. function numberFormat(number, decimals, point, thousands) {
  4373. //form http://phpjs.org/functions/number_format/
  4374. //number 必需,要格式化的数字
  4375. //decimals 可选,规定多少个小数位。
  4376. //point 可选,规定用作小数点的字符串(默认为 . )。
  4377. //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。
  4378. number = (number + '')
  4379. .replace(/[^0-9+\-Ee.]/g, '')
  4380. var n = !isFinite(+number) ? 0 : +number,
  4381. prec = !isFinite(+decimals) ? 3 : Math.abs(decimals),
  4382. sep = thousands || ",",
  4383. dec = point || ".",
  4384. s = '',
  4385. toFixedFix = function(n, prec) {
  4386. var k = Math.pow(10, prec)
  4387. return '' + (Math.round(n * k) / k)
  4388. .toFixed(prec)
  4389. }
  4390. // Fix for IE parseFloat(0.55).toFixed(0) = 0;
  4391. s = (prec ? toFixedFix(n, prec) : '' + Math.round(n))
  4392. .split('.')
  4393. if (s[0].length > 3) {
  4394. s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep)
  4395. }
  4396. if ((s[1] || '')
  4397. .length < prec) {
  4398. s[1] = s[1] || ''
  4399. s[1] += new Array(prec - s[1].length + 1)
  4400. .join('0')
  4401. }
  4402. return s.join(dec)
  4403. }
  4404. var filters = avalon.filters = {
  4405. uppercase: function(str) {
  4406. return str.toUpperCase()
  4407. },
  4408. lowercase: function(str) {
  4409. return str.toLowerCase()
  4410. },
  4411. truncate: function(str, length, truncation) {
  4412. //length,新字符串长度,truncation,新字符串的结尾的字段,返回新字符串
  4413. length = length || 30
  4414. truncation = typeof truncation === "string" ? truncation : "..."
  4415. return str.length > length ? str.slice(0, length - truncation.length) + truncation : String(str)
  4416. },
  4417. $filter: function(val) {
  4418. for (var i = 1, n = arguments.length; i < n; i++) {
  4419. var array = arguments[i]
  4420. var fn = avalon.filters[array[0]]
  4421. if (typeof fn === "function") {
  4422. var arr = [val].concat(array.slice(1))
  4423. val = fn.apply(null, arr)
  4424. }
  4425. }
  4426. return val
  4427. },
  4428. camelize: camelize,
  4429. //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
  4430. // <a href="javasc&NewLine;ript&colon;alert('XSS')">chrome</a>
  4431. // <a href="data:text/html;base64, PGltZyBzcmM9eCBvbmVycm9yPWFsZXJ0KDEpPg==">chrome</a>
  4432. // <a href="jav ascript:alert('XSS');">IE67chrome</a>
  4433. // <a href="jav&#x09;ascript:alert('XSS');">IE67chrome</a>
  4434. // <a href="jav&#x0A;ascript:alert('XSS');">IE67chrome</a>
  4435. sanitize: function(str) {
  4436. return str.replace(rscripts, "").replace(ropen, function(a, b) {
  4437. var match = a.toLowerCase().match(/<(\w+)\s/)
  4438. if (match) { //处理a标签的href属性,img标签的src属性,form标签的action属性
  4439. var reg = rsanitize[match[1]]
  4440. if (reg) {
  4441. a = a.replace(reg, function(s, name, value) {
  4442. var quote = value.charAt(0)
  4443. return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line
  4444. })
  4445. }
  4446. }
  4447. return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件
  4448. })
  4449. },
  4450. escape: function(str) {
  4451. //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 &lt
  4452. return String(str).
  4453. replace(/&/g, '&amp;').
  4454. replace(rsurrogate, function(value) {
  4455. var hi = value.charCodeAt(0)
  4456. var low = value.charCodeAt(1)
  4457. return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';'
  4458. }).
  4459. replace(rnoalphanumeric, function(value) {
  4460. return '&#' + value.charCodeAt(0) + ';'
  4461. }).
  4462. replace(/</g, '&lt;').
  4463. replace(/>/g, '&gt;')
  4464. },
  4465. currency: function(amount, symbol, fractionSize) {
  4466. return (symbol || "\uFFE5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2)
  4467. },
  4468. number: numberFormat
  4469. }
  4470. /*
  4471. 'yyyy': 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
  4472. 'yy': 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
  4473. 'y': 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
  4474. 'MMMM': Month in year (January-December)
  4475. 'MMM': Month in year (Jan-Dec)
  4476. 'MM': Month in year, padded (01-12)
  4477. 'M': Month in year (1-12)
  4478. 'dd': Day in month, padded (01-31)
  4479. 'd': Day in month (1-31)
  4480. 'EEEE': Day in Week,(Sunday-Saturday)
  4481. 'EEE': Day in Week, (Sun-Sat)
  4482. 'HH': Hour in day, padded (00-23)
  4483. 'H': Hour in day (0-23)
  4484. 'hh': Hour in am/pm, padded (01-12)
  4485. 'h': Hour in am/pm, (1-12)
  4486. 'mm': Minute in hour, padded (00-59)
  4487. 'm': Minute in hour (0-59)
  4488. 'ss': Second in minute, padded (00-59)
  4489. 's': Second in minute (0-59)
  4490. 'a': am/pm marker
  4491. 'Z': 4 digit (+sign) representation of the timezone offset (-1200-+1200)
  4492. format string can also be one of the following predefined localizable formats:
  4493. 'medium': equivalent to 'MMM d, y h:mm:ss a' for en_US locale (e.g. Sep 3, 2010 12:05:08 pm)
  4494. 'short': equivalent to 'M/d/yy h:mm a' for en_US locale (e.g. 9/3/10 12:05 pm)
  4495. 'fullDate': equivalent to 'EEEE, MMMM d,y' for en_US locale (e.g. Friday, September 3, 2010)
  4496. 'longDate': equivalent to 'MMMM d, y' for en_US locale (e.g. September 3, 2010
  4497. 'mediumDate': equivalent to 'MMM d, y' for en_US locale (e.g. Sep 3, 2010)
  4498. 'shortDate': equivalent to 'M/d/yy' for en_US locale (e.g. 9/3/10)
  4499. 'mediumTime': equivalent to 'h:mm:ss a' for en_US locale (e.g. 12:05:08 pm)
  4500. 'shortTime': equivalent to 'h:mm a' for en_US locale (e.g. 12:05 pm)
  4501. */
  4502. new function() {// jshint ignore:line
  4503. function toInt(str) {
  4504. return parseInt(str, 10) || 0
  4505. }
  4506. function padNumber(num, digits, trim) {
  4507. var neg = ""
  4508. if (num < 0) {
  4509. neg = '-'
  4510. num = -num
  4511. }
  4512. num = "" + num
  4513. while (num.length < digits)
  4514. num = "0" + num
  4515. if (trim)
  4516. num = num.substr(num.length - digits)
  4517. return neg + num
  4518. }
  4519. function dateGetter(name, size, offset, trim) {
  4520. return function(date) {
  4521. var value = date["get" + name]()
  4522. if (offset > 0 || value > -offset)
  4523. value += offset
  4524. if (value === 0 && offset === -12) {
  4525. value = 12
  4526. }
  4527. return padNumber(value, size, trim)
  4528. }
  4529. }
  4530. function dateStrGetter(name, shortForm) {
  4531. return function(date, formats) {
  4532. var value = date["get" + name]()
  4533. var get = (shortForm ? ("SHORT" + name) : name).toUpperCase()
  4534. return formats[get][value]
  4535. }
  4536. }
  4537. function timeZoneGetter(date) {
  4538. var zone = -1 * date.getTimezoneOffset()
  4539. var paddedZone = (zone >= 0) ? "+" : ""
  4540. paddedZone += padNumber(Math[zone > 0 ? "floor" : "ceil"](zone / 60), 2) + padNumber(Math.abs(zone % 60), 2)
  4541. return paddedZone
  4542. }
  4543. //取得上午下午
  4544. function ampmGetter(date, formats) {
  4545. return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1]
  4546. }
  4547. var DATE_FORMATS = {
  4548. yyyy: dateGetter("FullYear", 4),
  4549. yy: dateGetter("FullYear", 2, 0, true),
  4550. y: dateGetter("FullYear", 1),
  4551. MMMM: dateStrGetter("Month"),
  4552. MMM: dateStrGetter("Month", true),
  4553. MM: dateGetter("Month", 2, 1),
  4554. M: dateGetter("Month", 1, 1),
  4555. dd: dateGetter("Date", 2),
  4556. d: dateGetter("Date", 1),
  4557. HH: dateGetter("Hours", 2),
  4558. H: dateGetter("Hours", 1),
  4559. hh: dateGetter("Hours", 2, -12),
  4560. h: dateGetter("Hours", 1, -12),
  4561. mm: dateGetter("Minutes", 2),
  4562. m: dateGetter("Minutes", 1),
  4563. ss: dateGetter("Seconds", 2),
  4564. s: dateGetter("Seconds", 1),
  4565. sss: dateGetter("Milliseconds", 3),
  4566. EEEE: dateStrGetter("Day"),
  4567. EEE: dateStrGetter("Day", true),
  4568. a: ampmGetter,
  4569. Z: timeZoneGetter
  4570. }
  4571. var rdateFormat = /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/
  4572. var raspnetjson = /^\/Date\((\d+)\)\/$/
  4573. filters.date = function(date, format) {
  4574. var locate = filters.date.locate,
  4575. text = "",
  4576. parts = [],
  4577. fn, match
  4578. format = format || "mediumDate"
  4579. format = locate[format] || format
  4580. if (typeof date === "string") {
  4581. if (/^\d+$/.test(date)) {
  4582. date = toInt(date)
  4583. } else if (raspnetjson.test(date)) {
  4584. date = +RegExp.$1
  4585. } else {
  4586. var trimDate = date.trim()
  4587. var dateArray = [0, 0, 0, 0, 0, 0, 0]
  4588. var oDate = new Date(0)
  4589. //取得年月日
  4590. trimDate = trimDate.replace(/^(\d+)\D(\d+)\D(\d+)/, function(_, a, b, c) {
  4591. var array = c.length === 4 ? [c, a, b] : [a, b, c]
  4592. dateArray[0] = toInt(array[0]) //年
  4593. dateArray[1] = toInt(array[1]) - 1 //月
  4594. dateArray[2] = toInt(array[2]) //日
  4595. return ""
  4596. })
  4597. var dateSetter = oDate.setFullYear
  4598. var timeSetter = oDate.setHours
  4599. trimDate = trimDate.replace(/[T\s](\d+):(\d+):?(\d+)?\.?(\d)?/, function(_, a, b, c, d) {
  4600. dateArray[3] = toInt(a) //小时
  4601. dateArray[4] = toInt(b) //分钟
  4602. dateArray[5] = toInt(c) //秒
  4603. if (d) { //毫秒
  4604. dateArray[6] = Math.round(parseFloat("0." + d) * 1000)
  4605. }
  4606. return ""
  4607. })
  4608. var tzHour = 0
  4609. var tzMin = 0
  4610. trimDate = trimDate.replace(/Z|([+-])(\d\d):?(\d\d)/, function(z, symbol, c, d) {
  4611. dateSetter = oDate.setUTCFullYear
  4612. timeSetter = oDate.setUTCHours
  4613. if (symbol) {
  4614. tzHour = toInt(symbol + c)
  4615. tzMin = toInt(symbol + d)
  4616. }
  4617. return ""
  4618. })
  4619. dateArray[3] -= tzHour
  4620. dateArray[4] -= tzMin
  4621. dateSetter.apply(oDate, dateArray.slice(0, 3))
  4622. timeSetter.apply(oDate, dateArray.slice(3))
  4623. date = oDate
  4624. }
  4625. }
  4626. if (typeof date === "number") {
  4627. date = new Date(date)
  4628. }
  4629. if (avalon.type(date) !== "date") {
  4630. return
  4631. }
  4632. while (format) {
  4633. match = rdateFormat.exec(format)
  4634. if (match) {
  4635. parts = parts.concat(match.slice(1))
  4636. format = parts.pop()
  4637. } else {
  4638. parts.push(format)
  4639. format = null
  4640. }
  4641. }
  4642. parts.forEach(function(value) {
  4643. fn = DATE_FORMATS[value]
  4644. text += fn ? fn(date, locate) : value.replace(/(^'|'$)/g, "").replace(/''/g, "'")
  4645. })
  4646. return text
  4647. }
  4648. var locate = {
  4649. AMPMS: {
  4650. 0: "上午",
  4651. 1: "下午"
  4652. },
  4653. DAY: {
  4654. 0: "星期日",
  4655. 1: "星期一",
  4656. 2: "星期二",
  4657. 3: "星期三",
  4658. 4: "星期四",
  4659. 5: "星期五",
  4660. 6: "星期六"
  4661. },
  4662. MONTH: {
  4663. 0: "1月",
  4664. 1: "2月",
  4665. 2: "3月",
  4666. 3: "4月",
  4667. 4: "5月",
  4668. 5: "6月",
  4669. 6: "7月",
  4670. 7: "8月",
  4671. 8: "9月",
  4672. 9: "10月",
  4673. 10: "11月",
  4674. 11: "12月"
  4675. },
  4676. SHORTDAY: {
  4677. "0": "周日",
  4678. "1": "周一",
  4679. "2": "周二",
  4680. "3": "周三",
  4681. "4": "周四",
  4682. "5": "周五",
  4683. "6": "周六"
  4684. },
  4685. fullDate: "y年M月d日EEEE",
  4686. longDate: "y年M月d日",
  4687. medium: "yyyy-M-d H:mm:ss",
  4688. mediumDate: "yyyy-M-d",
  4689. mediumTime: "H:mm:ss",
  4690. "short": "yy-M-d ah:mm",
  4691. shortDate: "yy-M-d",
  4692. shortTime: "ah:mm"
  4693. }
  4694. locate.SHORTMONTH = locate.MONTH
  4695. filters.date.locate = locate
  4696. }// jshint ignore:line
  4697. /*********************************************************************
  4698. * AMD加载器 *
  4699. **********************************************************************/
  4700. //https://www.devbridge.com/articles/understanding-amd-requirejs/
  4701. //http://maxogden.com/nested-dependencies.html
  4702. var modules = avalon.modules = {
  4703. "domReady!": {
  4704. exports: avalon,
  4705. state: 3
  4706. },
  4707. "avalon": {
  4708. exports: avalon,
  4709. state: 4
  4710. }
  4711. }
  4712. //Object(modules[id]).state拥有如下值
  4713. // undefined 没有定义
  4714. // 1(send) 已经发出请求
  4715. // 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行
  4716. // 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行
  4717. // 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行
  4718. modules.exports = modules.avalon
  4719. var otherRequire = window.require
  4720. var otherDefine = window.define
  4721. var innerRequire
  4722. plugins.loader = function (builtin) {
  4723. var flag = innerRequire && builtin
  4724. window.require = flag ? innerRequire : otherRequire
  4725. window.define = flag ? innerRequire.define : otherDefine
  4726. }
  4727. new function () {// jshint ignore:line
  4728. var loadings = [] //正在加载中的模块列表
  4729. var factorys = [] //放置define方法的factory函数
  4730. var rjsext = /\.js$/i
  4731. function makeRequest(name, config) {
  4732. //1. 去掉资源前缀
  4733. var res = "js"
  4734. name = name.replace(/^(\w+)\!/, function (a, b) {
  4735. res = b
  4736. return ""
  4737. })
  4738. if (res === "ready") {
  4739. log("debug: ready!已经被废弃,请使用domReady!")
  4740. res = "domReady"
  4741. }
  4742. //2. 去掉querystring, hash
  4743. var query = ""
  4744. name = name.replace(rquery, function (a) {
  4745. query = a
  4746. return ""
  4747. })
  4748. //3. 去掉扩展名
  4749. var suffix = "." + res
  4750. var ext = /js|css/.test(suffix) ? suffix : ""
  4751. name = name.replace(/\.[a-z0-9]+$/g, function (a) {
  4752. if (a === suffix) {
  4753. ext = a
  4754. return ""
  4755. } else {
  4756. return a
  4757. }
  4758. })
  4759. var req = avalon.mix({
  4760. query: query,
  4761. ext: ext,
  4762. res: res,
  4763. name: name,
  4764. toUrl: toUrl
  4765. }, config)
  4766. req.toUrl(name)
  4767. return req
  4768. }
  4769. function fireRequest(req) {
  4770. var name = req.name
  4771. var res = req.res
  4772. //1. 如果该模块已经发出请求,直接返回
  4773. var module = modules[name]
  4774. var urlNoQuery = name && req.urlNoQuery
  4775. if (module && module.state >= 1) {
  4776. return name
  4777. }
  4778. module = modules[urlNoQuery]
  4779. if (module && module.state >= 3) {
  4780. innerRequire(module.deps || [], module.factory, urlNoQuery)
  4781. return urlNoQuery
  4782. }
  4783. if (name && !module) {
  4784. module = modules[urlNoQuery] = {
  4785. id: urlNoQuery,
  4786. state: 1 //send
  4787. }
  4788. var wrap = function (obj) {
  4789. resources[res] = obj
  4790. obj.load(name, req, function (a) {
  4791. if (arguments.length && a !== void 0) {
  4792. module.exports = a
  4793. }
  4794. module.state = 4
  4795. checkDeps()
  4796. })
  4797. }
  4798. if (!resources[res]) {
  4799. innerRequire([res], wrap)
  4800. } else {
  4801. wrap(resources[res])
  4802. }
  4803. }
  4804. return name ? urlNoQuery : res + "!"
  4805. }
  4806. //核心API之一 require
  4807. var requireQueue = []
  4808. var isUserFirstRequire = false
  4809. innerRequire = avalon.require = function (array, factory, parentUrl, defineConfig) {
  4810. if (!isUserFirstRequire) {
  4811. requireQueue.push(avalon.slice(arguments))
  4812. if (arguments.length <= 2) {
  4813. isUserFirstRequire = true
  4814. var queue = requireQueue.splice(0, requireQueue.length), args
  4815. while (args = queue.shift()) {
  4816. innerRequire.apply(null, args)
  4817. }
  4818. }
  4819. return
  4820. }
  4821. if (!Array.isArray(array)) {
  4822. avalon.error("require方法的第一个参数应为数组 " + array)
  4823. }
  4824. var deps = [] // 放置所有依赖项的完整路径
  4825. var uniq = createMap()
  4826. var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line
  4827. defineConfig = defineConfig || createMap()
  4828. defineConfig.baseUrl = kernel.baseUrl
  4829. var isBuilt = !!defineConfig.built
  4830. if (parentUrl) {
  4831. defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/"))
  4832. defineConfig.mapUrl = parentUrl.replace(rjsext, "")
  4833. }
  4834. if (isBuilt) {
  4835. var req = makeRequest(defineConfig.defineName, defineConfig)
  4836. id = req.urlNoQuery
  4837. } else {
  4838. array.forEach(function (name) {
  4839. var req = makeRequest(name, defineConfig)
  4840. var url = fireRequest(req) //加载资源,并返回该资源的完整地址
  4841. if (url) {
  4842. if (!uniq[url]) {
  4843. deps.push(url)
  4844. uniq[url] = "司徒正美" //去重
  4845. }
  4846. }
  4847. })
  4848. }
  4849. var module = modules[id]
  4850. if (!module || module.state !== 4) {
  4851. modules[id] = {
  4852. id: id,
  4853. deps: isBuilt ? array.concat() : deps,
  4854. factory: factory || noop,
  4855. state: 3
  4856. }
  4857. }
  4858. if (!module) {
  4859. //如果此模块是定义在另一个JS文件中, 那必须等该文件加载完毕, 才能放到检测列队中
  4860. loadings.push(id)
  4861. }
  4862. checkDeps()
  4863. }
  4864. //核心API之二 require
  4865. innerRequire.define = function (name, deps, factory) { //模块名,依赖列表,模块本身
  4866. if (typeof name !== "string") {
  4867. factory = deps
  4868. deps = name
  4869. name = "anonymous"
  4870. }
  4871. if (!Array.isArray(deps)) {
  4872. factory = deps
  4873. deps = []
  4874. }
  4875. var config = {
  4876. built: !isUserFirstRequire, //用r.js打包后,所有define会放到requirejs之前
  4877. defineName: name
  4878. }
  4879. var args = [deps, factory, config]
  4880. factory.require = function (url) {
  4881. args.splice(2, 0, url)
  4882. if (modules[url]) {
  4883. modules[url].state = 3 //loaded
  4884. var isCycle = false
  4885. try {
  4886. isCycle = checkCycle(modules[url].deps, url)
  4887. } catch (e) {
  4888. }
  4889. if (isCycle) {
  4890. avalon.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块")
  4891. }
  4892. }
  4893. delete factory.require //释放内存
  4894. innerRequire.apply(null, args) //0,1,2 --> 1,2,0
  4895. }
  4896. //根据标准,所有遵循W3C标准的浏览器,script标签会按标签的出现顺序执行。
  4897. //老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。
  4898. //较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验,
  4899. //下载可以是并行的,但是执行顺序还是按照标签出现的顺序。
  4900. //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守
  4901. //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕
  4902. //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段
  4903. var url = config.built ? "unknown" : getCurrentScript()
  4904. if (url) {
  4905. var module = modules[url]
  4906. if (module) {
  4907. module.state = 2
  4908. }
  4909. factory.require(url)
  4910. } else {//合并前后的safari,合并后的IE6-9走此分支
  4911. factorys.push(factory)
  4912. }
  4913. }
  4914. //核心API之三 require.config(settings)
  4915. innerRequire.config = kernel
  4916. //核心API之四 define.amd 标识其符合AMD规范
  4917. innerRequire.define.amd = modules
  4918. //==========================对用户配置项进行再加工==========================
  4919. var allpaths = kernel["orig.paths"] = createMap()
  4920. var allmaps = kernel["orig.map"] = createMap()
  4921. var allpackages = kernel["packages"] = []
  4922. var allargs = kernel["orig.args"] = createMap()
  4923. avalon.mix(plugins, {
  4924. paths: function (hash) {
  4925. avalon.mix(allpaths, hash)
  4926. kernel.paths = makeIndexArray(allpaths)
  4927. },
  4928. map: function (hash) {
  4929. avalon.mix(allmaps, hash)
  4930. var list = makeIndexArray(allmaps, 1, 1)
  4931. avalon.each(list, function (_, item) {
  4932. item.val = makeIndexArray(item.val)
  4933. })
  4934. kernel.map = list
  4935. },
  4936. packages: function (array) {
  4937. array = array.concat(allpackages)
  4938. var uniq = createMap()
  4939. var ret = []
  4940. for (var i = 0, pkg; pkg = array[i++]; ) {
  4941. pkg = typeof pkg === "string" ? {name: pkg} : pkg
  4942. var name = pkg.name
  4943. if (!uniq[name]) {
  4944. var url = joinPath(pkg.location || name, pkg.main || "main")
  4945. url = url.replace(rjsext, "")
  4946. ret.push(pkg)
  4947. uniq[name] = pkg.location = url
  4948. pkg.reg = makeMatcher(name)
  4949. }
  4950. }
  4951. kernel.packages = ret.sort()
  4952. },
  4953. urlArgs: function (hash) {
  4954. if (typeof hash === "string") {
  4955. hash = {"*": hash}
  4956. }
  4957. avalon.mix(allargs, hash)
  4958. kernel.urlArgs = makeIndexArray(allargs, 1)
  4959. },
  4960. baseUrl: function (url) {
  4961. if (!isAbsUrl(url)) {
  4962. var baseElement = head.getElementsByTagName("base")[0]
  4963. if (baseElement) {
  4964. head.removeChild(baseElement)
  4965. }
  4966. var node = DOC.createElement("a")
  4967. node.href = url
  4968. url = node.href
  4969. if (baseElement) {
  4970. head.insertBefore(baseElement, head.firstChild)
  4971. }
  4972. }
  4973. if (url.length > 3)
  4974. kernel.baseUrl = url
  4975. },
  4976. shim: function (obj) {
  4977. for (var i in obj) {
  4978. var value = obj[i]
  4979. if (Array.isArray(value)) {
  4980. value = obj[i] = {
  4981. deps: value
  4982. }
  4983. }
  4984. if (!value.exportsFn && (value.exports || value.init)) {
  4985. value.exportsFn = makeExports(value)
  4986. }
  4987. }
  4988. kernel.shim = obj
  4989. }
  4990. })
  4991. //==============================内部方法=================================
  4992. function checkCycle(deps, nick) {
  4993. //检测是否存在循环依赖
  4994. for (var i = 0, id; id = deps[i++]; ) {
  4995. if (modules[id].state !== 4 &&
  4996. (id === nick || checkCycle(modules[id].deps, nick))) {
  4997. return true
  4998. }
  4999. }
  5000. }
  5001. function checkFail(node, onError) {
  5002. var id = trimQuery(node.src) //检测是否死链
  5003. node.onload = node.onerror = null
  5004. if (onError) {
  5005. setTimeout(function () {
  5006. head.removeChild(node)
  5007. node = null // 处理旧式IE下的循环引用问题
  5008. })
  5009. log("debug: 加载 " + id + " 失败" + onError + " " + (!modules[id].state))
  5010. } else {
  5011. return true
  5012. }
  5013. }
  5014. function checkDeps() {
  5015. //检测此JS模块的依赖是否都已安装完毕,是则安装自身
  5016. loop: for (var i = loadings.length, id; id = loadings[--i]; ) {
  5017. var obj = modules[id],
  5018. deps = obj.deps
  5019. if (!deps)
  5020. continue
  5021. for (var j = 0, key; key = deps[j]; j++) {
  5022. if (Object(modules[key]).state !== 4) {
  5023. continue loop
  5024. }
  5025. }
  5026. //如果deps是空对象或者其依赖的模块的状态都是4
  5027. if (obj.state !== 4) {
  5028. loadings.splice(i, 1) //必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它
  5029. fireFactory(obj.id, obj.deps, obj.factory)
  5030. checkDeps() //如果成功,则再执行一次,以防有些模块就差本模块没有安装好
  5031. }
  5032. }
  5033. }
  5034. function loadJS(url, id, callback) {
  5035. //通过script节点加载目标模块
  5036. var node = DOC.createElement("script")
  5037. node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点
  5038. node.onload = function () {
  5039. var factory = factorys.pop()
  5040. factory && factory.require(id)
  5041. if (callback) {
  5042. callback()
  5043. }
  5044. log("debug: 已成功加载 " + url)
  5045. id && loadings.push(id)
  5046. checkDeps()
  5047. }
  5048. node.onerror = function () {
  5049. checkFail(node, true)
  5050. }
  5051. head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null
  5052. node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错
  5053. log("debug: 正准备加载 " + url) //更重要的是IE6下可以收窄getCurrentScript的寻找范围
  5054. }
  5055. var resources = innerRequire.plugins = {
  5056. //三大常用资源插件 js!, css!, text!, domReady!
  5057. domReady: {
  5058. load: noop
  5059. },
  5060. js: {
  5061. load: function (name, req, onLoad) {
  5062. var url = req.url
  5063. var id = req.urlNoQuery
  5064. var shim = kernel.shim[name.replace(rjsext, "")]
  5065. if (shim) { //shim机制
  5066. innerRequire(shim.deps || [], function () {
  5067. var args = avalon.slice(arguments)
  5068. loadJS(url, id, function () {
  5069. onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0)
  5070. })
  5071. })
  5072. } else {
  5073. loadJS(url, id)
  5074. }
  5075. }
  5076. },
  5077. css: {
  5078. load: function (name, req, onLoad) {
  5079. var url = req.url
  5080. head.insertAdjacentHTML("afterBegin", '<link rel="stylesheet" href="' + url + '">')
  5081. log("debug: 已成功加载 " + url)
  5082. onLoad()
  5083. }
  5084. },
  5085. text: {
  5086. load: function (name, req, onLoad) {
  5087. var url = req.url
  5088. var xhr = getXHR()
  5089. xhr.onload = function () {
  5090. var status = xhr.status;
  5091. if (status > 399 && status < 600) {
  5092. avalon.error(url + " 对应资源不存在或没有开启 CORS")
  5093. } else {
  5094. log("debug: 已成功加载 " + url)
  5095. onLoad(xhr.responseText)
  5096. }
  5097. }
  5098. var time = "_=" + (new Date() - 0)
  5099. var _url = url.indexOf("?") === -1 ? url + "?" + time : url + "&" + time
  5100. xhr.open("GET", _url, true)
  5101. if ("withCredentials" in xhr) {//这是处理跨域
  5102. xhr.withCredentials = true
  5103. }
  5104. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")//告诉后端这是AJAX请求
  5105. xhr.send()
  5106. log("debug: 正准备加载 " + url)
  5107. }
  5108. }
  5109. }
  5110. innerRequire.checkDeps = checkDeps
  5111. var rquery = /(\?[^#]*)$/
  5112. function trimQuery(url) {
  5113. return (url || "").replace(rquery, "")
  5114. }
  5115. function isAbsUrl(path) {
  5116. //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative
  5117. return /^(?:[a-z]+:)?\/\//i.test(String(path))
  5118. }
  5119. function getCurrentScript() {
  5120. // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js
  5121. var stack
  5122. try {
  5123. a.b.c() //强制报错,以便捕获e.stack
  5124. } catch (e) { //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样
  5125. stack = e.stack
  5126. }
  5127. if (stack) {
  5128. /**e.stack最后一行在所有支持的浏览器大致如下:
  5129. *chrome23:
  5130. * at http://113.93.50.63/data.js:4:1
  5131. *firefox17:
  5132. *@http://113.93.50.63/query.js:4
  5133. *opera12:http://www.oldapps.com/opera.php?system=Windows_XP
  5134. *@http://113.93.50.63/data.js:4
  5135. *IE10:
  5136. * at Global code (http://113.93.50.63/data.js:4:1)
  5137. * //firefox4+ 可以用document.currentScript
  5138. */
  5139. stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分
  5140. stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符
  5141. return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行号与或许存在的出错字符起始位置
  5142. }
  5143. var nodes = head.getElementsByTagName("script") //只在head标签中寻找
  5144. for (var i = nodes.length, node; node = nodes[--i]; ) {
  5145. if (node.className === subscribers && node.readyState === "interactive") {
  5146. var url = node.src
  5147. return node.className = trimQuery(url)
  5148. }
  5149. }
  5150. }
  5151. var rcallback = /^callback\d+$/
  5152. function fireFactory(id, deps, factory) {
  5153. var module = Object(modules[id])
  5154. module.state = 4
  5155. for (var i = 0, array = [], d; d = deps[i++]; ) {
  5156. if (d === "exports") {
  5157. var obj = module.exports || (module.exports = createMap())
  5158. array.push(obj)
  5159. } else {
  5160. array.push(modules[d].exports)
  5161. }
  5162. }
  5163. try {
  5164. var ret = factory.apply(window, array)
  5165. } catch (e) {
  5166. log("执行[" + id + "]模块的factory抛错: ", e)
  5167. }
  5168. if (ret !== void 0) {
  5169. module.exports = ret
  5170. }
  5171. if (rcallback.test(id)) {
  5172. delete modules[id]
  5173. }
  5174. delete module.factory
  5175. return ret
  5176. }
  5177. function toUrl(id) {
  5178. if (id.indexOf(this.res + "!") === 0) {
  5179. id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况
  5180. }
  5181. var url = id
  5182. //1. 是否命中paths配置项
  5183. var usePath = 0
  5184. var baseUrl = this.baseUrl
  5185. var rootUrl = this.parentUrl || baseUrl
  5186. eachIndexArray(id, kernel.paths, function (value, key) {
  5187. url = url.replace(key, value)
  5188. usePath = 1
  5189. })
  5190. //2. 是否命中packages配置项
  5191. if (!usePath) {
  5192. eachIndexArray(id, kernel.packages, function (value, key, item) {
  5193. url = url.replace(item.name, item.location)
  5194. })
  5195. }
  5196. //3. 是否命中map配置项
  5197. if (this.mapUrl) {
  5198. eachIndexArray(this.mapUrl, kernel.map, function (array) {
  5199. eachIndexArray(url, array, function (mdValue, mdKey) {
  5200. url = url.replace(mdKey, mdValue)
  5201. rootUrl = baseUrl
  5202. })
  5203. })
  5204. }
  5205. var ext = this.ext
  5206. if (ext && usePath && url.slice(-ext.length) === ext) {
  5207. url = url.slice(0, -ext.length)
  5208. }
  5209. //4. 转换为绝对路径
  5210. if (!isAbsUrl(url)) {
  5211. rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl
  5212. url = joinPath(rootUrl, url)
  5213. }
  5214. //5. 还原扩展名,query
  5215. var urlNoQuery = url + ext
  5216. url = urlNoQuery + this.query
  5217. urlNoQuery = url.replace(rquery, function (a) {
  5218. this.query = a
  5219. return ""
  5220. })
  5221. //6. 处理urlArgs
  5222. eachIndexArray(id, kernel.urlArgs, function (value) {
  5223. url += (url.indexOf("?") === -1 ? "?" : "&") + value;
  5224. })
  5225. this.url = url
  5226. return this.urlNoQuery = urlNoQuery
  5227. }
  5228. function makeIndexArray(hash, useStar, part) {
  5229. //创建一个经过特殊算法排好序的数组
  5230. var index = hash2array(hash, useStar, part)
  5231. index.sort(descSorterByName)
  5232. return index
  5233. }
  5234. function makeMatcher(prefix) {
  5235. return new RegExp('^' + prefix + '(/|$)')
  5236. }
  5237. function makeExports(value) {
  5238. return function () {
  5239. var ret
  5240. if (value.init) {
  5241. ret = value.init.apply(window, arguments)
  5242. }
  5243. return ret || (value.exports && getGlobal(value.exports))
  5244. }
  5245. }
  5246. function hash2array(hash, useStar, part) {
  5247. var array = [];
  5248. for (var key in hash) {
  5249. // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty
  5250. var item = {
  5251. name: key,
  5252. val: hash[key]
  5253. }
  5254. array.push(item)
  5255. item.reg = key === "*" && useStar ? /^/ : makeMatcher(key)
  5256. if (part && key !== "*") {
  5257. item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)')
  5258. }
  5259. // }
  5260. }
  5261. return array
  5262. }
  5263. function eachIndexArray(moduleID, array, matcher) {
  5264. array = array || []
  5265. for (var i = 0, el; el = array[i++]; ) {
  5266. if (el.reg.test(moduleID)) {
  5267. matcher(el.val, el.name, el)
  5268. return false
  5269. }
  5270. }
  5271. }
  5272. // 根据元素的name项进行数组字符数逆序的排序函数
  5273. function descSorterByName(a, b) {
  5274. var aaa = a.name
  5275. var bbb = b.name
  5276. if (bbb === "*") {
  5277. return -1
  5278. }
  5279. if (aaa === "*") {
  5280. return 1
  5281. }
  5282. return bbb.length - aaa.length
  5283. }
  5284. var rdeuce = /\/\w+\/\.\./
  5285. function joinPath(a, b) {
  5286. if (a.charAt(a.length - 1) !== "/") {
  5287. a += "/"
  5288. }
  5289. if (b.slice(0, 2) === "./") { //相对于兄弟路径
  5290. return a + b.slice(2)
  5291. }
  5292. if (b.slice(0, 2) === "..") { //相对于父路径
  5293. a += b
  5294. while (rdeuce.test(a)) {
  5295. a = a.replace(rdeuce, "")
  5296. }
  5297. return a
  5298. }
  5299. if (b.slice(0, 1) === "/") {
  5300. return a + b.slice(1)
  5301. }
  5302. return a + b
  5303. }
  5304. function getGlobal(value) {
  5305. if (!value) {
  5306. return value
  5307. }
  5308. var g = window
  5309. value.split(".").forEach(function (part) {
  5310. g = g[part]
  5311. })
  5312. return g
  5313. }
  5314. var mainNode = DOC.scripts[DOC.scripts.length - 1]
  5315. var dataMain = mainNode.getAttribute("data-main")
  5316. if (dataMain) {
  5317. plugins.baseUrl(dataMain)
  5318. var href = kernel.baseUrl
  5319. kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1)
  5320. loadJS(href.replace(rjsext, "") + ".js")
  5321. } else {
  5322. var loaderUrl = trimQuery(mainNode.src)
  5323. kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1)
  5324. }
  5325. }// jshint ignore:line
  5326. /*********************************************************************
  5327. * DOMReady *
  5328. **********************************************************************/
  5329. var readyList = [],
  5330. isReady
  5331. var fireReady = function (fn) {
  5332. isReady = true
  5333. var require = avalon.require
  5334. if (require && require.checkDeps) {
  5335. modules["domReady!"].state = 4
  5336. require.checkDeps()
  5337. }
  5338. while (fn = readyList.shift()) {
  5339. fn(avalon)
  5340. }
  5341. }
  5342. if (DOC.readyState === "complete") {
  5343. setTimeout(fireReady) //如果在domReady之外加载
  5344. } else {
  5345. DOC.addEventListener("DOMContentLoaded", fireReady)
  5346. }
  5347. window.addEventListener("load", fireReady)
  5348. avalon.ready = function (fn) {
  5349. if (!isReady) {
  5350. readyList.push(fn)
  5351. } else {
  5352. fn(avalon)
  5353. }
  5354. }
  5355. avalon.config({
  5356. loader: false
  5357. })
  5358. avalon.ready(function () {
  5359. avalon.scan(DOC.body)
  5360. })
  5361. // Register as a named AMD module, since avalon can be concatenated with other
  5362. // files that may use define, but not via a proper concatenation script that
  5363. // understands anonymous AMD modules. A named AMD is safest and most robust
  5364. // way to register. Lowercase avalon is used because AMD module names are
  5365. // derived from file names, and Avalon is normally delivered in a lowercase
  5366. // file name. Do this after creating the global so that if an AMD module wants
  5367. // to call noConflict to hide this version of avalon, it will work.
  5368. // Note that for maximum portability, libraries that are not avalon should
  5369. // declare themselves as anonymous modules, and avoid setting a global if an
  5370. // AMD loader is present. avalon is a special case. For more information, see
  5371. // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
  5372. if (typeof define === "function" && define.amd) {
  5373. define("avalon", [], function() {
  5374. return avalon
  5375. })
  5376. }
  5377. // Map over avalon in case of overwrite
  5378. var _avalon = window.avalon
  5379. avalon.noConflict = function(deep) {
  5380. if (deep && window.avalon === avalon) {
  5381. window.avalon = _avalon
  5382. }
  5383. return avalon
  5384. }
  5385. // Expose avalon identifiers, even in AMD
  5386. // and CommonJS for browser emulators
  5387. if (noGlobal === void 0) {
  5388. window.avalon = avalon
  5389. }
  5390. return avalon
  5391. }));