zepto. js 소스 코드 분석

Zepto 는 현대 고급 브 라 우 저 를 위 한 가 벼 운 자바 스 크 립 트 라 이브 러 리 로 jquery 와 유사 한 api 를 가지 고 있 습 니 다.만약 당신 이 jquery 를 사용 할 수 있다 면, 당신 도 zepto 를 사용 할 것 입 니 다.
Zepto 중국어 매 뉴 얼:http://www.w3cschool.cc/manual/zeptojs.html
/* Zepto v1.0-1-ga3cab6c - polyfill zepto detect event ajax form fx - zeptojs.com/license */ ;(function(undefined) { if (String.prototype.trim === undefined) // fix for iOS 3.2 String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, '') } // For iOS 3.x // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce //                    ,                    //  [1,2,3,4,].reduce(function(x,y){ return x+y}); ==> ((1+2)+3)+4, if (Array.prototype.reduce === undefined) Array.prototype.reduce = function(fun) { if (this === void 0 || this === null) throw new TypeError() var t = Object(this), len = t.length >>> 0, k = 0, accumulator if (typeof fun != 'function') throw new TypeError() if (len == 0 && arguments.length == 1) throw new TypeError() //      if (arguments.length >= 2) accumulator = arguments[1] //        2 ,             else do { if (k in t) { accumulator = t[k++] //                 break } if (++k >= len) throw new TypeError() //            ??? } while (true) //    ,                    while (k < len) { if (k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t) k++ } return accumulator } })() var Zepto = (function() { var undefined, key, $, classList, emptyArray = [], slice = emptyArray.slice, filter = emptyArray.filter, document = window.document, elementDisplay = {}, classCache = {}, getComputedStyle = document.defaultView.getComputedStyle, //  CSS ,   px      cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1, 'opacity': 1, 'z-index': 1, 'zoom': 1 }, //HTML        fragmentRE = /^\s*<(\w+|!)[^>]*>/, //              ,   <div></div>   <div/> tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, //    rootNodeRE = /^(?:body|html)$/i, //    get set     // special attributes that should be get/set via method calls methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], //          adjacencyOperators = ['after', 'prepend', 'before', 'append'], table = document.createElement('table'), tableRow = document.createElement('tr'), //          tr,tbody,thead,tfoot,td,th  innerHTMl   ,              HTML    containers = { 'tr': document.createElement('tbody'), 'tbody': table, 'thead': table, 'tfoot': table, 'td': tableRow, 'th': tableRow, '*': document.createElement('div') }, // DOM ready   ,document            readyRE = /complete|loaded|interactive/, //class       classSelectorRE = /^\.([\w-]+)$/, //id       idSelectorRE = /^#([\w-]*)$/, //DOM     tagSelectorRE = /^[\w-]+$/, class2type = {}, toString = class2type.toString, zepto = {}, camelize, uniq, tempParent = document.createElement('div'); //                 zepto.matches = function(element, selector) { if (!element || element.nodeType !== 1) return false //        MatchesSelector   var matchesSelector = element.webkitMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.matchesSelector if (matchesSelector) return matchesSelector.call(element, selector); //        MatchesSelector  ,          div  , //   selector     div     ,      element       ,   ,       (  false)    // fall back to performing a selector: var match, parent = element.parentNode,temp = !parent // element     ,            div   if (temp)(parent = tempParent).appendChild(element) // parent     ,   selector     ,   element       ,     -1,   ~-1  0,            match = ~zepto.qsa(parent, selector).indexOf(element) //         temp && tempParent.removeChild(element) return match } //       function type(obj) { //obj null  undefined ,    'null' 'undefined' return obj == null ? String(obj) : class2type[toString.call(obj)] || "object" } function isFunction(value) { return type(value) == "function" } function isWindow(obj) { return obj != null && obj == obj.window } function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } function isObject(obj) { return type(obj) == "object" } //             new Object     true,new Object       false //   http://snandy.iteye.com/blog/663245 function isPlainObject(obj) { return isObject(obj) && !isWindow(obj) && obj.__proto__ == Object.prototype } function isArray(value) { return value instanceof Array } //   ,  nodeList,           ,                length  ,      true function likeArray(obj) { return typeof obj.length == 'number' } //         null undefined,  0==null,'' == null false function compact(array) { return filter.call(array, function(item) { return item != null }) } //            function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } //             camelize = function(str) { return str.replace(/-+(.)?/g, function(match, chr) { return chr ? chr.toUpperCase() : '' }) } //        -     ,         ,  border-width function dasherize(str) { return str.replace(/::/g, '/') // ::   / .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') //          _,    ,  AAAbb,  AA_Abb .replace(/([a-z\d])([A-Z])/g, '$1_$2') //          _,       ,  bbbAaa,  bbb_Aaa .replace(/_/g, '-') // _   - .toLowerCase() //     } //    ,                       ,              uniq = function(array) { return filter.call(array, function(item, idx) { return array.indexOf(item) == idx }) } //           function classRE(name) { //classCache,     return name in classCache ? classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) } //           'px'  ,  cssNumber         function maybeAddPx(name, value) { return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value } //       display   function defaultDisplay(nodeName) { var element, display if (!elementDisplay[nodeName]) { //       element = document.createElement(nodeName) document.body.appendChild(element) display = getComputedStyle(element, '').getPropertyValue("display") element.parentNode.removeChild(element) display == "none" && (display = "block") // display  none ,     block,         elementDisplay[nodeName] = display //       display   } return elementDisplay[nodeName] } //          (       ),Firefox   children,        childNodes function children(element) { return 'children' in element ? slice.call(element.children) : $.map(element.childNodes, function(node) { if (node.nodeType == 1) return node }) } // `$.zepto.fragment` takes a html string and an optional tag name // to generate DOM nodes nodes from the given html string. // The generated DOM nodes are returned as an array. // This function can be overriden in plugins for example to make // it compatible with browsers that don't support the DOM fully. zepto.fragment = function(html, name, properties) { //   <div class="test"/>   <div class="test"></div>,        if (html.replace) html = html.replace(tagExpanderRE, "<$1></$2>") // name     if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 //       ,    tr,tbody,thead,tfoot,td,th,       div if (!(name in containers)) name = '*' var nodes, dom, container = containers[name] //     container.innerHTML = '' + html // html         //       ,           DOM    dom = $.each(slice.call(container.childNodes), function() { container.removeChild(this) //     }) //  properties   ,                      if (isPlainObject(properties)) { nodes = $(dom) // dom  zepto  ,        zepto     //    ,     $.each(properties, function(key, value) { //      'val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset',   zepto        if (methodAttributes.indexOf(key) > -1) nodes[key](value) else nodes.attr(key, value) }) } //         DOM      ,  '<li></li><li></li><li></li>'  [li,li,li] return dom } // `$.zepto.Z` swaps out the prototype of the given `dom` array // of nodes with `$.fn` and thus supplying all the Zepto functions // to the array. Note that `__proto__` is not supported on Internet // Explorer. This method can be overriden in plugins. zepto.Z = function(dom, selector) { dom = dom || [] dom.__proto__ = $.fn //   dom  __proto__    $.fn     $.fn         dom.selector = selector || '' return dom } // `$.zepto.isZ` should return `true` if the given object is a Zepto // collection. This method can be overriden in plugins. //          Zepto  zepto.isZ = function(object) { return object instanceof zepto.Z } // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and // takes a CSS selector and an optional context (and handles various // special cases). // This method can be overriden in plugins. zepto.init = function(selector, context) { // If nothing given, return an empty Zepto collection if (!selector) return zepto.Z() //    ,      //  selector    ,  DOM ready       else if (isFunction(selector)) return $(document).ready(selector) //  selector   zepto.Z  ,         else if (zepto.isZ(selector)) return selector else { var dom //  selector     ,      null,undefined   if (isArray(selector)) dom = compact(selector) //  selector    ,  DOM   typeof   object,               else if (isObject(selector)) //        , {},   selector  copy      ,         //       DOM,         dom = [isPlainObject(selector) ? $.extend({}, selector) : selector], selector = null //  selector   HTML    ,      DOM   else if (fragmentRE.test(selector)) dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null //       context,        selector,   selector    CSS    else if (context !== undefined) return $(context).find(selector) //         ,  document   selector,   selector    CSS    else dom = zepto.qsa(document, selector) //          zepto   return zepto.Z(dom, selector) } } // `$` will be the base `Zepto` object. When calling this // function just call `$.zepto.init, which makes the implementation // details of selecting nodes and creating Zepto collections // patchable in plugins. $ = function(selector, context) { return zepto.init(selector, context) } //  ,deep         function extend(target, source, deep) { for (key in source) //       if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { //            target    key     if (isPlainObject(source[key]) && !isPlainObject(target[key])) target[key] = {} //            target    key     if (isArray(source[key]) && !isArray(target[key])) target[key] = [] extend(target[key], source[key], deep) } else if (source[key] !== undefined) target[key] = source[key] } // Copy all but undefined properties from one or more // objects to the `target` object. $.extend = function(target) { var deep, args = slice.call(arguments, 1) if (typeof target == 'boolean') { //       boolean     ,         deep = target target = args.shift() //target       } //       ,     target  args.forEach(function(arg) { extend(target, arg, deep) }) return target } // `$.zepto.qsa` is Zepto's CSS selector implementation which // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. // This method can be overriden in plugins. zepto.qsa = function(element, selector) { var found // element document, selector ID     return (isDocument(element) && idSelectorRE.test(selector)) ? //    document.getElementById,RegExp.$1 ID  ,         [] ((found = element.getElementById(RegExp.$1)) ? [found] : []) : // element        document ,  [] (element.nodeType !== 1 && element.nodeType !== 9) ? [] : //                 slice.call( //  selector    ,    getElementsByClassName classSelectorRE.test(selector) ? element.getElementsByClassName(RegExp.$1) : //  selector    ,    getElementsByTagName tagSelectorRE.test(selector) ? element.getElementsByTagName(selector) : //    querySelectorAll element.querySelectorAll(selector)) } //         function filtered(nodes, selector) { return selector === undefined ? $(nodes) : $(nodes).filter(selector) } //  parent    node $.contains = function(parent, node) { return parent !== node && parent.contains(node) } //                 ,  arg          //                   function funcArg(context, arg, idx, payload) { return isFunction(arg) ? arg.call(context, idx, payload) : arg } function setAttribute(node, name, value) { //       null undefined,         ,    name   value value == null ? node.removeAttribute(name) : node.setAttribute(name, value) } // access className property while respecting SVGAnimatedString function className(node, value) { var klass = node.className, svg = klass && klass.baseVal !== undefined if (value === undefined) return svg ? klass.baseVal : klass svg ? (klass.baseVal = value) : (node.className = value) } // "true" => true // "false" => false // "null" => null // "42" => 42 // "42.5" => 42.5 // JSON => parse if valid // String => self function deserializeValue(value) { var num try { return value ? value == "true" || (value == "false" ? false : value == "null" ? null : !isNaN(num = Number(value)) ? num : /^[\[\{]/.test(value) ? $.parseJSON(value) : value) : value } catch (e) { return value } } $.type = type $.isFunction = isFunction $.isWindow = isWindow $.isArray = isArray $.isPlainObject = isPlainObject //    $.isEmptyObject = function(obj) { var name for (name in obj) return false return true } //              $.inArray = function(elem, array, i) { return emptyArray.indexOf.call(array, elem, i) } //             $.camelCase = camelize //         $.trim = function(str) { return str.trim() } // plugin compatibility $.uuid = 0 $.support = {} $.expr = {} //  elements,       callback     ,           null undefined    //          for in,                ,    toString,valueOf $.map = function(elements, callback) { var value, values = [], i, key //             nodeList if (likeArray(elements)) for (i = 0; i < elements.length; i++) { value = callback(elements[i], i) if (value != null) values.push(value) } else //      for (key in elements) { value = callback(elements[key], key) if (value != null) values.push(value) } return flatten(values) } //    ,       callback    ,                ,                 false, //     ,   elements $.each = function(elements, callback) { var i, key if (likeArray(elements)) { for (i = 0; i < elements.length; i++) if (callback.call(elements[i], i, elements[i]) === false) return elements } else { for (key in elements) if (callback.call(elements[key], key, elements[key]) === false) return elements } return elements } //   $.grep = function(elements, callback) { return filter.call(elements, callback) } if (window.JSON) $.parseJSON = JSON.parse // Populate the class2type map //  class2type   $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type["[object " + name + "]"] = name.toLowerCase() }) //  DOM      // Define methods that will be available on all // Zepto collections $.fn = { // Because a collection acts like an array // copy over these useful array functions. forEach: emptyArray.forEach, reduce: emptyArray.reduce, push: emptyArray.push, sort: emptyArray.sort, indexOf: emptyArray.indexOf, concat: emptyArray.concat, // `map` and `slice` in the jQuery API work differently // from their array counterparts map: function(fn) { return $($.map(this, function(el, i) { return fn.call(el, i, el) })) }, slice: function() { return $(slice.apply(this, arguments)) }, //DOM Ready ready: function(callback) { if (readyRE.test(document.readyState)) callback($) else document.addEventListener('DOMContentLoaded', function() { callback($) }, false) return this }, //            ,  idx  0, idx  idx+length,length       get: function(idx) { return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] }, //         toArray: function() { return this.get() }, //       size: function() { return this.length }, //    dom    remove: function() { return this.each(function() { if (this.parentNode != null) this.parentNode.removeChild(this) }) }, //    ,          callback     ,     false  ,     callback      false //          each: function(callback) { emptyArray.every.call(this, function(el, idx) { return callback.call(el, idx, el) !== false }) return this }, //    ,       true    filter: function(selector) { //this.not(selector)         ,      (    this.not          ),        if (isFunction(selector)) return this.not(this.not(selector)) //filter       true    return $(filter.call(this, function(element) { return zepto.matches(element, selector) // element selector  ,    })) }, //  selector               add: function(selector, context) { return $(uniq(this.concat($(selector, context)))) //      }, //       1      selector   is: function(selector) { return this.length > 0 && zepto.matches(this[0], selector) }, //            ,     :css   ,function, dom ,nodeList not: function(selector) { var nodes = [] // selector    ,safari  typeof odeList  function,            selector.call !== undefined if (isFunction(selector) && selector.call !== undefined) { this.each(function(idx) { //        selector.call(this,idx)     false      if (!selector.call(this, idx)) nodes.push(this) }) } else { // selector       ,       ,           selector    var excludes = typeof selector == 'string' ? this.filter(selector) : // selector nodeList   slice.call(selector),     isFunction(selector.item)     selector       // selector css   ,  $(selector) (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) this.forEach(function(el) { //     excludes      ,        if (excludes.indexOf(el) < 0) nodes.push(el) }) } return $(nodes) //            ,      zepto  ,        ,     }, /*   node string    ,          selector    isObject(selector)        node,  typeof node == 'object'     node ,              node         string ,         selector,     0,  false,filter           ,        */ has: function(selector) { return this.filter(function() { return isObject(selector) ? $.contains(this, selector) : $(this).find(selector).size() }) }, /*             , idx -1 ,        */ eq: function(idx) { return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1) }, /*            */ first: function() { var el = this[0] //           //                 zepto         ,    zepto   //el && !isObject(el)         el        ,    el   ,  isObject(el)     true return el && !isObject(el) ? el : $(el) }, /*             */ last: function() { var el = this[this.length - 1] //            //  el node, isObject(el)  true,    zepto   return el && !isObject(el) ? el : $(el) }, /*         selector,selector     ,   ,     */ find: function(selector) { var result, $this = this //  selector node  zepto    if (typeof selector == 'object') //  selector,            selector result = $(selector).filter(function() { var node = this //  $.contains(parent, node)  true, emptyArray.some    true,   filter         return emptyArray.some.call($this, function(parent) { return $.contains(parent, node) }) }) //  selector css    //         1 ,  zepto.qsa,     zepto   else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) //      1,   map   else result = this.map(function() { return zepto.qsa(this, selector) }) return result }, //                      closest: function(selector, context) { var node = this[0], collection = false if (typeof selector == 'object') collection = $(selector) // selector node  zepto   ,  node  collection       node.parentNode     // selector        ,  node selector   ,    node.parentNode     while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) // node   context,document   , node.parentNode node = node !== context && !isDocument(node) && node.parentNode return $(node) }, //          parents: function(selector) { var ancestors = [], nodes = this //    nodes      ,   while nodes       //          ,       ,             //       ,         ,          ,nodes.length  0  while (nodes.length > 0) //nodes               nodes = $.map(nodes, function(node) { //  nodes,           //ancestors.indexOf(node) < 0      if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { ancestors.push(node) //            ,      return node } }) //               ,                       return filtered(ancestors, selector) }, //         parent: function(selector) { return filtered(uniq(this.pluck('parentNode')), selector) }, children: function(selector) { return filtered(this.map(function() { return children(this) }), selector) }, contents: function() { return this.map(function() { return slice.call(this.childNodes) }) }, siblings: function(selector) { return filtered(this.map(function(i, el) { //                 ,      return filter.call(children(el.parentNode), function(child) { return child !== el }) }), selector) }, empty: function() { return this.each(function() { this.innerHTML = '' }) }, //                 pluck: function(property) { return $.map(this, function(el) { return el[property] }) }, show: function() { return this.each(function() { //       display="none"    this.style.display == "none" && (this.style.display = null) //          display   none ,    display     if (getComputedStyle(this, '').getPropertyValue("display") == "none") this.style.display = defaultDisplay(this.nodeName) //defaultDisplay       display    }) }, replaceWith: function(newContent) { //                  ,           return this.before(newContent).remove() }, wrap: function(structure) { var func = isFunction(structure) if (this[0] && !func) //  structure    ,     DOM var dom = $(structure).get(0), //  structure               wrap       ,   clone dom clone = dom.parentNode || this.length > 1 return this.each(function(index) { $(this).wrapAll( func ? structure.call(this, index) : clone ? dom.cloneNode(true) : dom) }) }, wrapAll: function(structure) { if (this[0]) { //                  ,   structure     $(this[0]).before(structure = $(structure)) var children // drill down to the inmost element // structure             while ((children = structure.children()).length) structure = children.first() //               ,  wrapAll    $(structure).append(this) } return this }, //                wrapInner: function(structure) { var func = isFunction(structure) return this.each(function(index) { //           ,   structure      ,       ,    structure append     var self = $(this), contents = self.contents(), dom = func ? structure.call(this, index) : structure contents.length ? contents.wrapAll(dom) : self.append(dom) }) }, unwrap: function() { //          this.parent().each(function() { $(this).replaceWith($(this).children()) }) return this }, //clone node clone: function() { return this.map(function() { return this.cloneNode(true) }) }, //     hide: function() { return this.css("display", "none") }, toggle: function(setting) { return this.each(function() { var el = $(this); /*   setting             ,    ,     true ,    ,false ,                  ,     ,    ,   toogle   ,     display    none              toogle  ,        ,                  。    true,   show  ,false    hide   */ (setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() }) }, prev: function(selector) { return $(this.pluck('previousElementSibling')).filter(selector || '*') }, next: function(selector) { return $(this.pluck('nextElementSibling')).filter(selector || '*') }, //     ,         HTML,     ,            HTML,        0,   null html: function(html) { return html === undefined ? //  html    ,           html (this.length > 0 ? this[0].innerHTML : null) : //      ,       html this.each(function(idx) { //     innerHTMl var originHtml = this.innerHTML //    html            , //     ,           ,     ,            innerHTML     $(this).empty().append(funcArg(this, html, idx, originHtml)) }) }, text: function(text) { //     text  ,      ,      0 ,       textContent,    null, //    text  ,            textContent text return text === undefined ? (this.length > 0 ? this[0].textContent : null) : this.each(function() { this.textContent = text }) }, attr: function(name, value) { var result //   name      ,             return (typeof name == 'string' && value === undefined) ? //               node  ,  undefined (this.length == 0 || this[0].nodeType !== 1 ? undefined : //     input value (name == 'value' && this[0].nodeName == 'INPUT') ? this.val() : //       node    ,       ie9,10  getAttribute   ,      null //  div.aa = 10, div.getAttribute('aa')    null,   div.aa  div['aa']     (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result) : this.each(function(idx) { if (this.nodeType !== 1) return //  name     , {'id':'test','value':11},         if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) //  name            , funcArg   value    function             //  funcArg      undefined  null,            else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) }) }, removeAttr: function(name) { return this.each(function() { this.nodeType === 1 && setAttribute(this, name)//setAttribute       null ,     name   }) }, //           name                ,   setAttribute    prop: function(name, value) { //    value ,   ,  value         ,value                 return (value === undefined) ? (this[0] && this[0][name]) : this.each(function(idx) { this[name] = funcArg(this, value, idx, this[name]) }) }, data: function(name, value) { //    attr             ,  attr   , value     ,        ,     ,         var data = this.attr('data-' + dasherize(name), value) return data !== null ? deserializeValue(data) : undefined }, val: function(value) { return (value === undefined) ? //      select,           option      (this[0] && (this[0].multiple ? $(this[0]).find('option').filter(function(o) { return this.selected }).pluck('value') : this[0].value)) : this.each(function(idx) { this.value = funcArg(this, value, idx, this.value) }) }, offset: function(coordinates) { if (coordinates) return this.each(function(index) { var $this = $(this), //coordinates {}     ,           coords coords = funcArg(this, coordinates, index, $this.offset()), //    offset parentOffset = $this.offsetParent().offset(), //         ,       props = { top: coords.top - parentOffset.top, left: coords.left - parentOffset.left } //     position static ,  top,left     if ($this.css('position') == 'static') props['position'] = 'relative' $this.css(props) }) //       offset,  offsetTop,offsetLeft,offsetWidth,offsetHeight if (this.length == 0) return null var obj = this[0].getBoundingClientRect() //window.pageYOffset    Math.max(document.documentElement.scrollTop||document.body.scrollTop) return { left: obj.left + window.pageXOffset, top: obj.top + window.pageYOffset, width: Math.round(obj.width), height: Math.round(obj.height) } }, css: function(property, value) { //        if (arguments.length < 2 && typeof property == 'string') return this[0] && (this[0].style[camelize(property)] || getComputedStyle(this[0], '').getPropertyValue(property)) //     var css = '' if (type(property) == 'string') { if (!value && value !== 0) // value          false    (null,undefined),  property   this.each(function() { //style.removeProperty      CSS   (IE   DOM style  ) this.style.removeProperty(dasherize(property)) }) else css = dasherize(property) + ":" + maybeAddPx(property, value) } else { // property     for (key in property) if (!property[key] && property[key] !== 0) // property[key]          false   ,  key   this.each(function() { this.style.removeProperty(dasherize(key)) }) else css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' } //   return this.each(function() { this.style.cssText += ';' + css }) }, index: function(element) { //   $(element)[0]         node,  this    node    //    element ,                  //this.parent().children().indexOf(this[0])     ,       parent().children().indexOf(this)   return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) }, hasClass: function(name) { return emptyArray.some.call(this, function(el) { //     this classRE(name)      return this.test(className(el)) }, classRE(name)) }, addClass: function(name) { return this.each(function(idx) { classList = [] var cls = className(this), newName = funcArg(this, name, idx, cls) //          ,      newName.split(/\s+/g).forEach(function(klass) { if (!$(this).hasClass(klass)) classList.push(klass) }, this) classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) }) }, removeClass: function(name) { return this.each(function(idx) { if (name === undefined) return className(this, '') classList = className(this) funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass) { classList = classList.replace(classRE(klass), " ") }) className(this, classList.trim()) }) }, toggleClass: function(name, when) { return this.each(function(idx) { var $this = $(this), names = funcArg(this, name, idx, className(this)) names.split(/\s+/g).forEach(function(klass) { (when === undefined ? !$this.hasClass(klass) : when) ? $this.addClass(klass) : $this.removeClass(klass) }) }) }, scrollTop: function() { if (!this.length) return return ('scrollTop' in this[0]) ? this[0].scrollTop : this[0].scrollY }, position: function() { if (!this.length) return var elem = this[0], // Get *real* offsetParent offsetParent = this.offsetParent(), // Get correct offsets offset = this.offset(), parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() // Subtract element margins // note: when an element has margin: auto the offsetLeft and marginLeft // are the same in Safari causing offset.left to incorrectly be 0 offset.top -= parseFloat($(elem).css('margin-top')) || 0 offset.left -= parseFloat($(elem).css('margin-left')) || 0 // Add offsetParent borders parentOffset.top += parseFloat($(offsetParent[0]).css('border-top-width')) || 0 parentOffset.left += parseFloat($(offsetParent[0]).css('border-left-width')) || 0 // Subtract the two offsets return { top: offset.top - parentOffset.top, left: offset.left - parentOffset.left } }, offsetParent: function() { return this.map(function() { var parent = this.offsetParent || document.body while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") parent = parent.offsetParent return parent }) } } // for now $.fn.detach = $.fn.remove // Generate the `width` and `height` functions ; ['width', 'height'].forEach(function(dimension) { $.fn[dimension] = function(value) { var offset, el = this[0], // width,hegiht  Width,Height,   window  document width height Dimension = dimension.replace(/./, function(m) { return m[0].toUpperCase() }) //       ,  window width height innerWidth,innerHeight if (value === undefined) return isWindow(el) ? el['inner' + Dimension] : //  document width height , offsetWidth,offsetHeight isDocument(el) ? el.documentElement['offset' + Dimension] : (offset = this.offset()) && offset[dimension] else return this.each(function(idx) { el = $(this) el.css(dimension, funcArg(this, value, idx, el[dimension]())) }) } }) function traverseNode(node, fun) { fun(node) for (var key in node.childNodes) traverseNode(node.childNodes[key], fun) } // Generate the `after`, `prepend`, `before`, `append`, // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. adjacencyOperators.forEach(function(operator, operatorIndex) { var inside = operatorIndex % 2 //=> prepend, append $.fn[operator] = function() { // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings var argType, nodes = $.map(arguments, function(arg) { argType = type(arg) return argType == "object" || argType == "array" || arg == null ? arg : zepto.fragment(arg) }), parent, copyByClone = this.length > 1 //          ,   clone       if (nodes.length < 1) return this return this.each(function(_, target) { parent = inside ? target : target.parentNode //    target after,prepend,append    before  ,insertBefore       null   appendChild   target = operatorIndex == 0 ? target.nextSibling : operatorIndex == 1 ? target.firstChild : operatorIndex == 2 ? target : null nodes.forEach(function(node) { if (copyByClone) node = node.cloneNode(true) else if (!parent) return $(node).remove() //     ,         SCRIPT,          window      traverseNode(parent.insertBefore(node, target), function(el) { if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && (!el.type || el.type === 'text/javascript') && !el.src) window['eval'].call(window, el.innerHTML) }) }) }) } // after => insertAfter // prepend => prependTo // before => insertBefore // append => appendTo $.fn[inside ? operator + 'To' : 'insert' + (operatorIndex ? 'Before' : 'After')] = function(html) { $(html)[operator](this) return this } }) zepto.Z.prototype = $.fn // Export internal API functions in the `$.zepto` namespace zepto.uniq = uniq zepto.deserializeValue = deserializeValue $.zepto = zepto return $ })(); window.Zepto = Zepto; '$' in window || (window.$ = Zepto); ;(function($) { function detect(ua) { var os = this.os = {}, browser = this.browser = {}, webkit = ua.match(/WebKit\/([\d.]+)/), android = ua.match(/(Android)\s+([\d.]+)/), ipad = ua.match(/(iPad).*OS\s([\d_]+)/), iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/), webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/), touchpad = webos && ua.match(/TouchPad/), kindle = ua.match(/Kindle\/([\d.]+)/), silk = ua.match(/Silk\/([\d._]+)/), blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/), bb10 = ua.match(/(BB10).*Version\/([\d.]+)/), rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/), playbook = ua.match(/PlayBook/), chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/), firefox = ua.match(/Firefox\/([\d.]+)/) // Todo: clean this up with a better OS/browser seperation: // - discern (more) between multiple browsers on android // - decide if kindle fire in silk mode is android or not // - Firefox on Android doesn't specify the Android version // - possibly devide in os, device and browser hashes if (browser.webkit = !! webkit) browser.version = webkit[1] if (android) os.android = true, os.version = android[2] if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.') if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.') if (webos) os.webos = true, os.version = webos[2] if (touchpad) os.touchpad = true if (blackberry) os.blackberry = true, os.version = blackberry[2] if (bb10) os.bb10 = true, os.version = bb10[2] if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2] if (playbook) browser.playbook = true if (kindle) os.kindle = true, os.version = kindle[1] if (silk) browser.silk = true, browser.version = silk[1] if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true if (chrome) browser.chrome = true, browser.version = chrome[1] if (firefox) browser.firefox = true, browser.version = firefox[1] os.tablet = !! (ipad || playbook || (android && !ua.match(/Mobile/)) || (firefox && ua.match(/Tablet/))) os.phone = !! (!os.tablet && (android || iphone || webos || blackberry || bb10 || (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || (firefox && ua.match(/Mobile/)))) } detect.call($, navigator.userAgent) // make available to unit tests $.__detect = detect })(Zepto) /*        */ ; (function($) { var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents = {}, hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' // element      ,    ,         function zid(element) { return element._zid || (element._zid = _zid++) } //                       function findHandlers(element, event, fn, selector) { event = parse(event) if (event.ns) var matcher = matcherFor(event.ns) return (handlers[zid(element)] || []).filter(function(handler) { return handler && (!event.e || handler.e == event.e) //           && (!event.ns || matcher.test(handler.ns)) //             //            zid(handler.fn)      handler.fn    ,    ,       , //    fn handler.fn         ,  fn           , //                           && (!fn || zid(handler.fn) === zid(fn)) && (!selector || handler.sel == selector) }) } //      ,                     function parse(event) { var parts = ('' + event).split('.') return { e: parts[0], ns: parts.slice(1).sort().join(' ') } } //          function matcherFor(ns) { return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') } //  events function eachEvent(events, fn, iterator) { if ($.type(events) != "string") $.each(events, iterator) else events.split(/\s/).forEach(function(type) { iterator(type, fn) }) } //   focus blur                  function eventCapture(handler, captureSetting) { return handler.del && (handler.e == 'focus' || handler.e == 'blur') || !! captureSetting } //     mouseenter mouseleave    function realEvent(type) { return hover[type] || type } //         ,           , ['click','mouseover','mouseout'],    'click mouseover mouseout' function add(element, events, fn, selector, getDelegate, capture) { var id = zid(element), set = (handlers[id] || (handlers[id] = [])) //                 eachEvent(events, fn, function(event, fn) { var handler = parse(event) //  fn,      mouseenter, mouseleave , fn      handler.fn = fn handler.sel = selector //    mouseenter, mouseleave if (handler.e in hover) fn = function(e) { /* relatedTarget       ,   mouseover mouseout       mouseover              ,mouseout                related   ,      mouseover  mouseout,mouseover !$.contains(this, related)              related !== this           ,                     ,                                related   this , !$.contains(this, related)    ,                */ var related = e.relatedTarget if (!related || (related !== this && !$.contains(this, related))) return handler.fn.apply(this, arguments) } //     handler.del = getDelegate && getDelegate(fn, event) var callback = handler.del || fn handler.proxy = function(e) { var result = callback.apply(element, [e].concat(e.data)) //         false ,          if (result === false) e.preventDefault(), e.stopPropagation() return result } //                handler.i = set.length //          set.push(handler) element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }) } //                    ,                ,              , add function remove(element, events, fn, selector, capture) { var id = zid(element) eachEvent(events || '', fn, function(event, fn) { findHandlers(element, event, fn, selector).forEach(function(handler) { delete handlers[id][handler.i] element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }) }) } $.event = { add: add, remove: remove } //     $.proxy = function(fn, context) { if ($.isFunction(fn)) { //  fn   ,           context       fn var proxyFn = function() { return fn.apply(context, arguments) } //  fn    proxyFn._zid = zid(fn) return proxyFn } else if (typeof context == 'string') { return $.proxy(fn[context], fn) } else { throw new TypeError("expected function") } } $.fn.bind = function(event, callback) { return this.each(function() { add(this, event, callback) }) } $.fn.unbind = function(event, callback) { return this.each(function() { remove(this, event, callback) }) } //            $.fn.one = function(event, callback) { return this.each(function(i, element) { //    ,             。           add(this, event, callback, null, function(fn, type) { return function() { var result = fn.apply(element, arguments) //          remove(element, type, fn) //        return result } }) }) } var returnTrue = function() { return true }, returnFalse = function() { return false }, ignoreProperties = /^([A-Z]|layer[XY]$)/, eventMethods = { preventDefault: 'isDefaultPrevented', //     preventDefault   //                    .                  ,                                   . stopImmediatePropagation: 'isImmediatePropagationStopped', //     stopImmediatePropagation  , stopPropagation: 'isPropagationStopped' //     stopPropagation   } //       function createProxy(event) { var key, proxy = { originalEvent: event } //    event for (key in event) if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] //  event   proxy // preventDefault,stopImmediatePropagatio,stopPropagation     proxy  $.each(eventMethods, function(name, predicate) { proxy[name] = function() { this[predicate] = returnTrue return event[name].apply(event, arguments) } proxy[predicate] = returnFalse }) return proxy } // emulates the 'defaultPrevented' property for browsers that have none //event.defaultPrevented       ,                ,         event.preventDefault()  . function fix(event) { if (!('defaultPrevented' in event)) { event.defaultPrevented = false //   false var prevent = event.preventDefault //     preventDefault event.preventDefault = function() { //  preventDefault this.defaultPrevented = true prevent.call(this) } } } //     $.fn.delegate = function(selector, event, callback) { return this.each(function(i, element) { add(element, event, callback, selector, function(fn) { return function(e) { //       element    ,  selector     var evt, match = $(e.target).closest(selector, element).get(0) if (match) { //evt      preventDefault,stopImmediatePropagatio,stopPropagation  ,currentTarge,liveFiredn     ,   e      evt = $.extend(createProxy(e), { currentTarget: match, liveFired: element }) return fn.apply(match, [evt].concat([].slice.call(arguments, 1))) } } }) }) } //       $.fn.undelegate = function(selector, event, callback) { return this.each(function() { remove(this, event, callback, selector) }) } $.fn.live = function(event, callback) { $(document.body).delegate(this.selector, event, callback) return this } $.fn.die = function(event, callback) { $(document.body).undelegate(this.selector, event, callback) return this } //on  live        ,      on      $.fn.on = function(event, selector, callback) { return !selector || $.isFunction(selector) ? this.bind(event, selector || callback) : this.delegate(selector, event, callback) } $.fn.off = function(event, selector, callback) { return !selector || $.isFunction(selector) ? this.unbind(event, selector || callback) : this.undelegate(selector, event, callback) } //       $.fn.trigger = function(event, data) { if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event) fix(event) event.data = data return this.each(function() { // items in the collection might not be DOM elements // (todo: possibly support events on plain old objects) if ('dispatchEvent' in this) this.dispatchEvent(event) }) } // triggers event handlers on current element just as if an event occurred, // doesn't trigger an actual event, doesn't bubble //               ,      $.fn.triggerHandler = function(event, data) { var e, result this.each(function(i, element) { e = createProxy(typeof event == 'string' ? $.Event(event) : event) e.data = data e.target = element //                    ,     ,     stopImmediatePropagation, //  e.isImmediatePropagationStopped()    true,       false //  each          false ,     ,                  $.each(findHandlers(element, event.type || event), function(i, handler) { result = handler.proxy(e) if (e.isImmediatePropagationStopped()) return false }) }) return result } // shortcut methods for `.bind(event, fn)` for each event type ; ('focusin focusout load resize scroll unload click dblclick ' + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave ' + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { $.fn[event] = function(callback) { return callback ? //   callback  ,        this.bind(event, callback) : //    callback  ,        this.trigger(event) } }) ; ['focus', 'blur'].forEach(function(name) { $.fn[name] = function(callback) { if (callback) this.bind(name, callback) else this.each(function() { try { this[name]() } catch (e) {} }) return this } }) //        event   $.Event = function(type, props) { // type      if (typeof type != 'string') props = type, type = props.type //    event  ,   click,mouseover,mouseout ,    MouseEvent,bubbles      var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true //  bubbles   true false,  props            event    if (props) for (var name in props)(name == 'bubbles') ? (bubbles = !! props[name]) : (event[name] = props[name]) //   event  ,type     , click,bubbles     ,            preventDefault          event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null) //  isDefaultPrevented  ,event.defaultPrevented       ,                ,         event.preventDefault()  . event.isDefaultPrevented = function() { return this.defaultPrevented } return event } })(Zepto) /** Ajax     **/ ; (function($) { var jsonpID = 0, document = window.document, key, name, rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, scriptTypeRE = /^(?:text|application)\/javascript/i, xmlTypeRE = /^(?:text|application)\/xml/i, jsonType = 'application/json', htmlType = 'text/html', blankRE = /^\s*$/ // trigger a custom event and return false if it was cancelled function triggerAndReturn(context, eventName, data) { var event = $.Event(eventName) $(context).trigger(event, data) return !event.defaultPrevented } // trigger an Ajax "global" event //   ajax      function triggerGlobal(settings, context, eventName, data) { if (settings.global) return triggerAndReturn(context || document, eventName, data) } // Number of active Ajax requests $.active = 0 //settings.global true         ajax   //     $.active++ === 0   ,       ,    $.active  0 $.active++ === 0    function ajaxStart(settings) { if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') } //      !(--$.active)        ,--$.active 0,   $.active   1,        ,      function ajaxStop(settings) { if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') } // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable //    ajaxBeforeSend  ,    false,        function ajaxBeforeSend(xhr, settings) { var context = settings.context if (settings.beforeSend.call(context, xhr, settings) === false || triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) return false triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) } function ajaxSuccess(data, xhr, settings) { var context = settings.context, status = 'success' settings.success.call(context, data, status, xhr) triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) ajaxComplete(status, xhr, settings) } // type: "timeout", "error", "abort", "parsererror" function ajaxError(error, type, xhr, settings) { var context = settings.context settings.error.call(context, xhr, type, error) triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error]) ajaxComplete(type, xhr, settings) } // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" function ajaxComplete(status, xhr, settings) { var context = settings.context settings.complete.call(context, xhr, status) triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) ajaxStop(settings) } // Empty function, used as default callback function empty() {} //   http://zh.wikipedia.org/zh-cn/JSONP $.ajaxJSONP = function(options) { if (!('type' in options)) return $.ajax(options) var callbackName = 'jsonp' + (++jsonpID), //        script = document.createElement('script'), //js       cleanup = function() { clearTimeout(abortTimeout) //     timeout     $(script).remove() //     script  ,      JS         delete window[callbackName] //           }, //     abort = function(type) { cleanup() // In case of manual abort or timeout, keep an empty function as callback // so that the SCRIPT tag that eventually loads won't result in an error. //                          JS   ,    script     src   ,        ,       if (!type || type == 'timeout') window[callbackName] = empty ajaxError(null, type || 'abort', xhr, options) }, xhr = { abort: abort }, abortTimeout if (ajaxBeforeSend(xhr, options) === false) { abort('abort') return false } //           window[callbackName] = function(data) { cleanup() ajaxSuccess(data, xhr, options) } script.onerror = function() { abort('error') } //             ,   script,       script.src = options.url.replace(/=\?/, '=' + callbackName) $('head').append(script) //          if (options.timeout > 0) abortTimeout = setTimeout(function() { abort('timeout') }, options.timeout) return xhr } //ajax     $.ajaxSettings = { // Default type of request type: 'GET', // Callback that is executed before request beforeSend: empty, // Callback that is executed if the request succeeds success: empty, // Callback that is executed the the server drops error error: empty, // Callback that is executed on request complete (both: error and success) complete: empty, // The context for the callbacks context: null, // Whether to trigger "global" Ajax events global: true, // Transport xhr: function() { return new window.XMLHttpRequest() }, // MIME types mapping accepts: { script: 'text/javascript, application/javascript', json: jsonType, xml: 'application/xml, text/xml', html: htmlType, text: 'text/plain' }, // Whether the request is to another domain crossDomain: false, // Default timeout timeout: 0, // Whether data should be serialized to string processData: true, // Whether the browser should be allowed to cache GET responses cache: true }; //  MIME         ,  ajax    dataType ,            // html,json,scirpt,xml,text function mimeToDataType(mime) { if (mime) mime = mime.split(';', 2)[0] return mime && (mime == htmlType ? 'html' : mime == jsonType ? 'json' : scriptTypeRE.test(mime) ? 'script' : xmlTypeRE.test(mime) && 'xml') || 'text' } //         URL   function appendQuery(url, query) { //     replace,        &  &&,&?,? ?& ??   ?,           return (url + '&' + query).replace(/[&?]{1,2}/, '?') } // serialize payload and append it to the URL for GET requests //             ,   GET  ,                   function serializeData(options) { //options.processData     Get  ,      options.data      ,   options.data      if (options.processData && options.data && $.type(options.data) != "string") //options.traditional     $.param      options.data = $.param(options.data, options.traditional) if (options.data && (!options.type || options.type.toUpperCase() == 'GET')) //   GET  ,                  options.url = appendQuery(options.url, options.data) } $.ajax = function(options) { //         $.ajaxSettings   $.extend      ,      $.ajaxSettings     //              var settings = $.extend({}, options || {}) //       $.ajaxSettings        ,   $.ajaxSettings[key]      for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] //    ajaxStart ajaxStart(settings) //                host           if (!settings.crossDomain) settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && RegExp.$2 != window.location.host //          ,         if (!settings.url) settings.url = window.location.toString(); // data     serializeData(settings); //        if (settings.cache === false) settings.url = appendQuery(settings.url, '_=' + Date.now()) //      jsonp,       =?   callback=?,        var dataType = settings.dataType, hasPlaceholder = /=\?/.test(settings.url) if (dataType == 'jsonp' || hasPlaceholder) { if (!hasPlaceholder) settings.url = appendQuery(settings.url, 'callback=?') return $.ajaxJSONP(settings) } var mime = settings.accepts[dataType], baseHeaders = {}, //             ,           protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, xhr = settings.xhr(), abortTimeout //       if (!settings.crossDomain) baseHeaders['X-Requested-With'] = 'XMLHttpRequest' if (mime) { baseHeaders['Accept'] = mime if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] xhr.overrideMimeType && xhr.overrideMimeType(mime) } //    GET  ,                  if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) baseHeaders['Content-Type'] = (settings.contentType || 'application/x-www-form-urlencoded') settings.headers = $.extend(baseHeaders, settings.headers || {}) xhr.onreadystatechange = function() { if (xhr.readyState == 4) { xhr.onreadystatechange = empty; clearTimeout(abortTimeout) var result, error = false //              //  >=200 && < 300      //   == 304         ,       //                   ,xhr.status == 0                   ,      localhost            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { //          dataType = dataType || mimeToDataType(xhr.getResponseHeader('content-type')) result = xhr.responseText try { // http://perfectionkills.com/global-eval-what-are-the-options/ if (dataType == 'script')(1, eval)(result) //          JS else if (dataType == 'xml') result = xhr.responseXML else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) } catch (e) { error = e } //      ,     parsererror   if (error) ajaxError(error, 'parsererror', xhr, settings) //    ajaxSuccess else ajaxSuccess(result, xhr, settings) } else { //      ,   xhr.status             ajaxError(null, xhr.status ? 'error' : 'abort', xhr, settings) } } } var async = 'async' in settings ? settings.async : true xhr.open(settings.type, settings.url, async) //        for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]) //  ajaxBeforeSend     false,        if (ajaxBeforeSend(xhr, settings) === false) { xhr.abort() return false } //    settings.timeout,         ,   timeout       if (settings.timeout > 0) abortTimeout = setTimeout(function() { xhr.onreadystatechange = empty xhr.abort() ajaxError(null, 'timeout', xhr, settings) }, settings.timeout) // avoid sending empty string (#319) xhr.send(settings.data ? settings.data : null) return xhr } // handle optional data/success arguments //      ajax          function parseArguments(url, data, success, dataType) { var hasData = !$.isFunction(data) //  data function,              return { url: url, data: hasData ? data : undefined, //  data  function   success: !hasData ? data : $.isFunction(success) ? success : undefined, dataType: hasData ? dataType || success : success } } //   get   $.get = function(url, data, success, dataType) { return $.ajax(parseArguments.apply(null, arguments)) } $.post = function(url, data, success, dataType) { var options = parseArguments.apply(null, arguments) options.type = 'POST' return $.ajax(options) } $.getJSON = function(url, data, success) { var options = parseArguments.apply(null, arguments) options.dataType = 'json' return $.ajax(options) } //   url   http://www.xxxx.com selector    ,        HTML       $.fn.load = function(url, data, success) { if (!this.length) return this //           var self = this, parts = url.split(/\s/), selector, options = parseArguments(url, data, success), callback = options.success if (parts.length > 1) options.url = parts[0], selector = parts[1] //                ,          HTML        options.success = function(response) { //selector                  ,            .test    self.html(selector ? $('<div>').html(response.replace(rscript, "")).find(selector) : response) //          callback && callback.apply(self, arguments) } $.ajax(options) return this } var escape = encodeURIComponent function serialize(params, obj, traditional, scope) { var type, array = $.isArray(obj) $.each(obj, function(key, value) { type = $.type(value) //scope    value  object  array    //traditional              , //               {a:[1,2,3]},           'a=1&a=2&a=3' //         a[]=1&a[]=2&a[]=3 if (scope) key = traditional ? scope : scope + '[' + (array ? '' : key) + ']' // handle data in serializeArray() format //       [{},{},{}]       ,               if (!scope && array) params.add(value.name, value.value) // recurse into nested objects // value                        ,      value else if (type == "array" || (!traditional && type == "object")) serialize(params, value, traditional, key) else params.add(key, value) }) } // obj           ,traditional            ,                 $.param = function(obj, traditional) { var params = [] //     add    params,    serialize          params.add = function(k, v) { this.push(escape(k) + '=' + escape(v)) } serialize(params, obj, traditional) return params.join('&').replace(/%20/g, '+') } })(Zepto) ; (function($) { //     ,      [{name:value},{name2:value2}]    $.fn.serializeArray = function() { var result = [], el //                            $(Array.prototype.slice.call(this.get(0).elements)).each(function() { el = $(this) var type = el.attr('type') //   type  ,  fieldset,submi,reset,button        radio checkbox if (this.nodeName.toLowerCase() != 'fieldset' && !this.disabled && type != 'submit' && type != 'reset' && type != 'button' && //       ,      radio   checkbox ,    true, //    radio  checkbox ,      this.checked, radio  checkbox    this.checked  true  //            radio checkbox  ((type != 'radio' && type != 'checkbox') || this.checked)) result.push({ name: el.attr('name'), value: el.val() }) }) return result } //       name1=value1&name2=value2    $.fn.serialize = function() { var result = [] this.serializeArray().forEach(function(elm) { result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) }) return result.join('&') } //     $.fn.submit = function(callback) { if (callback) this.bind('submit', callback) else if (this.length) { var event = $.Event('submit') this.eq(0).trigger(event) if (!event.defaultPrevented) this.get(0).submit() } return this } })(Zepto) //CSS3   ; (function($, undefined) { var prefix = '', eventPrefix, endEventName, endAnimationName, vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' }, document = window.document, testEl = document.createElement('div'), supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i, transform, transitionProperty, transitionDuration, transitionTiming, animationName, animationDuration, animationTiming, cssReset = {} //           -       , borderWidth ==> border-width function dasherize(str) { return downcase(str.replace(/([a-z])([A-Z])/, '$1-$2')) } function downcase(str) { return str.toLowerCase() } //        function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) } //          CSS          ,        webkit //      CSS     prefix   '-webkit-',          eventPrefix  Webkit $.each(vendors, function(vendor, event) { if (testEl.style[vendor + 'TransitionProperty'] !== undefined) { prefix = '-' + downcase(vendor) + '-' eventPrefix = event return false } }) transform = prefix + 'transform' cssReset[transitionProperty = prefix + 'transition-property'] = cssReset[transitionDuration = prefix + 'transition-duration'] = cssReset[transitionTiming = prefix + 'transition-timing-function'] = cssReset[animationName = prefix + 'animation-name'] = cssReset[animationDuration = prefix + 'animation-duration'] = cssReset[animationTiming = prefix + 'animation-timing-function'] = '' $.fx = { off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined), speeds: { _default: 400, fast: 200, slow: 600 }, cssPrefix: prefix, transitionEnd: normalizeEvent('TransitionEnd'), animationEnd: normalizeEvent('AnimationEnd') } $.fn.animate = function(properties, duration, ease, callback) { if ($.isPlainObject(duration)) ease = duration.easing, callback = duration.complete, duration = duration.duration //  duration    ,        ,      ,  $.fx.speeds        ,          ,      if (duration) duration = (typeof duration == 'number' ? duration : ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000 return this.anim(properties, duration, ease, callback) } $.fn.anim = function(properties, duration, ease, callback) { var key, cssValues = {}, cssProperties, transforms = '', that = this, wrappedCallback, endEvent = $.fx.transitionEnd //          if (duration === undefined) duration = 0.4 //        CSS3   , duration=0,            if ($.fx.off) duration = 0 //  properties      keyframe if (typeof properties == 'string') { // keyframe animation cssValues[animationName] = properties cssValues[animationDuration] = duration + 's' cssValues[animationTiming] = (ease || 'linear') endEvent = $.fx.animationEnd } else { cssProperties = [] // CSS transitions for (key in properties) //      CSS         if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') ' else cssValues[key] = properties[key], cssProperties.push(dasherize(key)) if (transforms) cssValues[transform] = transforms, cssProperties.push(transform) if (duration > 0 && typeof properties === 'object') { cssValues[transitionProperty] = cssProperties.join(', ') cssValues[transitionDuration] = duration + 's' cssValues[transitionTiming] = (ease || 'linear') } } wrappedCallback = function(event) { if (typeof event !== 'undefined') { if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below" $(event.target).unbind(endEvent, wrappedCallback) } $(this).css(cssReset) callback && callback.call(this) } //          ,            , //         ,         ,           if (duration > 0) this.bind(endEvent, wrappedCallback) // trigger page reflow so new elements can animate this.size() && this.get(0).clientLeft //   this.css(cssValues) //         0 ,     if (duration <= 0) setTimeout(function() { that.each(function() { wrappedCallback.call(this) }) }, 0) return this } testEl = null })(Zepto)

좋은 웹페이지 즐겨찾기