├── test
├── fixtures
│ ├── ajax_load_simple.html
│ ├── iframe_document.html
│ ├── zepto.json
│ ├── ajax_load_selector.html
│ └── ajax_load_selector_javascript.html
├── gesture_functional.html
├── test.css
├── server.coffee
├── polyfill.html
├── touchcancel_functional.html
├── stack.html
├── fx_functional.html
├── assets_functional.html
├── runner.coffee
├── touch_functional.html
├── selector.html
├── evidence_runner.js
├── form.html
├── event.html
├── data.html
├── touch.html
├── fx.html
└── detect.html
├── .travis.yml
├── script
├── guard
└── test
├── .gitignore
├── examples
├── anim.html
├── load_jquery_on_ie.html
├── touch_events.html
├── snow
│ └── index.html
└── iphone
│ ├── index.html
│ └── iphone.css
├── src
├── stack.js
├── assets.js
├── gesture.js
├── polyfill.js
├── form.js
├── fx_methods.js
├── data.js
├── detect.js
├── selector.js
├── touch.js
├── fx.js
├── event.js
├── ajax.js
└── zepto.js
├── CONTRIBUTING.md
├── package.json
├── MIT-LICENSE
├── make
├── README.md
└── vendor
└── evidence.js
/test/fixtures/ajax_load_simple.html:
--------------------------------------------------------------------------------
1 | simple ajax load
2 |
--------------------------------------------------------------------------------
/test/fixtures/iframe_document.html:
--------------------------------------------------------------------------------
1 | Hello from iframe!
2 |
--------------------------------------------------------------------------------
/test/fixtures/zepto.json:
--------------------------------------------------------------------------------
1 | {
2 | "zepto": "awesomeness"
3 | }
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 0.6
4 | script: script/test
5 |
--------------------------------------------------------------------------------
/script/guard:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | if [ -z "$BUNDLE_GEMFILE" ]; then
3 | export BUNDLE_GEMFILE=shutup
4 | fi
5 |
6 | exec guard --no-notify "$@"
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | dist/
3 | dist/zepto.min.js
4 | dist/zepto.js
5 | pkg
6 | *.swp
7 | docs/*
8 | .jhw-cache
9 | .rbenv-version
10 | public/
11 | node_modules
12 |
--------------------------------------------------------------------------------
/script/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | port=3999
3 | pidfile=test/server.pid
4 |
5 | ./node_modules/.bin/coffee test/server.coffee $port &
6 | pid=$!
7 |
8 | terminate_test_server() {
9 | kill $pid
10 | }
11 | trap terminate_test_server EXIT
12 |
13 | phantomjs test/runner.coffee "http://localhost:${port}/" "$@"
14 | exit $?
15 |
--------------------------------------------------------------------------------
/examples/anim.html:
--------------------------------------------------------------------------------
1 |
HELLO WORLD
2 |
3 |
4 |
5 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/src/stack.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | $.fn.end = function(){
7 | return this.prevObject || $()
8 | }
9 |
10 | $.fn.andSelf = function(){
11 | return this.add(this.prevObject || $())
12 | }
13 |
14 | 'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){
15 | var fn = $.fn[property]
16 | $.fn[property] = function(){
17 | var ret = fn.apply(this, arguments)
18 | ret.prevObject = this
19 | return ret
20 | }
21 | })
22 | })(Zepto)
23 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Code style guidelines
2 |
3 | * `function name() { }` for named functions
4 | * `function(){ }` for anonymous functions
5 | * No curly braces for single-line control flow statements such as `if` & friends
6 | * Don't write [semicolons that are optional][optional]
7 | * Put a single semicolon _before_ statements that start with `(` or `[`
8 | (see above article as for why it's needed)
9 | * Use long, descriptive variable and method names
10 | * Use blank lines to separate "paragraphs" of code for readability
11 | * Use comments to describe non-obvious code behavior
12 |
13 |
14 | [optional]: http://mislav.uniqpath.com/2010/05/semicolons/
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zepto"
3 | , "version": "1.0.0"
4 | , "homepage": "http://zeptojs.com"
5 | , "scripts": {
6 | "test": "coffee make test"
7 | , "dist": "coffee make dist"
8 | , "start": "coffee test/server.coffee"
9 | }
10 | , "repository": {
11 | "type": "git"
12 | , "url": "https://github.com/madrobby/zepto.git"
13 | }
14 | , "licenses": [
15 | {
16 | "type": "MIT"
17 | , "url": "http://zeptojs.com/license/"
18 | }
19 | ]
20 | , "devDependencies": {
21 | "uglify-js": "1.2.6"
22 | , "express": "3.1.x"
23 | , "coffee-script": "1.5.x"
24 | , "shelljs": "0.1.x"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/load_jquery_on_ie.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Load jQuery if Zepto is not supported
5 |
6 |
7 | Load jQuery if Zepto is not supported
8 |
9 |
10 |
18 |
19 |
--------------------------------------------------------------------------------
/src/assets.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | var cache = [], timeout
7 |
8 | $.fn.remove = function(){
9 | return this.each(function(){
10 | if(this.parentNode){
11 | if(this.tagName === 'IMG'){
12 | cache.push(this)
13 | this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
14 | if (timeout) clearTimeout(timeout)
15 | timeout = setTimeout(function(){ cache = [] }, 60000)
16 | }
17 | this.parentNode.removeChild(this)
18 | }
19 | })
20 | }
21 | })(Zepto)
22 |
--------------------------------------------------------------------------------
/test/fixtures/ajax_load_selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | testAjaxLoad
6 |
7 |
8 | ajax load with selector
9 |
10 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/fixtures/ajax_load_selector_javascript.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | testAjaxLoad
6 |
7 |
8 | ajax load with selector
9 |
10 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
11 |
12 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/touch_events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
13 |
14 |
15 | List item 1 DELETE
16 | List item 2 DELETE
17 | List item 3 DELETE
18 | List item 4 DELETE
19 |
20 |
21 |
31 |
--------------------------------------------------------------------------------
/test/gesture_functional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zepto gesture functional test
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Zepto gestures functional test
14 |
15 |
16 | gesture events test
17 |
18 |
19 |
20 |
21 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/test/test.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 1em;
3 | font: medium "American Typewriter", Helvetica, sans-serif;
4 | }
5 | a:link, a:visited { color: darkblue; }
6 | #results.failed em { font-style: normal; color: crimson; }
7 | #results.passed em { font-style: normal; color: darkgreen; }
8 | #fixtures {
9 | position: absolute;
10 | top: -10000px;
11 | left: -10000px;
12 | }
13 | #nav {
14 | list-style: none;
15 | padding: 0;
16 | margin: 2em 0 0 0;
17 | font-size: 12px;
18 | max-width: 30em;
19 | }
20 | #nav a {
21 | padding: .8em 1.5em;
22 | background: #eee;
23 | border-top: 2px solid white;
24 | text-decoration: none;
25 | text-transform: uppercase;
26 | letter-spacing: .1em;
27 | display: block;
28 | color: #555;
29 | }
30 | #nav .current a { background: #ccc; color: black; }
31 | #nav a:active { background: #555; color: white; }
32 |
33 | @media only screen and (max-device-width:480px) {
34 | body { margin: 7px; font-size: small; }
35 | h1 { margin: 0; }
36 | h1, #results { text-align: center; }
37 | #results { min-height: 3em; }
38 | #nav { font-size: 14px; max-width: auto; }
39 | }
40 |
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010-2012 Thomas Fuchs
2 | http://zeptojs.com/
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/gesture.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | if ($.os.ios) {
7 | var gesture = {}, gestureTimeout
8 |
9 | function parentIfText(node){
10 | return 'tagName' in node ? node : node.parentNode
11 | }
12 |
13 | $(document).bind('gesturestart', function(e){
14 | var now = Date.now(), delta = now - (gesture.last || now)
15 | gesture.target = parentIfText(e.target)
16 | gestureTimeout && clearTimeout(gestureTimeout)
17 | gesture.e1 = e.scale
18 | gesture.last = now
19 | }).bind('gesturechange', function(e){
20 | gesture.e2 = e.scale
21 | }).bind('gestureend', function(e){
22 | if (gesture.e2 > 0) {
23 | Math.abs(gesture.e1 - gesture.e2) != 0 && $(gesture.target).trigger('pinch') &&
24 | $(gesture.target).trigger('pinch' + (gesture.e1 - gesture.e2 > 0 ? 'In' : 'Out'))
25 | gesture.e1 = gesture.e2 = gesture.last = 0
26 | } else if ('last' in gesture) {
27 | gesture = {}
28 | }
29 | })
30 |
31 | ;['pinch', 'pinchIn', 'pinchOut'].forEach(function(m){
32 | $.fn[m] = function(callback){ return this.bind(m, callback) }
33 | })
34 | }
35 | })(Zepto)
36 |
--------------------------------------------------------------------------------
/src/polyfill.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function(undefined){
6 | if (String.prototype.trim === undefined) // fix for iOS 3.2
7 | String.prototype.trim = function(){ return this.replace(/^\s+|\s+$/g, '') }
8 |
9 | // For iOS 3.x
10 | // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
11 | if (Array.prototype.reduce === undefined)
12 | Array.prototype.reduce = function(fun){
13 | if(this === void 0 || this === null) throw new TypeError()
14 | var t = Object(this), len = t.length >>> 0, k = 0, accumulator
15 | if(typeof fun != 'function') throw new TypeError()
16 | if(len == 0 && arguments.length == 1) throw new TypeError()
17 |
18 | if(arguments.length >= 2)
19 | accumulator = arguments[1]
20 | else
21 | do{
22 | if(k in t){
23 | accumulator = t[k++]
24 | break
25 | }
26 | if(++k >= len) throw new TypeError()
27 | } while (true)
28 |
29 | while (k < len){
30 | if(k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t)
31 | k++
32 | }
33 | return accumulator
34 | }
35 |
36 | })()
37 |
--------------------------------------------------------------------------------
/src/form.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function ($) {
6 | $.fn.serializeArray = function () {
7 | var result = [], el
8 | $( Array.prototype.slice.call(this.get(0).elements) ).each(function () {
9 | el = $(this)
10 | var type = el.attr('type')
11 | if (this.nodeName.toLowerCase() != 'fieldset' &&
12 | !this.disabled && type != 'submit' && type != 'reset' && type != 'button' &&
13 | ((type != 'radio' && type != 'checkbox') || this.checked))
14 | result.push({
15 | name: el.attr('name'),
16 | value: el.val()
17 | })
18 | })
19 | return result
20 | }
21 |
22 | $.fn.serialize = function () {
23 | var result = []
24 | this.serializeArray().forEach(function (elm) {
25 | result.push( encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value) )
26 | })
27 | return result.join('&')
28 | }
29 |
30 | $.fn.submit = function (callback) {
31 | if (callback) this.bind('submit', callback)
32 | else if (this.length) {
33 | var event = $.Event('submit')
34 | this.eq(0).trigger(event)
35 | if (!event.defaultPrevented) this.get(0).submit()
36 | }
37 | return this
38 | }
39 |
40 | })(Zepto)
41 |
--------------------------------------------------------------------------------
/test/server.coffee:
--------------------------------------------------------------------------------
1 | express = require 'express'
2 | app = express()
3 |
4 | module.exports = app
5 |
6 | project_root = __dirname.replace(/\/[^\/]+$/, '/')
7 | app.use express.static(project_root)
8 | app.use express.static(project_root + 'node_modules/mocha')
9 | app.use express.static(project_root + 'node_modules/chai')
10 |
11 | app.use express.bodyParser()
12 |
13 | mime = (req) ->
14 | type = req.headers['content-type'] or ''
15 | type.split(';')[0]
16 |
17 | dump = (obj) ->
18 | obj = '' unless obj
19 | obj = JSON.stringify(obj) if obj and typeof obj isnt "string"
20 | obj
21 |
22 | app.all '/test/echo', (req, res) ->
23 | res.send """
24 | #{req.method} ?#{dump(req.query)}
25 | content-type: #{mime(req)}
26 | accept: #{req.headers['accept']}
27 | #{dump(req.body)}
28 | """
29 |
30 | app.get '/test/jsonp', (req, res) ->
31 | res.jsonp
32 | query: req.query
33 | hello: 'world'
34 |
35 | app.get '/test/json', (req, res) ->
36 | if /json/.test req.headers['accept']
37 | res.json
38 | query: req.query
39 | hello: 'world'
40 | else
41 | res.send 400, 'FAIL'
42 |
43 | app.all '/test/slow', (req, res) ->
44 | setTimeout ->
45 | res.send 'DONE'
46 | , 200
47 |
48 | app.all '/test/error', (req, res) ->
49 | res.send 500, 'BOOM'
50 |
51 | if process.argv[1] is __filename
52 | port = process.argv[2]
53 | unless port
54 | port = 3000
55 | console.log "Listening on port #{port}"
56 | app.listen port
57 |
--------------------------------------------------------------------------------
/test/polyfill.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto compatibility unit tests
8 |
9 |
10 |
11 |
12 |
13 |
14 | Compatibility tests
15 |
16 | Running… see browser console for results
17 |
18 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/test/touchcancel_functional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zepto touch functional test
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Zepto touch functional test
14 |
15 |
16 | Double-tap and hold until the JavaScript alert occurs. After closing the
17 | alert, tap again. Without touchcancel you will see a double tap instead of a tap.
18 |
19 |
20 |
21 | touch events test
22 |
23 |
24 |
25 |
26 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/test/stack.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto Stack unit tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Zepto DOM unit tests
16 |
17 | Running… see browser console for results
18 |
19 |
20 |
21 |
25 |
26 |
32 |
33 |
34 |
35 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/examples/snow/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Let it snow with Zepto.js
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/test/fx_functional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto fx functional test
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 | Zepto fx functional
20 |
21 |
24 |
25 |
28 |
29 | Hide
30 | Show
31 | Reg. show
32 | Toggle
33 | Both: Toggle ('slow')
34 | Both: Toggle
35 |
36 | Fade in
37 | Fade out
38 | Fade toggle
39 | Both: Fade toggle
40 |
41 |
42 |
43 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/test/assets_functional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zepto assets functional test
6 |
7 |
8 |
9 |
22 |
23 |
24 | Zepto assets functional test
25 |
26 |
27 |
28 |
33 |
34 | When you run this test without the assets plugin, Mobile Safari will stop loading after on average 8 images (that's on the iPad with 1 MB images). It might also crash.
35 | PLEASE NOTE: You must restart Safari between runs (click the home button to return to the home screen, double-click the home button, tap-and-hold the Safari icon, then tap the minus badge).
36 |
37 |
38 |
39 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/examples/iphone/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | iPhone.Zepto
5 |
6 |
7 |
8 |
9 |
10 |
11 |
23 |
32 |
33 |
34 |
35 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/test/runner.coffee:
--------------------------------------------------------------------------------
1 | # Test runner for PhantomJS
2 | # Usage:
3 | # $ phantomjs test/runner.coffee [, , ...]
4 | #
5 | # When no test pages specified, runs all automated tests.
6 |
7 | system = require('system')
8 | fs = require('fs')
9 |
10 | args = system.args.slice(1)
11 | prefix = args.shift() || "file://#{fs.workingDirectory}/"
12 |
13 | if args.length > 0
14 | # list of test pages to run
15 | suites = args
16 | else
17 | # by default, run all test/*.html pages
18 | modules = 'zepto ajax data detect event form fx selector stack'.split /\s+/
19 | suites = modules.map (name)-> "test/#{name}.html"
20 |
21 | page = require('webpage').create()
22 |
23 | page.onConsoleMessage = (msg) ->
24 | console.log msg
25 |
26 | page.onError = (msg, trace) ->
27 | console.log 'ERROR: ' + msg
28 |
29 | # used for waiting until the tests finish running
30 | waitFor = (testFn, onReady, timeout=3000) ->
31 | start = new Date()
32 | interval = setInterval ->
33 | if testFn()
34 | clearInterval interval
35 | onReady()
36 | else if new Date() - start > timeout
37 | console.log "timed out."
38 | phantom.exit(1)
39 | , 100
40 |
41 | loadNextSuite = ->
42 | if not suites.length
43 | phantom.exit()
44 | else
45 | url = suites.shift() + "?verbosity=WARN"
46 | # PhantomJS chokes on the query string on relative paths
47 | url = prefix + url if not /:\/\//.test url
48 |
49 | page.open url, (status) ->
50 | if status isnt "success"
51 | console.log "failed opening #{url}"
52 | phantom.exit(1)
53 |
54 | waitFor ->
55 | page.evaluate ->
56 | # the "#results" element needs to have the "finished" class
57 | res = document.getElementById 'results'
58 | /finished/.test res.className if res
59 | , ->
60 | passed = page.evaluate ->
61 | res = document.getElementById 'results'
62 | paths = location.pathname.split('/')
63 | # echo test results to the console
64 | console.log "#{paths[paths.length - 1]} - " + res.textContent
65 | /passed/.test res.className
66 |
67 | if passed
68 | loadNextSuite()
69 | else
70 | phantom.exit(1)
71 |
72 | loadNextSuite()
73 |
--------------------------------------------------------------------------------
/src/fx_methods.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($, undefined){
6 | var document = window.document, docElem = document.documentElement,
7 | origShow = $.fn.show, origHide = $.fn.hide, origToggle = $.fn.toggle
8 |
9 | function anim(el, speed, opacity, scale, callback) {
10 | if (typeof speed == 'function' && !callback) callback = speed, speed = undefined
11 | var props = { opacity: opacity }
12 | if (scale) {
13 | props.scale = scale
14 | el.css($.fx.cssPrefix + 'transform-origin', '0 0')
15 | }
16 | return el.animate(props, speed, null, callback)
17 | }
18 |
19 | function hide(el, speed, scale, callback) {
20 | return anim(el, speed, 0, scale, function(){
21 | origHide.call($(this))
22 | callback && callback.call(this)
23 | })
24 | }
25 |
26 | $.fn.show = function(speed, callback) {
27 | origShow.call(this)
28 | if (speed === undefined) speed = 0
29 | else this.css('opacity', 0)
30 | return anim(this, speed, 1, '1,1', callback)
31 | }
32 |
33 | $.fn.hide = function(speed, callback) {
34 | if (speed === undefined) return origHide.call(this)
35 | else return hide(this, speed, '0,0', callback)
36 | }
37 |
38 | $.fn.toggle = function(speed, callback) {
39 | if (speed === undefined || typeof speed == 'boolean')
40 | return origToggle.call(this, speed)
41 | else return this.each(function(){
42 | var el = $(this)
43 | el[el.css('display') == 'none' ? 'show' : 'hide'](speed, callback)
44 | })
45 | }
46 |
47 | $.fn.fadeTo = function(speed, opacity, callback) {
48 | return anim(this, speed, opacity, null, callback)
49 | }
50 |
51 | $.fn.fadeIn = function(speed, callback) {
52 | var target = this.css('opacity')
53 | if (target > 0) this.css('opacity', 0)
54 | else target = 1
55 | return origShow.call(this).fadeTo(speed, target, callback)
56 | }
57 |
58 | $.fn.fadeOut = function(speed, callback) {
59 | return hide(this, speed, null, callback)
60 | }
61 |
62 | $.fn.fadeToggle = function(speed, callback) {
63 | return this.each(function(){
64 | var el = $(this)
65 | el[
66 | (el.css('opacity') == 0 || el.css('display') == 'none') ? 'fadeIn' : 'fadeOut'
67 | ](speed, callback)
68 | })
69 | }
70 |
71 | })(Zepto)
72 |
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | // The following code is heavily inspired by jQuery's $.fn.data()
6 |
7 | ;(function($) {
8 | var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
9 | exp = $.expando = 'Zepto' + (+new Date())
10 |
11 | // Get value from node:
12 | // 1. first try key as given,
13 | // 2. then try camelized key,
14 | // 3. fall back to reading "data-*" attribute.
15 | function getData(node, name) {
16 | var id = node[exp], store = id && data[id]
17 | if (name === undefined) return store || setData(node)
18 | else {
19 | if (store) {
20 | if (name in store) return store[name]
21 | var camelName = camelize(name)
22 | if (camelName in store) return store[camelName]
23 | }
24 | return dataAttr.call($(node), name)
25 | }
26 | }
27 |
28 | // Store value under camelized key on node
29 | function setData(node, name, value) {
30 | var id = node[exp] || (node[exp] = ++$.uuid),
31 | store = data[id] || (data[id] = attributeData(node))
32 | if (name !== undefined) store[camelize(name)] = value
33 | return store
34 | }
35 |
36 | // Read all "data-*" attributes from a node
37 | function attributeData(node) {
38 | var store = {}
39 | $.each(node.attributes, function(i, attr){
40 | if (attr.name.indexOf('data-') == 0)
41 | store[camelize(attr.name.replace('data-', ''))] =
42 | $.zepto.deserializeValue(attr.value)
43 | })
44 | return store
45 | }
46 |
47 | $.fn.data = function(name, value) {
48 | return value === undefined ?
49 | // set multiple values via object
50 | $.isPlainObject(name) ?
51 | this.each(function(i, node){
52 | $.each(name, function(key, value){ setData(node, key, value) })
53 | }) :
54 | // get value from first element
55 | this.length == 0 ? undefined : getData(this[0], name) :
56 | // set value on all elements
57 | this.each(function(){ setData(this, name, value) })
58 | }
59 |
60 | $.fn.removeData = function(names) {
61 | if (typeof names == 'string') names = names.split(/\s+/)
62 | return this.each(function(){
63 | var id = this[exp], store = id && data[id]
64 | if (store) $.each(names, function(){ delete store[camelize(this)] })
65 | })
66 | }
67 | })(Zepto)
68 |
--------------------------------------------------------------------------------
/src/detect.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | function detect(ua){
7 | var os = this.os = {}, browser = this.browser = {},
8 | webkit = ua.match(/WebKit\/([\d.]+)/),
9 | android = ua.match(/(Android)\s+([\d.]+)/),
10 | ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
11 | iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
12 | webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),
13 | touchpad = webos && ua.match(/TouchPad/),
14 | kindle = ua.match(/Kindle\/([\d.]+)/),
15 | silk = ua.match(/Silk\/([\d._]+)/),
16 | blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/),
17 | bb10 = ua.match(/(BB10).*Version\/([\d.]+)/),
18 | rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/),
19 | playbook = ua.match(/PlayBook/),
20 | chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/),
21 | firefox = ua.match(/Firefox\/([\d.]+)/)
22 |
23 | // Todo: clean this up with a better OS/browser seperation:
24 | // - discern (more) between multiple browsers on android
25 | // - decide if kindle fire in silk mode is android or not
26 | // - Firefox on Android doesn't specify the Android version
27 | // - possibly devide in os, device and browser hashes
28 |
29 | if (browser.webkit = !!webkit) browser.version = webkit[1]
30 |
31 | if (android) os.android = true, os.version = android[2]
32 | if (iphone) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.')
33 | if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.')
34 | if (webos) os.webos = true, os.version = webos[2]
35 | if (touchpad) os.touchpad = true
36 | if (blackberry) os.blackberry = true, os.version = blackberry[2]
37 | if (bb10) os.bb10 = true, os.version = bb10[2]
38 | if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]
39 | if (playbook) browser.playbook = true
40 | if (kindle) os.kindle = true, os.version = kindle[1]
41 | if (silk) browser.silk = true, browser.version = silk[1]
42 | if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true
43 | if (chrome) browser.chrome = true, browser.version = chrome[1]
44 | if (firefox) browser.firefox = true, browser.version = firefox[1]
45 |
46 | os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) || (firefox && ua.match(/Tablet/)))
47 | os.phone = !!(!os.tablet && (android || iphone || webos || blackberry || bb10 ||
48 | (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) || (firefox && ua.match(/Mobile/))))
49 | }
50 |
51 | detect.call($, navigator.userAgent)
52 | // make available to unit tests
53 | $.__detect = detect
54 |
55 | })(Zepto)
56 |
--------------------------------------------------------------------------------
/make:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env coffee
2 | require 'shelljs/make'
3 | fs = require 'fs'
4 |
5 | version = '1.0'
6 | zepto_js = 'dist/zepto.js'
7 | zepto_min = 'dist/zepto.min.js'
8 | zepto_gz = 'dist/zepto.min.gz'
9 |
10 | port = 3999
11 | root = __dirname + '/'
12 |
13 | target.all = ->
14 | target[zepto_js]()
15 | target.test()
16 |
17 | ## TASKS ##
18 |
19 | target.test = ->
20 | test_app = require './test/server'
21 | server = test_app.listen port
22 | exec "phantomjs test/runner.coffee 'http://localhost:#{port}/'", (code) ->
23 | server.close -> exit(code)
24 |
25 | target[zepto_js] = ->
26 | target.build() unless test('-e', zepto_js)
27 |
28 | target[zepto_min] = ->
29 | target.minify() if stale(zepto_min, zepto_js)
30 |
31 | target[zepto_gz] = ->
32 | target.compress() if stale(zepto_gz, zepto_min)
33 |
34 | target.dist = ->
35 | target.build()
36 | target.minify()
37 | target.compress()
38 |
39 | target.build = ->
40 | cd __dirname
41 | mkdir '-p', 'dist'
42 | modules = (env['MODULES'] || 'polyfill zepto detect event ajax form fx').split(' ')
43 | module_files = ( "src/#{module}.js" for module in modules )
44 | intro = "/* Zepto #{describe_version()} - #{modules.join(' ')} - zeptojs.com/license */\n"
45 | dist = intro + cat(module_files).replace(/^\/[\/*].*$/mg, '').replace(/\n{3,}/g, "\n\n")
46 | dist.to(zepto_js)
47 | report_size(zepto_js)
48 |
49 | target.minify = ->
50 | target.build() unless test('-e', zepto_js)
51 | zepto_code = cat(zepto_js)
52 | intro = zepto_code.slice(0, zepto_code.indexOf("\n") + 1)
53 | (intro + minify(zepto_code)).to(zepto_min)
54 | report_size(zepto_min)
55 |
56 | target.compress = ->
57 | gzip = require('zlib').createGzip()
58 | inp = fs.createReadStream(zepto_min)
59 | out = fs.createWriteStream(zepto_gz)
60 | inp.pipe(gzip).pipe(out)
61 | out.on 'close', ->
62 | report_size(zepto_gz)
63 | factor = fsize(zepto_js) / fsize(zepto_gz)
64 | echo "compression factor: #{format_number(factor)}"
65 |
66 | ## HELPERS ##
67 |
68 | stale = (file, source) ->
69 | target[source]()
70 | !test('-e', file) || mtime(file) < mtime(source)
71 |
72 | mtime = (file) ->
73 | fs.statSync(file).mtime.getTime()
74 |
75 | fsize = (file) ->
76 | fs.statSync(file).size
77 |
78 | format_number = (size, precision = 1) ->
79 | factor = Math.pow(10, precision)
80 | decimal = Math.round(size * factor) % factor
81 | parseInt(size) + "." + decimal
82 |
83 | report_size = (file) ->
84 | echo "#{file}: #{format_number(fsize(file) / 1024)} KiB"
85 |
86 | describe_version = ->
87 | desc = exec "git --git-dir='#{root + '.git'}' describe --tags HEAD", silent: true
88 | if desc.code is 0 then desc.output.replace(/\s+$/, '') else version
89 |
90 | minify = (source_code) ->
91 | uglify = require('uglify-js')
92 | ast = uglify.parser.parse(source_code)
93 | ast = uglify.uglify.ast_mangle(ast)
94 | ast = uglify.uglify.ast_squeeze(ast)
95 | uglify.uglify.gen_code(ast)
96 |
--------------------------------------------------------------------------------
/test/touch_functional.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Zepto touch functional test
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Zepto touch functional test
14 |
15 |
16 | touch events test
17 |
18 |
19 |
20 | touch events test (scrollable cancel)
21 |
22 |
23 |
24 | touch events test (scrollable cancel, single tap only)
25 |
26 |
27 |
28 |
29 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/test/selector.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto selector tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Zepto selector tests
16 |
17 | Running… see browser console for results
18 |
19 |
20 |
21 |
look at me!
22 |
can't see me
23 |
24 | child1
25 | child2
26 |
27 | child3
28 | child4
29 |
30 |
31 |
32 |
33 |
34 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/src/selector.js:
--------------------------------------------------------------------------------
1 | ;(function($){
2 | var zepto = $.zepto, oldQsa = zepto.qsa, oldMatches = zepto.matches
3 |
4 | function visible(elem){
5 | elem = $(elem)
6 | return !!(elem.width() || elem.height()) && elem.css("display") !== "none"
7 | }
8 |
9 | // Implements a subset from:
10 | // http://api.jquery.com/category/selectors/jquery-selector-extensions/
11 | //
12 | // Each filter function receives the current index, all nodes in the
13 | // considered set, and a value if there were parentheses. The value
14 | // of `this` is the node currently being considered. The function returns the
15 | // resulting node(s), null, or undefined.
16 | //
17 | // Complex selectors are not supported:
18 | // li:has(label:contains("foo")) + li:has(label:contains("bar"))
19 | // ul.inner:first > li
20 | var filters = $.expr[':'] = {
21 | visible: function(){ if (visible(this)) return this },
22 | hidden: function(){ if (!visible(this)) return this },
23 | selected: function(){ if (this.selected) return this },
24 | checked: function(){ if (this.checked) return this },
25 | parent: function(){ return this.parentNode },
26 | first: function(idx){ if (idx === 0) return this },
27 | last: function(idx, nodes){ if (idx === nodes.length - 1) return this },
28 | eq: function(idx, _, value){ if (idx === value) return this },
29 | contains: function(idx, _, text){ if ($(this).text().indexOf(text) > -1) return this },
30 | has: function(idx, _, sel){ if (zepto.qsa(this, sel).length) return this }
31 | }
32 |
33 | var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*'),
34 | childRe = /^\s*>/,
35 | classTag = 'Zepto' + (+new Date())
36 |
37 | function process(sel, fn) {
38 | // quote the hash in `a[href^=#]` expression
39 | sel = sel.replace(/=#\]/g, '="#"]')
40 | var filter, arg, match = filterRe.exec(sel)
41 | if (match && match[2] in filters) {
42 | filter = filters[match[2]], arg = match[3]
43 | sel = match[1]
44 | if (arg) {
45 | var num = Number(arg)
46 | if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '')
47 | else arg = num
48 | }
49 | }
50 | return fn(sel, filter, arg)
51 | }
52 |
53 | zepto.qsa = function(node, selector) {
54 | return process(selector, function(sel, filter, arg){
55 | try {
56 | var taggedParent
57 | if (!sel && filter) sel = '*'
58 | else if (childRe.test(sel))
59 | // support "> *" child queries by tagging the parent node with a
60 | // unique class and prepending that classname onto the selector
61 | taggedParent = $(node).addClass(classTag), sel = '.'+classTag+' '+sel
62 |
63 | var nodes = oldQsa(node, sel)
64 | } catch(e) {
65 | console.error('error performing selector: %o', selector)
66 | throw e
67 | } finally {
68 | if (taggedParent) taggedParent.removeClass(classTag)
69 | }
70 | return !filter ? nodes :
71 | zepto.uniq($.map(nodes, function(n, i){ return filter.call(n, i, nodes, arg) }))
72 | })
73 | }
74 |
75 | zepto.matches = function(node, selector){
76 | return process(selector, function(sel, filter, arg){
77 | return (!sel || oldMatches(node, sel)) &&
78 | (!filter || filter.call(node, null, arg) === node)
79 | })
80 | }
81 | })(Zepto)
82 |
--------------------------------------------------------------------------------
/test/evidence_runner.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | var ConsoleTestRunner = Evidence.AutoRunner.RUNNERS.console,
3 | ConsoleTestResult = Evidence.UI.Console.TestResult,
4 | AutoRunner = Evidence.AutoRunner,
5 | printf = Evidence.UI.printf
6 |
7 | function inherit(superclass, extra) {
8 | var klass = function(){
9 | this.initialize.apply(this, arguments)
10 | }
11 | var tmp = function(){}
12 | tmp.prototype = superclass.prototype
13 | klass.prototype = new tmp()
14 | klass.prototype.constructor = klass
15 | klass.prototype.initialize = function(){
16 | superclass.apply(this, arguments)
17 | }
18 |
19 | if (extra) {
20 | var methods = extra.call(klass, superclass.prototype)
21 | for (var method in methods) klass.prototype[method] = methods[method]
22 | }
23 | return klass
24 | }
25 |
26 | var TestRunner = inherit(ConsoleTestRunner, function(_super) {
27 | AutoRunner.RUNNERS.zepto = this
28 | return {
29 | _makeResult: function() { return new TestResult(this.logger) }
30 | }
31 | })
32 |
33 | var TestResult = inherit(ConsoleTestResult, function(_super) {
34 | return {
35 | start: function(t0) {
36 | Evidence.TestResult.prototype.start.call(this, t0)
37 | this.logger.debug('Started tests.')
38 | },
39 | stop: function(t1) {
40 | _super.stop.call(this, t1)
41 | displayResults(this, (t1-this.t0)/1000)
42 | checkLeakedGlobals()
43 | },
44 | pauseTest: function(testcase) {
45 | this.logger.debug('Paused testcase ' + testcase + '.')
46 | },
47 | restartTest: function(testcase) {
48 | this.logger.debug('Restarted testcase ' + testcase + '.')
49 | },
50 | startSuite: function(suite) {
51 | this.logger.debug('Started suite ' + suite + '.')
52 | }
53 | }
54 | })
55 |
56 | // HACK: force our test runner as default
57 | ;(function(){
58 | var _super = AutoRunner.prototype.retrieveOptions
59 | AutoRunner.prototype.retrieveOptions = function() {
60 | var options = _super.call(this)
61 | if (!options.runner) options.runner = 'zepto'
62 | return options
63 | }
64 | })()
65 |
66 | function $(id) { return document.getElementById(id) }
67 |
68 | function displayResults(results, seconds) {
69 | var container = $('results')
70 | if (container) {
71 | if (results.failureCount || results.errorCount) {
72 | container.className = 'failed'
73 | container.innerHTML = printf("Finished in %d s. – %d failures, %d errors (%d assertions)",
74 | [seconds, results.failureCount, results.errorCount, results.assertionCount])
75 | } else {
76 | container.className = 'passed'
77 | container.innerHTML = printf("Finished in %d s. – %d tests passed (%d assertions)",
78 | [seconds, results.testCount, results.assertionCount])
79 | }
80 | container.className += ' finished'
81 | }
82 | }
83 |
84 | var globals = [], expected = ['Zepto', '$', 'Evidence']
85 | for (var key in window) globals.push(key)
86 |
87 | function checkLeakedGlobals() {
88 | var opera = /^Opera\b/.test(navigator.userAgent)
89 | for (var key in window)
90 | if ( globals.indexOf(key) < 0 && expected.indexOf(key) < 0 &&
91 | (!opera || typeof window[key] != 'object' || window[key].id != key) &&
92 | window.console && console.warn
93 | )
94 | console.warn("unexpected global: " + key)
95 | }
96 | })()
97 |
--------------------------------------------------------------------------------
/src/touch.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | var touch = {},
7 | touchTimeout, tapTimeout, swipeTimeout,
8 | longTapDelay = 750, longTapTimeout
9 |
10 | function parentIfText(node) {
11 | return 'tagName' in node ? node : node.parentNode
12 | }
13 |
14 | function swipeDirection(x1, x2, y1, y2) {
15 | var xDelta = Math.abs(x1 - x2), yDelta = Math.abs(y1 - y2)
16 | return xDelta >= yDelta ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
17 | }
18 |
19 | function longTap() {
20 | longTapTimeout = null
21 | if (touch.last) {
22 | touch.el.trigger('longTap')
23 | touch = {}
24 | }
25 | }
26 |
27 | function cancelLongTap() {
28 | if (longTapTimeout) clearTimeout(longTapTimeout)
29 | longTapTimeout = null
30 | }
31 |
32 | function cancelAll() {
33 | if (touchTimeout) clearTimeout(touchTimeout)
34 | if (tapTimeout) clearTimeout(tapTimeout)
35 | if (swipeTimeout) clearTimeout(swipeTimeout)
36 | if (longTapTimeout) clearTimeout(longTapTimeout)
37 | touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null
38 | touch = {}
39 | }
40 |
41 | $(document).ready(function(){
42 | var now, delta
43 |
44 | $(document.body)
45 | .bind('touchstart', function(e){
46 | now = Date.now()
47 | delta = now - (touch.last || now)
48 | touch.el = $(parentIfText(e.touches[0].target))
49 | touchTimeout && clearTimeout(touchTimeout)
50 | touch.x1 = e.touches[0].pageX
51 | touch.y1 = e.touches[0].pageY
52 | if (delta > 0 && delta <= 250) touch.isDoubleTap = true
53 | touch.last = now
54 | longTapTimeout = setTimeout(longTap, longTapDelay)
55 | })
56 | .bind('touchmove', function(e){
57 | cancelLongTap()
58 | touch.x2 = e.touches[0].pageX
59 | touch.y2 = e.touches[0].pageY
60 | if (Math.abs(touch.x1 - touch.x2) > 10)
61 | e.preventDefault()
62 | })
63 | .bind('touchend', function(e){
64 | cancelLongTap()
65 |
66 | // swipe
67 | if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
68 | (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))
69 |
70 | swipeTimeout = setTimeout(function() {
71 | touch.el.trigger('swipe')
72 | touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
73 | touch = {}
74 | }, 0)
75 |
76 | // normal tap
77 | else if ('last' in touch)
78 |
79 | // delay by one tick so we can cancel the 'tap' event if 'scroll' fires
80 | // ('tap' fires before 'scroll')
81 | tapTimeout = setTimeout(function() {
82 |
83 | // trigger universal 'tap' with the option to cancelTouch()
84 | // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
85 | var event = $.Event('tap')
86 | event.cancelTouch = cancelAll
87 | touch.el.trigger(event)
88 |
89 | // trigger double tap immediately
90 | if (touch.isDoubleTap) {
91 | touch.el.trigger('doubleTap')
92 | touch = {}
93 | }
94 |
95 | // trigger single tap after 250ms of inactivity
96 | else {
97 | touchTimeout = setTimeout(function(){
98 | touchTimeout = null
99 | touch.el.trigger('singleTap')
100 | touch = {}
101 | }, 250)
102 | }
103 |
104 | }, 0)
105 |
106 | })
107 | .bind('touchcancel', cancelAll)
108 |
109 | $(window).bind('scroll', cancelAll)
110 | })
111 |
112 | ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown', 'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(m){
113 | $.fn[m] = function(callback){ return this.bind(m, callback) }
114 | })
115 | })(Zepto)
116 |
--------------------------------------------------------------------------------
/src/fx.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($, undefined){
6 | var prefix = '', eventPrefix, endEventName, endAnimationName,
7 | vendors = { Webkit: 'webkit', Moz: '', O: 'o', ms: 'MS' },
8 | document = window.document, testEl = document.createElement('div'),
9 | supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,
10 | transform,
11 | transitionProperty, transitionDuration, transitionTiming,
12 | animationName, animationDuration, animationTiming,
13 | cssReset = {}
14 |
15 | function dasherize(str) { return downcase(str.replace(/([a-z])([A-Z])/, '$1-$2')) }
16 | function downcase(str) { return str.toLowerCase() }
17 | function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : downcase(name) }
18 |
19 | $.each(vendors, function(vendor, event){
20 | if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
21 | prefix = '-' + downcase(vendor) + '-'
22 | eventPrefix = event
23 | return false
24 | }
25 | })
26 |
27 | transform = prefix + 'transform'
28 | cssReset[transitionProperty = prefix + 'transition-property'] =
29 | cssReset[transitionDuration = prefix + 'transition-duration'] =
30 | cssReset[transitionTiming = prefix + 'transition-timing-function'] =
31 | cssReset[animationName = prefix + 'animation-name'] =
32 | cssReset[animationDuration = prefix + 'animation-duration'] =
33 | cssReset[animationTiming = prefix + 'animation-timing-function'] = ''
34 |
35 | $.fx = {
36 | off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),
37 | speeds: { _default: 400, fast: 200, slow: 600 },
38 | cssPrefix: prefix,
39 | transitionEnd: normalizeEvent('TransitionEnd'),
40 | animationEnd: normalizeEvent('AnimationEnd')
41 | }
42 |
43 | $.fn.animate = function(properties, duration, ease, callback){
44 | if ($.isPlainObject(duration))
45 | ease = duration.easing, callback = duration.complete, duration = duration.duration
46 | if (duration) duration = (typeof duration == 'number' ? duration :
47 | ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000
48 | return this.anim(properties, duration, ease, callback)
49 | }
50 |
51 | $.fn.anim = function(properties, duration, ease, callback){
52 | var key, cssValues = {}, cssProperties, transforms = '',
53 | that = this, wrappedCallback, endEvent = $.fx.transitionEnd
54 |
55 | if (duration === undefined) duration = 0.4
56 | if ($.fx.off) duration = 0
57 |
58 | if (typeof properties == 'string') {
59 | // keyframe animation
60 | cssValues[animationName] = properties
61 | cssValues[animationDuration] = duration + 's'
62 | cssValues[animationTiming] = (ease || 'linear')
63 | endEvent = $.fx.animationEnd
64 | } else {
65 | cssProperties = []
66 | // CSS transitions
67 | for (key in properties)
68 | if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '
69 | else cssValues[key] = properties[key], cssProperties.push(dasherize(key))
70 |
71 | if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)
72 | if (duration > 0 && typeof properties === 'object') {
73 | cssValues[transitionProperty] = cssProperties.join(', ')
74 | cssValues[transitionDuration] = duration + 's'
75 | cssValues[transitionTiming] = (ease || 'linear')
76 | }
77 | }
78 |
79 | wrappedCallback = function(event){
80 | if (typeof event !== 'undefined') {
81 | if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below"
82 | $(event.target).unbind(endEvent, wrappedCallback)
83 | }
84 | $(this).css(cssReset)
85 | callback && callback.call(this)
86 | }
87 | if (duration > 0) this.bind(endEvent, wrappedCallback)
88 |
89 | // trigger page reflow so new elements can animate
90 | this.size() && this.get(0).clientLeft
91 |
92 | this.css(cssValues)
93 |
94 | if (duration <= 0) setTimeout(function() {
95 | that.each(function(){ wrappedCallback.call(this) })
96 | }, 0)
97 |
98 | return this
99 | }
100 |
101 | testEl = null
102 | })(Zepto)
103 |
--------------------------------------------------------------------------------
/test/form.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto form unit tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Zepto form tests
17 |
18 | Running… see browser console for results
19 |
20 |
21 |
53 |
54 |
142 |
143 |
144 |
--------------------------------------------------------------------------------
/test/event.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto event tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Zepto event tests
16 |
17 | Running… see browser console for results
18 |
19 |
20 |
21 |
22 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/examples/iphone/iphone.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0px;
3 | padding: 0px;
4 | }
5 | .toolbar {
6 | -webkit-box-sizing: border-box;
7 | background: #6D84A2 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAArCAIAAAA2QHWOAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAEpJREFUeNpNjCEOgEAQA5v9/9eQaAQCd57L0WXTDSmimXZEse1HnNcIIINZYTPVv7Ac4/EWe7OTsC/ec+nDgcj/dpcH7EXt8up4AfRWcOjLIqWFAAAAAElFTkSuQmCC) repeat-x;
8 | border-bottom: 1px solid #2D3642;
9 | height: 45px;
10 | padding: 10px;
11 | position: relative;
12 | }
13 | body {
14 | -webkit-perspective: 800;
15 | -webkit-text-size-adjust: none;
16 | -webkit-transform-style: preserve-3d;
17 | -webkit-user-select: none;
18 | font-family: Helvetica;
19 | overflow-x: hidden;
20 | height: 100%;
21 | width: 100%;
22 | }
23 |
24 | body > section {
25 | background: #C5CCD3 url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAABCAIAAACdaSOZAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAABdJREFUeNpiPHrmCgMC/GNjYwNSAAEGADdNA3dnzPlQAAAAAElFTkSuQmCC);
26 | display: block;
27 | left: 0px;
28 | position: absolute;
29 | width: 100%;
30 | -webkit-transform: translate3d(100%,0%,0%);
31 | opacity: 0;
32 | -webkit-transition: all 0.25s ease-in-out;
33 | -webkit-transform-style: preserve-3d;
34 | z-index: -10;
35 | }
36 |
37 | .reverse {
38 | -webkit-transform: translate3d(-100%, 0%, 0%);
39 | opacity: 0;
40 | }
41 |
42 | .current {
43 | -webkit-transform: translate3d(0%,0%, 0%);
44 | opacity: 1;
45 | z-index: 1;
46 | }
47 | h1, h2 {
48 | color: #4C566C;
49 | font: normal normal bold 18px/normal Helvetica;
50 | margin: 10px 20px 6px;
51 | text-shadow: rgba(255, 255, 255, 0.19)
52 | }
53 | body.landscape .toolbar > h1 {
54 | margin-left: -125px;
55 | width: 250px;
56 | }
57 |
58 | .toolbar > h1 {
59 | color: white;
60 | font-size: 20px;
61 | font-weight: bold;
62 | height: 40px;
63 | left: 50%;
64 | line-height: 1em;
65 | margin: 1px 0px 0px -75px;
66 | overflow: hidden;
67 | position: absolute;
68 | text-align: center;
69 | text-overflow: ellipsis;
70 | text-shadow: rgba(0, 0, 0, 0.398438) 0px -1px 0px;
71 | top: 10px;
72 | white-space: nowrap;
73 | width: 150px;
74 | }
75 |
76 | ul {
77 | background: white;
78 | border: 1px solid #B4B4B4;
79 | border-bottom-left-radius: 8px 8px;
80 | border-bottom-right-radius: 8px 8px;
81 | border-top-left-radius: 8px 8px;
82 | border-top-right-radius: 8px 8px;
83 | color: black;
84 | font: normal normal bold 17px/normal Helvetica;
85 | margin: 15px 10px 17px;
86 | padding: 0px;
87 | }
88 |
89 | ul li {
90 | color: black;
91 | font-size: 14px;
92 | border-top: 1px solid #B4B4B4;
93 | color: #666;
94 | list-style-type: none;
95 | padding: 10px;
96 | }
97 |
98 | li:first-child, li:first-child a {
99 | border-top: 0px;
100 | border-top-left-radius: 8px 8px;
101 | border-top-right-radius: 8px 8px;
102 | }
103 |
104 | ul li.arrow {
105 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAUCAYAAAB4d5a9AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAKVJREFUeNpi/P//PwOtARMDHcDwsYQFRJSXl8P4dVC6CZvizs5O8i1BsqARid9Ei+BiQ2KDLKumhSU1QNyKxG+hlkXoEQ+yqAPNogpapK5KNIvaKbUIVxKeAsTvkPg5QCxETUukgfgAkqFPgdgBzVKKLIFZoIJmwR1qBRdNLEC2BJQpV9LCAmRL/gBxAtRwqlqAXqzcgRrOQE0LQIBxtNIiBQAEGAA7xCa2yF9zEgAAAABJRU5ErkJggg==);
106 | background-position: 100% 50%;
107 | background-repeat: no-repeat;
108 | }
109 |
110 | body > .current {
111 | display: block !important;
112 | }
113 |
114 | body.landscape > * {
115 | min-height: 320px;
116 | }
117 |
118 |
119 | ul li a, li.img a + a {
120 | color: black;
121 | display: block;
122 | margin: -10px;
123 | overflow: hidden;
124 | padding: 12px 10px;
125 | text-decoration: none;
126 | text-overflow: ellipsis;
127 | white-space: nowrap;
128 | }
129 |
130 |
131 | .button, .back, .cancel, .add {
132 | -webkit-border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAeCAIAAACqmwlGAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAatJREFUeNqVlMtKw0AUhqfJSRpTk5Za1FAvxS6sgrVeFrpQdOcT+IpuBVHcuVBQpCDYjeAdkSpavDTGNJkz43FpFZz8DISZ+b75J5tJbWwfMsZuby7rh/vN5v1H+539TMZxPa84v7g0WirTFISQR/t7jdOTcqVaGp+ze50uIfDbL62H3a3NqerMwtIqXF9dnF+dL6+t9/S6hmFqut4luHns80aKpcrxwY43PKK7+f6J2ZVcYTCl6ZIxKuwatEhbpmU72UKjfgCakXFz/TwW7L8QlgIbTNtBwVAgU0g644IGZoycqYVgQGRRLBQFggEpHJUFBI4iUhYIBhSSPooCwUB0zEWiBsERlRsECJSIUlEgOHmDH3TM909FgWBgqe8oCgRrLGGADlcvIDB5A2nfQ7kD6D5J/jn5lZILBoAUQgWVUgDoWi5r8zhUEXgU5nOOVp0sB+0W+f8WEDY9MabpYNUqQ29Pd1Hoi79eA1qkLQIIY5CGIOwUvYHBQr5xdvn4/BSGnS7BstIDhexUbVo3jNarD1Ky5xfftszF+WqPZcKvp5IjfoYRoYHv0/QLHvXjAb8xkEMAAAAASUVORK5CYII=) 0 5 0 5 stretch stretch;
133 | background: none;
134 | border-width: 0px 5px;
135 | color: white;
136 | font-family: inherit;
137 | font-size: 12px;
138 | font-weight: bold;
139 | height: 30px;
140 | line-height: 30px;
141 | margin: 0px;
142 | overflow: ;
143 | padding: 0px 3px;
144 | position: absolute;
145 | right: 6px;
146 | text-decoration: none;
147 | text-overflow: ellipsis;
148 | text-shadow: rgba(0, 0, 0, 0.496094) 0px -1px 0px;
149 | top: 8px;
150 | white-space: nowrap;
151 | width: auto;
152 | }
153 |
154 | .back {
155 | -webkit-border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACsAAAAeCAIAAAA6iHCJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAArFJREFUeNrF0mtPE2EQBeB5t9vSRqEUKiAFkasggmC5x3CRECHx8sH/qMHEoKkiMUQTNJIIaAjeiFGUcEsotN22u9vtOzMKogYL39rlyfkBk3NG3HsyC8dLJhOzM8+/fvkcjexAtghRXVN/dXCkvOIcAKhEDMdY+7ESejgeqKpv7x3J9/ogS5hoc33l0YPxju6+YFefSkRwlI311cnQRM/gbd+ZUpfb43CokD2nCv2lFbVvZib9JaUqMUEGTYtNPZ7oHLpZXBJQFIUYSCJkj3A4830lrd3Di2/nVcxYwTSMift3m4LXCovKCYGQIDe8vrJveNQfTE+Fys9f8pdVSSTILeFyF/z/B8uflnSLG+qakRlRQo45XO5DHejJxOtXLzsG7yA7ME2Qe0hw6A+mn4ZqLvY4XR6UCLZAxH8rfFx6Z6BaXVJlSQS7SKSDC+JabGFurrnvBvJ+NXZBYpX4oP9AQ5eietKSAMDuDt4vLkhHfr6/XCKCvZBIjezuLMzPN/XcIhIADPYiZPXFs8lAQ7dwOA8KsL8Dr7/CoDzSDDgJCT2ljI0OOzBGKMVJACGUXU2/3h/Uo5vMDCdBQSRLcn9nox7bEgLsDoDCDKYli4p89ZXFZjJ6Ah3wvlhcb2mqPa1a0jIBhJ1RiPl3wpH4QG+bTGwDo51DKPwHMccS5mBvSzyyCcB2rgB/k5aoqK72xgo9FrbxgsMSulkZOBvwu1O6BjnGhO48p8IZfj1EsPWCR+jSMiCX0pbh9xXsrZCZrW1toOcy6mFMpyA3mNnUwi2NtQoxZwaZwzF9bKhTpHaN+C7KNGQPobTMhBZe7Wyts1iox729RNyOJkeHOj4sf19Z3YgmsraI251X6ve2BYMEIqIlVebjd0rj2la0rrrySkuDU1UhSySiYVrbkbiZ2qv2J5+53J2yzo3SAAAAAElFTkSuQmCC) 0 8 0 14 stretch stretch;
156 | border-width: 0px 8px 0px 14px;
157 | left: 6px;
158 | max-width: 55px;
159 | padding: 0px;
160 | right: auto;
161 | }
162 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Zepto.js – a minimalist JavaScript library
2 |
3 | Zepto is a minimalist JavaScript library for modern browsers with a
4 | largely jQuery-compatible API. If you use jQuery, you already know how to use Zepto.
5 |
6 | See [zeptojs.com][] for an extended introduction, downloads
7 | and documentation.
8 |
9 | Zepto.js is licensed under the terms of the MIT License.
10 |
11 | ## Building
12 |
13 | [](http://travis-ci.org/madrobby/zepto)
14 |
15 | The official site offers a download of the default distribution of Zepto. This
16 | is good for starting out. However, at some point you might want to add some
17 | optional modules and remove some of the default ones you don't need, to keep the
18 | size at minimum. That's when you need to check out Zepto's source code and use
19 | the build commands.
20 |
21 | You will need Node.js installed on your system.
22 |
23 | ~~~ sh
24 | $ npm install
25 | $ npm run-script dist
26 | ~~~
27 |
28 | The resulting files are:
29 |
30 | 1. `dist/zepto.js`
31 | 2. `dist/zepto.min.js`
32 |
33 | If you install CoffeeScript globally, you can run `make` directly:
34 |
35 | ~~~ sh
36 | $ coffee make dist
37 | $ MODULES="zepto event data ..." ./make dist
38 | ~~~
39 |
40 | ## Zepto modules
41 |
42 | Zepto modules are individual files in the "src/" directory.
43 |
44 |
45 |
46 | module default description
47 |
48 |
49 |
50 | polyfill
51 | ✔
52 |
53 | Provides String.prototype.trim and Array.prototype.reduce methods
54 | if they are missing (required for iOS 3.x)
55 |
56 |
57 |
58 | zepto
59 | ✔
60 | Core module; contains most methods
61 |
62 |
63 | event
64 | ✔
65 | Event handling via on() & off()
66 |
67 |
68 | detect
69 | ✔
70 | Provides $.os and $.browser information
71 |
72 |
73 | fx
74 | ✔
75 | The animate() method
76 |
77 |
78 | fx_methods
79 |
80 |
81 | Animated show, hide, toggle,
82 | and fade*() methods.
83 |
84 |
85 |
86 | ajax
88 | ✔
89 | XMLHttpRequest and JSONP functionality
90 |
91 |
92 | form
94 | ✔
95 | Serialize & submit web forms
96 |
97 |
98 | assets
99 |
100 |
101 | Experimental support for cleaning up iOS memory after removing
102 | image elements from the DOM.
103 |
104 |
105 |
106 | data
108 |
109 |
110 | A full-blown data() method, capable of storing arbitrary
111 | objects in memory.
112 |
113 |
114 |
115 | selector
117 |
118 |
119 | Experimental jQuery
120 | CSS extensions support for functionality such as $('div:first') and
121 | el.is(':visible').
122 |
123 |
124 |
125 | touch
126 |
127 | Fires tap– and swipe–related events on touch devices
128 |
129 |
130 | gesture
131 |
132 | Fires pinch gesture events on touch devices
133 |
134 |
135 | stack
136 |
137 | Provides andSelf & end() chaining methods
138 |
139 |
140 |
141 |
142 | ## Contributing
143 |
144 | Get in touch:
145 |
146 | * IRC channel: [#zepto on freenode.net](irc://irc.freenode.net/zepto)
147 | * @[zeptojs](http://twitter.com/zeptojs)
148 |
149 | ### Write documentation
150 |
151 | Zepto docs are written in Markdown and live in the ["gh-pages" branch][docs].
152 | They are published on [zeptojs.com][].
153 |
154 | You can use GitHub's web interface to make quick changes to documentation for
155 | specific Zepto features
156 | ([example: ajaxSettings](https://github.com/madrobby/zepto/blob/gh-pages/ajax/_posts/1900-01-01-Z-ajaxSettings.md)).
157 | This will submit a pull request to us that we can review.
158 |
159 | ### Report a bug
160 |
161 | 1. Check if the bug is already fixed in the [master branch][master] since the
162 | last release.
163 | 2. Check [existing issues][issues]. Open a new one, including exact browser &
164 | platform information. For better formatting of your report, see
165 | [GitHub-flavored Markdown][mkd].
166 |
167 | ### Running tests
168 |
169 | You will need to install [PhantomJS][]. On OS X, that's easy:
170 |
171 | ~~~ sh
172 | $ brew install phantomjs
173 | ~~~
174 |
175 | To run the test suite, these are all equivalent:
176 |
177 | ~~~ sh
178 | $ npm test
179 | $ ./make test
180 | $ script/test
181 | ~~~
182 |
183 |
184 | [zeptojs.com]: http://zeptojs.com
185 | [master]: https://github.com/madrobby/zepto/commits/master
186 | [issues]: https://github.com/madrobby/zepto/issues
187 | [docs]: https://github.com/madrobby/zepto/tree/gh-pages#readme
188 | [mkd]: http://github.github.com/github-flavored-markdown/
189 | [evidence.js]: https://github.com/tobie/Evidence
190 | [phantomjs]: http://code.google.com/p/phantomjs/wiki/Installation
191 |
--------------------------------------------------------------------------------
/test/data.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto extended data() unit tests
8 |
9 |
10 |
11 |
12 |
13 |
14 | Zepto data() tests
15 |
16 | Running… see browser console for results
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/test/touch.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto touch unit tests
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Touch tests
17 |
18 | Running… see browser console for results
19 |
20 |
21 |
30 |
31 |
246 |
247 |
248 |
--------------------------------------------------------------------------------
/test/fx.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Zepto FX unit tests
8 |
9 |
10 |
11 |
12 |
13 |
49 |
50 |
51 | Zepto effects tests
52 |
53 | Running… see browser console for results
54 |
55 |
56 |
62 |
67 |
68 |
69 |
70 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/src/event.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | var $$ = $.zepto.qsa, handlers = {}, _zid = 1, specialEvents={},
7 | hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
8 |
9 | specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
10 |
11 | function zid(element) {
12 | return element._zid || (element._zid = _zid++)
13 | }
14 | function findHandlers(element, event, fn, selector) {
15 | event = parse(event)
16 | if (event.ns) var matcher = matcherFor(event.ns)
17 | return (handlers[zid(element)] || []).filter(function(handler) {
18 | return handler
19 | && (!event.e || handler.e == event.e)
20 | && (!event.ns || matcher.test(handler.ns))
21 | && (!fn || zid(handler.fn) === zid(fn))
22 | && (!selector || handler.sel == selector)
23 | })
24 | }
25 | function parse(event) {
26 | var parts = ('' + event).split('.')
27 | return {e: parts[0], ns: parts.slice(1).sort().join(' ')}
28 | }
29 | function matcherFor(ns) {
30 | return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
31 | }
32 |
33 | function eachEvent(events, fn, iterator){
34 | if ($.type(events) != "string") $.each(events, iterator)
35 | else events.split(/\s/).forEach(function(type){ iterator(type, fn) })
36 | }
37 |
38 | function eventCapture(handler, captureSetting) {
39 | return handler.del &&
40 | (handler.e == 'focus' || handler.e == 'blur') ||
41 | !!captureSetting
42 | }
43 |
44 | function realEvent(type) {
45 | return hover[type] || type
46 | }
47 |
48 | function add(element, events, fn, selector, getDelegate, capture){
49 | var id = zid(element), set = (handlers[id] || (handlers[id] = []))
50 | eachEvent(events, fn, function(event, fn){
51 | var handler = parse(event)
52 | handler.fn = fn
53 | handler.sel = selector
54 | // emulate mouseenter, mouseleave
55 | if (handler.e in hover) fn = function(e){
56 | var related = e.relatedTarget
57 | if (!related || (related !== this && !$.contains(this, related)))
58 | return handler.fn.apply(this, arguments)
59 | }
60 | handler.del = getDelegate && getDelegate(fn, event)
61 | var callback = handler.del || fn
62 | handler.proxy = function (e) {
63 | var result = callback.apply(element, [e].concat(e.data))
64 | if (result === false) e.preventDefault(), e.stopPropagation()
65 | return result
66 | }
67 | handler.i = set.length
68 | set.push(handler)
69 | element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
70 | })
71 | }
72 | function remove(element, events, fn, selector, capture){
73 | var id = zid(element)
74 | eachEvent(events || '', fn, function(event, fn){
75 | findHandlers(element, event, fn, selector).forEach(function(handler){
76 | delete handlers[id][handler.i]
77 | element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture))
78 | })
79 | })
80 | }
81 |
82 | $.event = { add: add, remove: remove }
83 |
84 | $.proxy = function(fn, context) {
85 | if ($.isFunction(fn)) {
86 | var proxyFn = function(){ return fn.apply(context, arguments) }
87 | proxyFn._zid = zid(fn)
88 | return proxyFn
89 | } else if (typeof context == 'string') {
90 | return $.proxy(fn[context], fn)
91 | } else {
92 | throw new TypeError("expected function")
93 | }
94 | }
95 |
96 | $.fn.bind = function(event, callback){
97 | return this.each(function(){
98 | add(this, event, callback)
99 | })
100 | }
101 | $.fn.unbind = function(event, callback){
102 | return this.each(function(){
103 | remove(this, event, callback)
104 | })
105 | }
106 | $.fn.one = function(event, callback){
107 | return this.each(function(i, element){
108 | add(this, event, callback, null, function(fn, type){
109 | return function(){
110 | var result = fn.apply(element, arguments)
111 | remove(element, type, fn)
112 | return result
113 | }
114 | })
115 | })
116 | }
117 |
118 | var returnTrue = function(){return true},
119 | returnFalse = function(){return false},
120 | ignoreProperties = /^([A-Z]|layer[XY]$)/,
121 | eventMethods = {
122 | preventDefault: 'isDefaultPrevented',
123 | stopImmediatePropagation: 'isImmediatePropagationStopped',
124 | stopPropagation: 'isPropagationStopped'
125 | }
126 | function createProxy(event) {
127 | var key, proxy = { originalEvent: event }
128 | for (key in event)
129 | if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key]
130 |
131 | $.each(eventMethods, function(name, predicate) {
132 | proxy[name] = function(){
133 | this[predicate] = returnTrue
134 | return event[name].apply(event, arguments)
135 | }
136 | proxy[predicate] = returnFalse
137 | })
138 | return proxy
139 | }
140 |
141 | // emulates the 'defaultPrevented' property for browsers that have none
142 | function fix(event) {
143 | if (!('defaultPrevented' in event)) {
144 | event.defaultPrevented = false
145 | var prevent = event.preventDefault
146 | event.preventDefault = function() {
147 | this.defaultPrevented = true
148 | prevent.call(this)
149 | }
150 | }
151 | }
152 |
153 | $.fn.delegate = function(selector, event, callback){
154 | return this.each(function(i, element){
155 | add(element, event, callback, selector, function(fn){
156 | return function(e){
157 | var evt, match = $(e.target).closest(selector, element).get(0)
158 | if (match) {
159 | evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element})
160 | return fn.apply(match, [evt].concat([].slice.call(arguments, 1)))
161 | }
162 | }
163 | })
164 | })
165 | }
166 | $.fn.undelegate = function(selector, event, callback){
167 | return this.each(function(){
168 | remove(this, event, callback, selector)
169 | })
170 | }
171 |
172 | $.fn.live = function(event, callback){
173 | $(document.body).delegate(this.selector, event, callback)
174 | return this
175 | }
176 | $.fn.die = function(event, callback){
177 | $(document.body).undelegate(this.selector, event, callback)
178 | return this
179 | }
180 |
181 | $.fn.on = function(event, selector, callback){
182 | return !selector || $.isFunction(selector) ?
183 | this.bind(event, selector || callback) : this.delegate(selector, event, callback)
184 | }
185 | $.fn.off = function(event, selector, callback){
186 | return !selector || $.isFunction(selector) ?
187 | this.unbind(event, selector || callback) : this.undelegate(selector, event, callback)
188 | }
189 |
190 | $.fn.trigger = function(event, data){
191 | if (typeof event == 'string' || $.isPlainObject(event)) event = $.Event(event)
192 | fix(event)
193 | event.data = data
194 | return this.each(function(){
195 | // items in the collection might not be DOM elements
196 | // (todo: possibly support events on plain old objects)
197 | if('dispatchEvent' in this) this.dispatchEvent(event)
198 | })
199 | }
200 |
201 | // triggers event handlers on current element just as if an event occurred,
202 | // doesn't trigger an actual event, doesn't bubble
203 | $.fn.triggerHandler = function(event, data){
204 | var e, result
205 | this.each(function(i, element){
206 | e = createProxy(typeof event == 'string' ? $.Event(event) : event)
207 | e.data = data
208 | e.target = element
209 | $.each(findHandlers(element, event.type || event), function(i, handler){
210 | result = handler.proxy(e)
211 | if (e.isImmediatePropagationStopped()) return false
212 | })
213 | })
214 | return result
215 | }
216 |
217 | // shortcut methods for `.bind(event, fn)` for each event type
218 | ;('focusin focusout load resize scroll unload click dblclick '+
219 | 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+
220 | 'change select keydown keypress keyup error').split(' ').forEach(function(event) {
221 | $.fn[event] = function(callback) {
222 | return callback ?
223 | this.bind(event, callback) :
224 | this.trigger(event)
225 | }
226 | })
227 |
228 | ;['focus', 'blur'].forEach(function(name) {
229 | $.fn[name] = function(callback) {
230 | if (callback) this.bind(name, callback)
231 | else this.each(function(){
232 | try { this[name]() }
233 | catch(e) {}
234 | })
235 | return this
236 | }
237 | })
238 |
239 | $.Event = function(type, props) {
240 | if (typeof type != 'string') props = type, type = props.type
241 | var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true
242 | if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
243 | event.initEvent(type, bubbles, true, null, null, null, null, null, null, null, null, null, null, null, null)
244 | event.isDefaultPrevented = function(){ return this.defaultPrevented }
245 | return event
246 | }
247 |
248 | })(Zepto)
249 |
--------------------------------------------------------------------------------
/src/ajax.js:
--------------------------------------------------------------------------------
1 | // Zepto.js
2 | // (c) 2010-2012 Thomas Fuchs
3 | // Zepto.js may be freely distributed under the MIT license.
4 |
5 | ;(function($){
6 | var jsonpID = 0,
7 | document = window.document,
8 | key,
9 | name,
10 | rscript = /
9 |
10 |
11 |
12 |
13 |
14 |
15 | Browser detection
16 |
17 | Running… see browser console for results
18 |
19 |
20 |
312 |
313 |