From 9b22c8df87b62402ab5c5d22c010b0291762eb58 Mon Sep 17 00:00:00 2001 From: Miller Medeiros Date: Fri, 24 Sep 2010 17:36:58 -0400 Subject: [PATCH] added `.bind` and `.unbind`, improved `.delegate`, added `swipe` plugin, added test page for events, fixed `classList` for the iOS (String.prototype.trim isn't supported); --- README.markdown | 32 +++- dev/build/build.number | 4 +- dev/build/build.properties | 2 +- dev/build/build.xml | 8 +- dev/src/classlist.js | 16 +- dev/src/core.js | 4 +- dev/src/event.js | 36 +++-- dev/src/extras/swipe.js | 71 +++++++++ dev/src/style.js | 7 +- dev/test/events.html | 244 +++++++++++++++++++++++++++++ dev/test/{zepto.html => unit.html} | 11 +- dist/js/extras/swipe.js | 71 +++++++++ dist/js/zepto.js | 67 +++++--- dist/js/zepto.min.js | 21 +-- 14 files changed, 535 insertions(+), 59 deletions(-) create mode 100644 dev/src/extras/swipe.js create mode 100644 dev/test/events.html rename dev/test/{zepto.html => unit.html} (95%) create mode 100644 dist/js/extras/swipe.js diff --git a/README.markdown b/README.markdown index 02cae3512..8584d1a41 100644 --- a/README.markdown +++ b/README.markdown @@ -40,7 +40,7 @@ The ultimate goal is to have a ~2k library that handles most basic dredge work f - `.delegate(selector, eventType, handler)` : Attach an Event listener to matched elements using the event delegation pattern. - `.hasClass(className)` : Check if any matched element has given class. - `.addClass(className)` : Add one or more classes (separated by spaces) into each matched element. - - `.removeClass(className)` : Removes one or more class names (separated by spaces) from mathched elements, removes all classes if `null`. + - `.removeClass(className)` : Removes one or more class names (separated by spaces) from matched elements, removes all classes if `null`. - `.toggleClass(className, switch)` : Add or remove one or more classes from each element in the set of matched elements. - `.add(elementsArray)` : Add a set of elements to the matched elements set. - `.map(callbackFn(i, element))` : Pass each element in the current matched set through a function, producing a new zepto object containing the return values. @@ -53,12 +53,30 @@ The ultimate goal is to have a ~2k library that handles most basic dredge work f - `$.extend(firstObj, secondObj)` : Mixin, copy properties from one object into another, will extend `zepto` by default if second parameter is omitted. - `$.map(array, callbackFn)` : Translate all items in an array or array-like object to another array of items. (similar to similar to `jQuery.map` and not to `Array.prototype.map`) -### Event Handlers ("live" events) ### +### Event Handlers ### -#### delegate #### +#### bind/unbind #### - $('body').delegate('div.touchable', 'touchstart', function(evt){ - alert("I'm touched!"); + - `.bind(eventType, eventHandler)` : Attach event listener onto each matched element. + - `.unbind(eventType, eventHandler)` : Remove event listener from each matched element, *(both parameters are required)*. + +##### example ##### + + var handler = function(evt){ + $(this).unbind('touchstart', handler); //remove listener after first call, so it will be called only once per matched element + alert("yay!"); + }; + + $('#my_div').bind('touchstart', handler); //add listener + + +#### delegate ("live" event) #### + +`.delegate(selector, eventType, eventHandler)` : Listen for events triggered by descendant nodes of matched elements - A.K.A "event delegation". + + //will trigger when any descendant element of "#my_div" that has the class ".touchable" is touched + $('#my_div').delegate('.touchable', 'touchstart', function(evt){ + alert("I'm touched!"); }); @@ -80,7 +98,9 @@ The ultimate goal is to have a ~2k library that handles most basic dredge work f ### Recommendations ### -Best used if you stick in the contents of zepto.min.js into a ` + + + + + + + \ No newline at end of file diff --git a/dev/test/zepto.html b/dev/test/unit.html similarity index 95% rename from dev/test/zepto.html rename to dev/test/unit.html index a639b5cda..b1407fb70 100644 --- a/dev/test/zepto.html +++ b/dev/test/unit.html @@ -260,7 +260,16 @@

Zepto unit tests

return (i % 2)? i : null; //convert nodes into numbers and remove few items }); t.assertEqual(mapped.get().join(','), compare.join(',')); - } + }/*, + + testText : function(t){ + $(document.body).append('
loremfoo
'); + t.assertEqual($('#test_text').text(), 'lorem ipsum dolor'); + $('#test_text').text('foo bar'); + t.assertEqual($('#test_text').text(), 'foo bar'); + t.assertEqual($('#test_text').get(0).innerHTML, 'foo bar'); + $('#test_text') + }*/ }); diff --git a/dist/js/extras/swipe.js b/dist/js/extras/swipe.js new file mode 100644 index 000000000..cb360a7e4 --- /dev/null +++ b/dist/js/extras/swipe.js @@ -0,0 +1,71 @@ + +/* -- zepto.js : swipe plugin ------------------- */ + +(function(zepto){ + + /** + * @param {string} direction Swipe direction ('left', 'right', 'up', 'down') + * @param {function({direction: string, changeX: number, changeY: number})} callback + * @param {{x: number, y: number}} threshold + */ + zepto.fn.swipe = function(direction, callback, threshold){ + + var thold = {x:30, y:30}, //default threshold + origin = {x:0, y:0}, + dest = {x:0, y:0}, + isVertical = (direction === 'up' || direction === 'down'); + + if(threshold) zepto.extend(thold, threshold); //overwrite default threshold + + function updateCords(cordsObj, evt){ + cordsObj.x = evt.targetTouches[0].pageX; + cordsObj.y = evt.targetTouches[0].pageY; + } + + function onTouchStart(evt){ + updateCords(origin, evt); + } + + function onTouchMove(evt){ + evt.preventDefault(); + updateCords(dest, evt); + } + + function onTouchEnd(evt){ + var changeX = origin.x - dest.x, + changeY = origin.y - dest.y, + distX = Math.abs(changeX), + distY = Math.abs(changeY), + evtInfo = { + changeX : changeX, + changeY : changeY, + direction : direction + }; + + if(!isVertical && distX >= thold.x && distY <= thold.y){ + if( (direction === 'left' && changeX > 0) || (direction === 'right' && changeX < 0) ){ + callback.call(evt.currentTarget, evtInfo); //assign `this` to element (used "currentTarget" instead of "target" because of event bubbling) + } + }else if(isVertical && distX <= thold.x && distY >= thold.y){ + if( (direction === 'up' && changeY > 0) || (direction === 'down' && changeY < 0) ){ + callback.call(evt.currentTarget, evtInfo); //assign `this` to element (used "currentTarget" instead of "target" because of event bubbling) + } + } + } + + this.bind('touchstart', onTouchStart); + this.bind('touchmove', onTouchMove); + this.bind('touchend', onTouchEnd); + //swipe doesn't require 'touchcancel' since 'touchend' won't be called then. + + return this; //chain + }; + + //create aliases "touchLeft", "touchRight", etc.. + 'left right up down'.split(' ').forEach(function(direction){ + zepto.fn['swipe'+ direction.substr(0,1).toUpperCase() + direction.substr(1)] = function(callback, threshold){ + return this.swipe(direction, callback, threshold); + }; + }); + +}(zepto)); \ No newline at end of file diff --git a/dist/js/zepto.js b/dist/js/zepto.js index 8092e7561..e68604466 100644 --- a/dist/js/zepto.js +++ b/dist/js/zepto.js @@ -1,8 +1,8 @@ /** - * @license zepto.js v0.1.3 + * @license zepto.js v0.1.4 * - original by Thomas Fuchs (http://github.com/madrobby/zepto), forked by Miller Medeiros (http://github.com/millermedeiros/zepto). * Released under the MIT license (http://www.opensource.org/licenses/mit-license.php) - * Build: 9 - Date: 09/23/2010 05:03 PM + * Build: 14 - Date: 09/24/2010 05:36 PM */ (function(window, document){ @@ -27,12 +27,12 @@ context = selector; matched = [selector]; selector = null; - }else if(selector instanceof zepto){ //zepto object + }else if(selector instanceof zepto){ //"clone" zepto object selector = selector.selector; context = selector.context; } - if(context instanceof zepto){ + if(context instanceof zepto){ //if finding descendant node(s) of all matched elements matched = []; context.each(function(el){ matched = matched.concat( zepto.makeArray(el.querySelectorAll(selector)) ); @@ -283,12 +283,12 @@ zepto.fn.extend({ /** * Set style of matched elements. - * @param {string} style CSS string. + * @param {string} css CSS string. * @return {zepto} */ - css : function(style){ + css : function(css){ return this.each(function(el){ - el.style.cssText += ';'+ style; + el.style.cssText += ';'+ css; }); }, @@ -300,6 +300,7 @@ zepto.fn.extend({ * @return {zepto} */ anim : function(transform, opacity, duration){ + //TODO: change the way anim works, since it's overwriting the "-webkit-transition:all" it's hard to change other CSS values later without animation. return this.css('-webkit-transition:all '+ (duration||0.5) +'s;'+'-webkit-transform:'+ transform +';opacity:'+ (opacity===0?0:opacity||1) ); } @@ -311,28 +312,44 @@ zepto.fn.extend({ zepto.fn.extend({ /** - * @param {string} selector - * @param {string} eventType + * @param {string} eventType Event type. + * @param {function(Event)} handler Event handler. + */ + bind : function(eventType, handler){ + return this.each(function(el){ + el.addEventListener(eventType, handler, false); + }); + }, + + /** + * @param {string} eventType Event type. + * @param {function(Event)} handler Event handler. + */ + unbind : function(eventType, handler){ + return this.each(function(el){ + el.removeEventListener(eventType, handler, false); + }); + }, + + /** + * @param {string} selector Selector + * @param {string} eventType Event type that it should listen to. (supports a single kind of event) * @param {function(this:HTMLElement, Event)} callback * @return {zepto} */ delegate : function(selector, eventType, callback){ - return this.each(function(elm){ - var - root = elm, - targets = this.find(selector).get(); - + var targets = this.find(selector).get(); + return this.each(function(el){ function delegateHandler(evt){ var node = evt.target; while(node && targets.indexOf(node)<0){ node = node.parentNode; } - if(node && node !== root){ + if(node && node !== el){ callback.call(node, evt); } } - - elm.addEventListener(eventType, delegateHandler, false); + el.addEventListener(eventType, delegateHandler, false); }); } @@ -423,7 +440,8 @@ zepto.extend({ //--- As of 2010/09/23 native HTML5 Element.classList is only supported by Firefox 3.6+ ---// - var regexSpaces = /\s+/g; + var regexSpaces = /\s+/g, + regexTrim = /^\s+|\s+$/g; /** * remove multiple spaces and trailing spaces @@ -431,7 +449,16 @@ zepto.extend({ * @return {string} */ function sanitize(className){ - return className.replace(regexSpaces, ' ').trim(); + return trim( className.replace(regexSpaces, ' ') ); + } + + /** + * Remove white spaces from begining and end of string + * - as of 2010/09/24 Safari Mobile doesn't support `String.prototype.trim` + * @param {string} str + */ + function trim(str){ + return str.replace(regexTrim, ''); } /** @@ -514,7 +541,7 @@ zepto.extend({ if(zepto.isDef(isAdd)){ (isAdd)? this.addClass(className) : this.removeClass(className); }else{ - var classes = className.trim().split(' '), + var classes = trim(className).split(' '), regex, elements = this.get(); //for scope and performance classes.forEach(function(c){ diff --git a/dist/js/zepto.min.js b/dist/js/zepto.min.js index a409718dd..1e1852c40 100644 --- a/dist/js/zepto.min.js +++ b/dist/js/zepto.min.js @@ -1,14 +1,15 @@ /* - zepto.js v0.1.3 + zepto.js v0.1.4 - original by Thomas Fuchs (http://github.com/madrobby/zepto), forked by Miller Medeiros (http://github.com/millermedeiros/zepto). Released under the MIT license (http://www.opensource.org/licenses/mit-license.php) - Build: 9 - Date: 09/23/2010 05:03 PM + Build: 14 - Date: 09/24/2010 05:36 PM */ -(function(d,g){var c=function(b,e){if(this instanceof c){e=e||g;var a;if(b){if(b.nodeType){e=b;a=[b];b=null}else if(b instanceof c){b=b.selector;e=b.context}if(e instanceof c){a=[];e.each(function(f){a=a.concat(c.makeArray(f.querySelectorAll(b)))});a=c.unique(a)}else a||(a=c.makeArray(e.querySelectorAll(b)))}this.selector=b;this.context=e;this.add(a)}else return new c(b,e)};d.zepto=d.$=c;c.fn=c.prototype={each:function(b){this.get().forEach(function(e){b.call(this,e)},this);return this},find:function(b){return c(b, -this)},get:function(b){return c.isDef(b)?this[parseInt(b,10)]:c.makeArray(this)},eq:function(b){return c(this.get(b))},add:function(b){Array.prototype.push.apply(this,b);return this},map:function(b){return c().add(c.map(this,function(e,a){return b.call(e,a,e)}))}};c.extend=c.fn.extend=function(b,e){var a;if(!e){e=b;b=this}for(a in e)if(e.hasOwnProperty(a))b[a]=e[a];return b};c.extend({unique:function(b){return b.filter(function(e,a,f){return f.indexOf(e)===a})},makeArray:function(b){return Array.prototype.slice.call(b)}, -isDef:function(b){return typeof b!=="undefined"},map:function(b,e){var a=[],f,h,i=b.length;for(h=0;h