source: extensions/iPiwigo/www/extensions/jqt.scroll.js @ 9188

Last change on this file since 9188 was 9188, checked in by Polly, 13 years ago

Adding the Phonegap www folder needed to compile.

  • Property svn:executable set to *
File size: 43.1 KB
Line 
1/*!*
2 *
3 * Add support for scrolling vertically and horizontally using jQTouch in Webkit Mobile
4 * Plus support for slides
5 *
6 * Copyright (c) 2010 Sam Shull <http://samshull.blogspot.com/>
7 * Released under MIT license
8 *
9 * Based on the work of Matteo Spinelli, http://cubiq.org/
10 * Released under MIT license
11 * http://cubiq.org/dropbox/mit-license.txt
12 *
13 * Find more about the scrolling function at
14 * http://cubiq.org/scrolling-div-for-mobile-webkit-turns-3/16
15 *
16 *
17 */
18   
19(function($, window, document, Number, Math, undefined) {
20    //we need this in the algorithm
21    if (!"WebKitCSSMatrix" in this) {
22        return null;
23    }
24   
25        /**
26         *    Determine 3d translate support
27         *
28         *    @var Boolean
29         */
30    var supports3d = ('m11' in new WebKitCSSMatrix()),
31       
32        /**
33         *    Single Object for base options
34         *    that is used to extend the defaults
35         *
36         *    @var Object
37         */
38        base = {
39           
40            /**
41             *    A function for converting attributes into options @see attributes
42             *
43             *    @var Function
44             */
45            attributesToOptions: attributesToOptions,
46           
47            /**
48             *    A dictionary of property/accessor pairs
49             *    where the name of the property coincides with the name
50             *    of an option, and the value is either a string representing the
51             *    name of the attribute where the value will be stored, or
52             *    a function that accepts two arguments, the first of the type DOMElement
53             *    and the second is a string indicating the desired direction which then
54             *    returns the desired value of the property on that object
55             *
56             *    @var Object
57             */
58            attributes: {
59                //use an attribute to set the defaultDuration option
60                defaultDuration: "slidespeed",
61                //use an attribute to determine whether or not you want the default touch event cancelled
62                preventDefault: function(e,d){return $(e).attr("preventdefault") === "false" ? false : !!defaults[d].preventDefault;},
63                //use bounce?
64                bounce: function(e,d){return e.attr("bounce") === "false" ? false : defaults[d].bounce},
65                //use a scrollbar?
66                scrollBar: function(e,d){return e.hasClass("with-scrollbar")},
67                //use slides?
68                useSlides: function(e,d){return $(e).find(defaults[d].slides.selector).length > 0;}
69            },
70           
71            /**
72             *    Selectors to ignore on touch start
73             *
74             *    @var String
75             */
76            ignore: "SELECT,TEXTAREA,BUTTON,INPUT",
77           
78            /**
79             *    Should the container slide to the next container?
80             *
81             *    @var Boolean
82             */
83            useSlides: false,
84           
85            /**
86             *    Properties for handling slides
87             *
88             *    @var Object
89             */
90            slides: {
91           
92                /**
93                 *    jQuery selector for the slide containers
94                 *
95                 *    @var String
96                 */
97                selector: ".slide-container",
98           
99                /**
100                 *    Identify the current slide container
101                 *
102                 *    @var String
103                 */
104                currentClass: "jqt-slide-current",
105           
106                /**
107                 *    Portion of the slide that must be moved
108                 *    before triggerring move to next slide
109                 *
110                 *    @var Number
111                 */
112                portion: 3,
113           
114                /**
115                 *    Amount of easing to use on slide
116                 *
117                 *    @var Number
118                 */
119                easing: 2,
120           
121                /**
122                 *    The function to determine position of next slide
123                 *
124                 *    @var Function
125                 */
126                callback: slideTo
127            },
128           
129            /**
130             *    The number of fingers required to activate the slide motion
131             *
132             *    @var Number
133             */
134            numberOfTouches: 1,
135           
136            /**
137             *    Amount of the parent container to use for a bounce
138             *
139             *    @var Number
140             */
141            divider: 6,
142           
143            /**
144             *    List of touch enevts to listen to. (Hopefully add support for non-touch one day)
145             *
146             *    @var Array<String>
147             */
148            touchEventList: ["touchend","touchmove","touchcancel"],
149           
150            /**
151             *    The return speed of a bounce
152             *
153             *    @var Number
154             */
155            bounceSpeed: 300,
156           
157            /**
158             *    The duration of a slide
159             *
160             *    @var Number
161             */
162            defaultDuration: 500,
163           
164            /**
165             *    Initial container offset in px
166             *
167             *    @var Number
168             */
169            defaultOffset: 0,
170           
171            /**
172             *    should the default be prevented on the events?
173             *
174             *    @var Boolean
175             */
176            preventDefault: true,
177           
178            /**
179             *    Limit the acceleration velocity
180             *
181             *    @var Number
182             */
183            maxScrollTime: 1000,
184           
185            /**
186             *    Friction to apply to the acceleration
187             *
188             *    @var Number
189             */
190            friction: 3,
191           
192            /**
193             *    Should the window.scrollTo(0,0) be called each time a touch event starts?
194             *
195             *    @var Boolean
196             */
197            scrollTopOnTouchstart: true,
198           
199            /**
200             *    Use bounce?
201             *
202             *    @var Boolean
203             */
204            bounce: true,
205           
206            /**
207             *    Show a scrollbar?
208             *
209             *    @var Boolean
210             */
211            scrollBar: true,
212           
213            /**
214             *    Object reference to Scrollbar object
215             *
216             *    @var ScrollBar
217             */
218            scrollBarObject: null,
219           
220            /**
221             *    Event handlers
222             *
223             *    @var Object
224             */
225            events: {
226                //
227                scrollTo: scrollTo,
228                //
229                reset: reset,
230                //
231                touchstart: touchStart,
232                //
233                touchmove: touchMove,
234                //
235                touchend: touchEnd,
236                //
237                touchcancel: touchEnd,
238                //
239                webkitTransitionEnd: transitionEnd
240            },
241           
242            /**
243             *    Function for actually performing a change to the position of
244             *    the slide container
245             *
246             *    @var Function
247             */
248            setPosition: setPosition,
249           
250            /**
251             *    Calculate the momentum of a touch event
252             *
253             *    @var Function
254             */
255            momentum: momentum
256        },
257       
258        /**
259         *
260         *
261         *    @var Object
262         */
263        defaults = {
264            /**
265             *    Vertical default settings
266             *
267             *    @var Object
268             */
269            vertical: $.extend({}, base, {
270           
271                /**
272                 *    direction of the scroll, for internal use,
273                 *    don't change this
274                 *
275                 *    @var String
276                 */
277                direction: "vertical",
278           
279                /**
280                 *    The jQuery.fn function name to find
281                 *    the inner dimension of an element
282                 *
283                 *    @var String
284                 */
285                dimension: "height",
286           
287                /**
288                 *    The jQuery.fn function name to find
289                 *    the outer dimension of an element
290                 *
291                 *    @var String
292                 */
293                outerDimension: "outerHeight",
294           
295                /**
296                 *    The property of a WebKitCSSMatrix Object initialized
297                 *    with the transform property of the given element
298                 *    that should be used to determine position
299                 *
300                 *    @var String
301                 */
302                matrixProperty: "m42",
303           
304                /**
305                 *    CSS/jQuery Selector for jQTouch
306                 *
307                 *    @var String
308                 */
309                selector: ".vertical-scroll > div",
310           
311                /**
312                 *    The property on the touch property of the event
313                 *    object for calculating movement
314                 *
315                 *    @var String
316                 */
317                eventProperty: "pageY",
318               
319                /**
320                 *    The base transform declaration
321                 *
322                 *    @var String
323                 */
324                tranform: supports3d ? "translate3d(0,{0}px,0)" : "translate(0,{0}px)",
325               
326                /**
327                 *   
328                 *
329                 *    @var String
330                 */
331                slideProperty: "offsetTop"
332            }),
333           
334            /**
335             *    Horizontal default settings
336             *
337             *    @var Object
338             */
339            horizontal: $.extend({}, base, {
340           
341                /**
342                 *    direction of the scroll, for internal use,
343                 *    don't change this
344                 *
345                 *    @var String
346                 */
347                direction: "horizontal",
348           
349                /**
350                 *    The jQuery.fn function name to find
351                 *    the inner dimension of an element
352                 *
353                 *    @var String
354                 */
355                dimension: "width",
356           
357                /**
358                 *    The jQuery.fn function name to find
359                 *    the outer dimension of an element
360                 *
361                 *    @var String
362                 */
363                outerDimension: "outerWidth",
364           
365                /**
366                 *    The property of a WebKitCSSMatrix Object initialized
367                 *    with the transform property of the given element
368                 *    that should be used to determine position
369                 *
370                 *    @var String
371                 */
372                matrixProperty: "m41",
373           
374                /**
375                 *    CSS/jQuery Selector for jQTouch
376                 *
377                 *    @var String
378                 */
379                selector: ".horizontal-scroll > table",
380           
381                /**
382                 *    The property on the touch property of the event
383                 *    object for calculating movement
384                 *
385                 *    @var String
386                 */
387                eventProperty: "pageX",
388               
389                /**
390                 *    The base transform declaration
391                 *
392                 *    @var String
393                 */
394                tranform: supports3d ? "translate3d({0}px,0,0)" : "translate({0}px,0)",
395               
396                /**
397                 *    slideHandler
398                 *
399                 *    @var String
400                 */
401                slideProperty: "offsetLeft"
402            })
403        },
404           
405        /**
406         *    Dynamically determine the window height minus twice the toolbar height
407         *    for the CSS rule(s) that require specified heights
408         *
409         *    @var Function
410         */
411        bottomToolbar = function(vars){return (window.innerHeight - (vars.toolbarHeight * 2)) + "px !important"},
412           
413        /**
414         *    Dynamically determine the window height minus the toolbar height
415         *    for the CSS rule(s) that require specified heights
416         *
417         *    @var Function
418         */
419        height = function(vars){return (window.innerHeight - vars.toolbarHeight) + "px"},
420           
421        /**
422         *    Dynamically determine the window width for the CSS rule(s) that require specified widths
423         *
424         *    @var Function
425         */
426        width = function (){return window.innerWidth + "px";},
427           
428        /**
429         *
430         *
431         *    @var Object
432         */
433        cssRules = {
434            /**
435             *
436             *
437             *    @var Object
438             */
439            variables : {
440                toolbarHeight: 46
441            },
442           
443            /**
444             *    Base CSS rules, calculated on page load regardless of orientation
445             *
446             *    @var Object
447             */
448            defaults: {
449                //the parent container
450                ".vertical-scroll": {
451                    position: "relative",
452                    "z-index": 1,
453                    overflow: "hidden",
454                    "margin-bottom": "44px",
455                    height: height
456                },
457                //the parent container with a toolbar
458                ".vertical-scroll.use-bottom-toolbar": {
459                    height: bottomToolbar
460                },
461                //the actual container being scrolled
462                ".vertical-scroll > div": {
463                    margin: "0 auto",
464                    "padding-bottom":"15px",
465                    "-webkit-transition-property": "-webkit-transform",
466                    "-webkit-transition-timing-function": "cubic-bezier(0,0,.25,1)",
467                    //overridden on element
468                    "-webkit-transform": "translate3d(0,0,0)",
469                    "-webkit-transition-duration": "0s",
470                },
471                //fullscreen rule
472                ".vertical-scroll.use-bottom-toolbar": {
473                    "margin-bottom": "0px"
474                },
475                //fullscreen rule
476                ".vertical-scroll.use-bottom-toolbar > div": {
477                    "padding-bottom":"0px"
478                },
479                //scrollbar rule
480                ".scrollbar": {
481                    "-webkit-transition-timing-function": "cubic-bezier(0,0,.25,1)",
482                    "-webkit-transform": "translate3d(0,0,0)",
483                    "-webkit-transition-property": "-webkit-transform,opacity",
484                    "-webkit-transition-duration": "0,0,0,1s",
485                    "-webkit-border-radius": "2px",
486                    "pointer-events": "none",
487                    opacity: 0,
488                    background:"rgba(0,0,0,.5)",
489                    //"-webkit-border-image": "-webkit-gradient(radial, 50% 50%, 2, 50% 50%, 4, from(rgba(0,0,0,.5)), to(rgba(0,0,0,.5))) 2",
490                    //"-webkit-box-shadow": "0 0 3px rgba(255,255,255,.5)",
491                    "-webkit-box-shadow": "0 0 2px rgba(255,255,255,.5)",
492                    position: "absolute",
493                    "z-index": 10,
494                    width: "5px",
495                    height: "5px"
496                },
497                //scrollbar rule
498                ".scrollbar.vertical": {
499                    top: "1px",
500                    right: "1px"
501                },
502                //scrollbar horizontal
503                ".scrollbar.horizontal": {
504                    bottom: "1px",
505                    left: "1px"
506                },
507                //parent container
508                ".horizontal-scroll": {
509                    width: width,
510                    height: "100%",
511                    overflow: "hidden",
512                    padding: "0px",
513                    position: "relative",
514                    //not actually required
515                    height: height,
516                    "line-height":height
517                },
518                //actual element being scrolled
519                ".horizontal-scroll > table": {
520                    height: "100%",
521                    "-webkit-transition-property": "-webkit-transform",
522                    "-webkit-transition-timing-function": "cubic-bezier(0,0,.25,1)",
523                    //overridden on element
524                    "-webkit-transform": "translate3d(0,0,0)",
525                    "-webkit-transition-duration": "0s",
526                }
527            },
528           
529            /**
530             *    Only calculated if in portrait mode
531             *
532             *    @var Object
533             */
534            portrait: {
535                ".portrait .vertical-scroll": {
536                    position: "relative",
537                    "z-index": 1,
538                    overflow: "hidden",
539                    height: height,       
540                },
541                ".portrait .vertical-scroll.use-bottom-toolbar,.portrait .horizontal-scroll.use-bottom-toolbar": {
542                    height: bottomToolbar
543                },
544                ".portrait .horizontal-scroll": {
545                    width: width
546                },
547                ".portrait .slide-container": {
548                    height: height,
549                    width: width
550                }
551            },
552           
553            /**
554             *    Only calculated if in landscape mode
555             *
556             *    @var Object
557             */
558            landscape: {
559                ".landscape .vertical-scroll": {
560                    position: "relative",
561                    "z-index": 1,
562                    overflow: "hidden",
563                    height: height,
564                },
565                ".landscape .vertical-scroll.use-bottom-toolbar,.landscape .horizontal-scroll.use-bottom-toolbar": {
566                    height: bottomToolbar
567                },
568                ".landscape .horizontal-scroll": {
569                    width: width
570                },
571                ".landscape .slide-container": {
572                    height: height,
573                    width: width
574                }
575            }
576        };
577   
578    /*
579     *    jQTouch extension
580     *   
581     */
582    if ($.jQTouch) {
583       
584        $.jQTouch.addExtension(function (jQT) {
585            var d = defaults;
586           
587            function binder (e, info) {
588                var v = d.vertical, h = d.horizontal,
589                    vertical = info.page.find(v.selector),
590                    horizontal = info.page.find(h.selector);
591               
592                vertical.verticallyScroll(v.attributesToOptions(vertical, "vertical", v.attributes));
593                horizontal.horizontallyScroll(h.attributesToOptions(horizontal, "horizontal", h.attributes));
594            }
595           
596            $(document.body).bind("pageInserted", binder);
597           
598            $(function() {
599                var v = d.vertical, 
600                    h = d.horizontal;
601                   
602                $(v.selector)
603                    .each(function() {
604                        $(this).verticallyScroll(v.attributesToOptions($(this), "vertical", v.attributes));
605                    });
606                   
607                $(h.selector)
608                    .each(function() {
609                        $(this).horizontallyScroll(h.attributesToOptions($(this), "horizontal", h.attributes));
610                    });
611            });
612           
613            return {};
614        });
615    }
616   
617    //$(window).bind("unload", window_unload);
618   
619    /**
620     *    Handler for creating options out of attributes on the scroll container
621     *
622     *    @param DOMElement element
623     *    @param String direction - "vertical" or "horizontal"
624     *    @param Object attributes - @see base.attributes
625     *    @return Object
626     */
627    function attributesToOptions (element, direction, attributes) {
628        var options = {};
629       
630        $.each(attributes, function(name, value) {
631            if ($.isFunction(value)) {
632                options[name] = value(element, direction);
633               
634            } else if (element.attr(value) != undefined) {
635                options[name] = element.attr(value);
636            }
637        });
638       
639        return options;
640    }
641   
642    /*
643     *    jQuery extensions
644     *
645     */
646   
647    /**
648     *    Attach vertical inertia scrolling to one or more objects
649     *
650     *    @param Object options - optional
651     *    @return jQuery
652     */
653    $.fn.verticallyScroll = function (options) {
654        return this.inertiaScroll("vertical", options);
655    };
656   
657    /**
658     *    Attach horizontal inertia scrolling to one or more objects
659     *
660     *    @param Object options - optional
661     *    @return jQuery
662     */
663    $.fn.horizontallyScroll = function (options) {
664        return this.inertiaScroll("horizontal", options);
665    };
666   
667    /**
668     *    Attach inertia scrolling to one or more objects
669     *
670     *    @param Object options - optional
671     *    @return jQuery
672     */
673    $.fn.inertiaScroll = function (direction, options) {
674        options = $.extend(true, {}, defaults[direction], options || {});
675       
676        return this.each(function () {
677            inertiaScroll(this, options);
678        });
679    };
680   
681    /**
682     *    Static jQUery property
683     *
684     *
685     *    @var Object
686     */
687    $.inertiaScroll = {
688   
689        /**
690         *    Set and/or retrieve the inertia scroll defaults
691         *
692         *    @param Object options - @see defaults - optional
693         *    @return Object
694         */
695        defaults: function (options) {
696            if (options !== undefined) {
697                defaults = $.extend(true, defaults, options);
698            }
699           
700            return $.extend({}, defaults);
701        },
702       
703        /**
704         *    Set and/or retrieve the inertia scroll default CSS
705         *
706         *    @param Object options - @see cssRules - optional
707         *    @return Object
708         */
709        defaultCSS: function (options) {
710            if (options !== undefined) {
711                cssRules = $.extend(true, cssRules, options);
712            }
713           
714            return $.extend({}, cssRules);
715        }
716    };
717
718    /**
719     *    Initialize the component, bind event listeners, updates CSS, etc...
720     *
721     *    @param DOMElement element
722     *    @param Object options - @see defaults
723     *    @return null
724     */
725    function inertiaScroll (element, options) {
726        var $element = $(element).data("jqt-scroll-options", options)
727                            .css("webkitTransform", format(options.tranform, options.defaultOffset)),
728            transform = $element.css("webkitTransform"),
729            matrix = transform ? new WebKitCSSMatrix(transform) : {m41:0};
730       
731        $.each(options.events, function (name, func) {
732            //these events get attatch
733            //if (!name.match(/^touchend|touchcancel|touchmove/)) {
734                element.addEventListener(name, func, false);
735            //}
736        });
737       
738        //additional bindings for jquery
739        $element.bind("reset", options.events.reset)
740                .bind("scrollTo", options.events.scrollTo);
741       
742        //store for later use
743        options.currentPosition = matrix[options.matrixProperty];
744        options.parentWidth = $element.parent()[options.dimension]();
745       
746        if (options.scrollBar && options.scrollBar === true && !options.scrollBarObject) {
747            options.scrollBarObject = $.isFunction(options.scrollBar) ? 
748                options.scrollBar($element.parent(), options.direction) :
749                Scrollbar($element.parent(), options.direction);
750        }
751       
752        return null;
753    }
754
755    /**
756     *    The default touchstart event handler function,
757     *    initializes the data for later use by the touchmove/end event handlers
758     *
759     *    @context scroll container
760     *    @param Event event
761     *    @return Boolean
762     */
763    function touchStart (event) {
764        var $this = $(this),
765            options = $this.data("jqt-scroll-options"),
766            location = event.touches[0][options.eventProperty],
767            matrix, mp,
768            dimension = $this[options.outerDimension](),
769            parent = $this.parent()[options.dimension](),
770            //maxScroll
771            endPoint = -(dimension - parent),
772            //a distance to stop inertia from hitting
773            quarter = parent / options.divider;
774           
775        //ignore some stuff
776        if (!!options.ignore && $(event.target).is(options.ignore) || event.targetTouches.length !== options.numberOfTouches) { 
777            return null;
778        }
779       
780        options.parentDimension = parent;
781       
782        //sometimes this would be a bad idea
783        if (options.scrollTopOnTouchstart) {
784            window.scrollTo(0,0);
785        }
786       
787        //figure out the base position
788        matrix = new WebKitCSSMatrix($this.css("webkitTransform"));
789        mp = matrix[options.matrixProperty];
790       
791        //store data for later
792        $this.data("jqt-scroll-current-event", {
793            startLocation: location,
794            currentLocation: location,
795            startPosition: mp,
796            lastPosition: mp,
797            currentPosition: mp,
798            startTime: event.timeStamp,
799            moved: false,
800            lastMoveTime: event.timeStamp,
801            parentDimension: parent,
802            endPoint: endPoint,
803            minScroll: !options.bounce ? 0 : quarter,
804            maxScroll: !options.bounce ? endPoint : endPoint - quarter,
805            end: false
806        });
807       
808        if (options.scrollBarObject) {
809            options.scrollBarObject.init(parent, dimension);
810        }
811       
812        options.setPosition($this, options, mp, 0);
813       
814        if (options.preventDefault) {
815            event.preventDefault();
816            return false;
817           
818        } else {
819            return true;
820        }
821    }
822
823    /**
824     *    The default touchmove event handler, performs
825     *    immediate changes to the position of the element
826     *
827     *    @context scroll container
828     *    @param Event event
829     *    @return Boolean
830     */
831    function touchMove (event) {
832        var $this = $(this),
833            options = $this.data("jqt-scroll-options"),
834            data = $this.data("jqt-scroll-current-event"),
835            lastMoveTime = data.lastMoveTime,
836            position = event.touches[0][options.eventProperty],
837            distance = data.startLocation - position,
838            point = data.startPosition - distance,
839            duration = 0;
840       
841        //apply friction if past scroll points
842        if (point > 5) {
843            point = (point - 5) / options.friction;
844           
845        } else if (point < data.endPoint) {
846            point = data.endPoint - ((data.endPoint - point) / options.friction);
847        }
848       
849        data.currentPosition = data.lastPosition = Math.floor(point);
850        data.moved = true;
851        data.lastMoveTime = event.timeStamp;
852        data.currentLocation = position;
853       
854        if ((data.lastMoveTime - lastMoveTime) > options.maxScrollTime) {
855            data.startTime = data.lastMoveTime;
856        }
857       
858        if (options.scrollBarObject && !options.scrollBarObject.visible) {
859            options.scrollBarObject.show();
860        }
861       
862        options.setPosition($this, options, data.currentPosition, duration);
863       
864        if (options.preventDefault) {
865            event.preventDefault();
866            return false;
867           
868        } else {
869            return true;
870        }
871    }
872
873    /**
874     *    The default touchend event handler, calculates
875     *    necessary changes as a result of an event
876     *
877     *    @context scroll container
878     *    @param Event event
879     *    @return Boolean
880     */
881    function touchEnd (event) {
882        var $this = $(this),
883            options = $this.data("jqt-scroll-options"),
884            data = $this.data("jqt-scroll-current-event"),
885            theTarget, theEvent;
886       
887        if (!data.moved) {
888            if (options.scrollBarObject) {
889                options.scrollBarObject.hide();
890            }
891           
892            theTarget  = event.target;
893           
894            if(theTarget.nodeType == 3) {
895                theTarget = theTarget.parentNode;
896            }
897           
898            theEvent = document.createEvent("MouseEvents");
899            theEvent.initEvent("click", true, true);
900            theTarget.dispatchEvent(theEvent);
901           
902            if (options.preventDefault) {
903                event.preventDefault();
904                return false;
905            }
906        }
907       
908        if (options.useSlides && $.isFunction(options.slides.callback)) {
909            options.slides.callback($this, options, data, event);
910           
911        } else {
912            options.momentum($this, options, data, event);
913        }
914       
915        options.setPosition($this, options, data.currentPosition, data.duration);
916       
917        if (options.preventDefault) {
918            event.preventDefault();
919            return false;
920           
921        } else {
922            return true;
923        }
924    }
925   
926    /**
927     *    The default transitionEnd event handler, ensures that
928     *    container has not scrolled past its possible dimensions
929     *    and returns to those dimensions where appropriate
930     *
931     *    @context scroll container
932     *    @param Event event
933     *    @return null
934     */
935    function transitionEnd (event) {
936       
937        var $this = $(this),
938            options = $this.data("jqt-scroll-options"),
939            data = $this.data("jqt-scroll-current-event");
940       
941        if (data && !data.end) {
942            if (data.currentPosition > 0) {
943                data.currentPosition = 0;
944                options.setPosition($this, options, 0, options.bounceSpeed);
945               
946            } else if (data.currentPosition < data.endPoint) {
947                data.currentPosition = data.endPoint;
948                options.setPosition($this, options, data.endPoint, options.bounceSpeed);
949               
950            } else if (options.scrollBarObject) {
951                options.scrollBarObject.hide();
952            }
953            data.end = true;
954        } else if (options.scrollBarObject) {
955            options.scrollBarObject.hide();
956        }
957       
958        return null;
959    }
960
961    /**
962     *    Calculate the momentum of a touch event
963     *
964     *    @param jQuery object
965     *    @param Object options
966     *    @param Object data
967     *    @param Event event
968     *    @return null
969     */
970    function momentum (object, options, data, event) {
971        var m = Math,
972            duration = m.min(options.maxScrollTime, data.lastMoveTime - data.startTime),
973            distance = data.startPosition - data.currentPosition,
974            velocity = m.abs(distance) / duration,
975            acceleration = duration * velocity * options.friction,
976            momentum = m.round(distance * velocity),
977            position = m.round(data.currentPosition - momentum);
978       
979        if (data.currentPosition > 0) {
980            position = 0;
981        } else if (data.currentPosition < data.endPoint) {
982            position = data.endPoint;
983        } else if (position > data.minScroll) {
984            acceleration = acceleration * m.abs(data.minScroll / position);
985            position = data.minScroll;
986        } else if (position < data.maxScroll) {
987            acceleration = acceleration * m.abs(data.maxScroll / position);
988            position = data.maxScroll;
989        }
990       
991        data.momentum = m.abs(momentum);
992        data.currentPosition = position;
993        data.duration = acceleration;
994       
995        return null;
996    }
997
998    /**
999     *    Calculate the position of the slide which should be showing after a touch event ends
1000     *
1001     *    @param jQuery container
1002     *    @param Object options
1003     *    @param Object data
1004     *    @param Event event
1005     *    @return null
1006     */
1007    function slideTo (container, options, data, event) {
1008        var slides = container.find(options.slides.selector),
1009            current = slides.filter("."+options.slides.currentClass).eq(0),
1010            index,
1011            distance = data.startPosition - data.currentPosition,
1012            difference = current[options.dimension]() / options.slides.portion,
1013            duration;
1014       
1015        if (!current.length) {
1016            current = slides.eq(0);
1017        }
1018       
1019        index = slides.index(current[0]);
1020        slides.removeClass(options.slides.currentClass);
1021       
1022        if (data.currentPosition > 0) {
1023            position = 0;
1024            slides.eq(0).addClass(options.slides.currentClass);
1025        } else if (data.currentPosition < data.endPoint) {
1026            position = data.endPoint;
1027            slides.eq(slides.length-1).addClass(options.slides.currentClass);
1028        } else if (distance < -difference) {
1029            position = -slides.eq(index > 0 ? index - 1 : 0)
1030                            .addClass(options.slides.currentClass).parent().attr(options.slideProperty);
1031        } else if (distance > difference) {
1032            position = -slides.eq(index < slides.length-1 ? index + 1 : slides.length-1)
1033                            .addClass(options.slides.currentClass).parent().attr(options.slideProperty);
1034        } else {
1035            position = -current.addClass(options.slides.currentClass).parent().attr(options.slideProperty);
1036        }
1037       
1038        duration = Math.abs(data.currentPosition - position) * options.slides.easing;
1039       
1040        data.momentum = duration;
1041        data.currentPosition = position;
1042        data.duration = duration;
1043       
1044        return null;
1045    }
1046
1047    /**
1048     *    Return the scroll container to its default position
1049     *
1050     *    @context scroll container
1051     *    @return mixed
1052     */
1053    function reset (event, offset, duration) {
1054        var $this = $(this), data,
1055            options = $this.data("jqt-scroll-options");
1056               
1057                offset = offset !== undefined ? offset : options.defaultOffset;
1058                       
1059        if (options.useSlides && $.isFunction(options.slides.callback)) {
1060                        var matrix, mp,
1061                                dimension = $this[options.outerDimension](),
1062                                parent = $this.parent()[options.dimension](),
1063                                //maxScroll
1064                                endPoint = -(dimension - parent),
1065                                //a distance to stop inertia from hitting
1066                                quarter = parent / options.divider;
1067                       
1068                        options.parentDimension = parent;
1069                       
1070                        //figure out the base position
1071                        matrix = new WebKitCSSMatrix($this.css("webkitTransform"));
1072                        mp = matrix[options.matrixProperty];
1073                       
1074                        data = $this.data("jqt-scroll-current-event", {
1075                                startLocation: 0,
1076                                currentLocation: 0,
1077                                startPosition: mp,
1078                                lastPosition: mp,
1079                                currentPosition: offset,
1080                                startTime: event && event.timeStamp,
1081                                moved: true,
1082                                lastMoveTime: event && event.timeStamp,
1083                                parentDimension: parent,
1084                                endPoint: endPoint,
1085                                minScroll: !options.bounce ? 0 : quarter,
1086                                maxScroll: !options.bounce ? endPoint : endPoint - quarter,
1087                                end: true
1088                        }).data("jqt-scroll-current-event");
1089               
1090               
1091            options.slides.callback($this, options, data, event);
1092           
1093        } else {
1094                        data = {
1095                                currentPosition: offset 
1096                        };
1097                }
1098               
1099        return options.setPosition($this, options, data.currentPosition, duration || options.defaultDuration);
1100    }
1101
1102    /**
1103     *    Return the scroll container to its default position
1104     *
1105     *    @context scroll container
1106     *
1107     *    @param Event event
1108     *    @param Number offset - position to move to
1109     *    @param Number duration - duration of the scroll
1110     *    @return mixed
1111     */
1112    function scrollTo (event, offset, duration) {
1113        var $this = $(this),
1114            options = $this.data("jqt-scroll-options");
1115           
1116        return options.setPosition($this, 
1117                                   options, 
1118                                   offset !== undefined ? offset : (event.detail || options.currentPosition), 
1119                                   duration !== undefined ? duration : options.defaultDuration);
1120    }
1121
1122    /**
1123     *    Calculate the momentum of a touch event
1124     *
1125     *    @param jQuery object
1126     *    @param Object options
1127     *    @param Number position
1128     *    @param Number duration
1129     *    @param String timing - timing function
1130     *    @return jQuery
1131     */
1132    function setPosition (object, options, position, duration, timing) {
1133       
1134        if (options.scrollBarObject) {
1135            var dimension = (object.parent()[options.dimension]() - object[options.dimension]());
1136           
1137            if (position > 0) {
1138                dimension += Number(position);
1139            }
1140           
1141            options.scrollBarObject.scrollTo(options.scrollBarObject.maxScroll / dimension * position, 
1142                                              format("{0}ms", duration !== undefined ? duration : options.defaultDuration));
1143        }
1144       
1145        if (duration !== undefined) {
1146            object.css("webkitTransitionDuration", format("{0}ms", duration));
1147        }
1148       
1149        if (timing !== undefined) {
1150            object.css("webkitTransitionTimingFunction", timing);
1151        }
1152       
1153        options.currentPosition = position || 0;
1154       
1155        return object.css("webkitTransform", format(options.tranform, options.currentPosition));
1156    }
1157   
1158    /**
1159     *    Format a String followed by a set of arguments using the format
1160     *    {0} is replaced with arguments[1]
1161     *
1162     *    @param String s
1163     *    @param Object arg1 ... argN
1164     *    @return String
1165     */
1166    function format (s) {
1167        var args = arguments;
1168        return s.replace(/\{(\d+)\}/g, function(a,b){return args[Number(b)+1] + ""});
1169    }
1170
1171    /**
1172     *    Entirely the work of Matteo Spinelli
1173     *    I just took out the overflow restriction and
1174     *    simplified the DOM creation with jQuery
1175     *
1176     *
1177     */
1178    function Scrollbar (object, direction) {
1179        if (!(this instanceof Scrollbar)) {
1180            return new Scrollbar(object, direction);
1181        }
1182       
1183        this.direction = direction;
1184        this.bar = $(document.createElement("div"))
1185            .addClass("scrollbar " + direction)
1186            .appendTo(object)[0];
1187    }
1188   
1189    Scrollbar.prototype = {
1190            direction: "vertical",
1191            transform: supports3d ? "translate3d({0}px,{1}px,0)" : "translate({0}px,{1}px)",
1192            size: 0,
1193            maxSize: 0,
1194            maxScroll: 0,
1195            visible: false,
1196            offset: 0,
1197           
1198            init: function (scroll, size) {
1199                this.offset = this.direction == "horizontal" ? 
1200                                this.bar.offsetWidth - this.bar.clientWidth : 
1201                                this.bar.offsetHeight - this.bar.clientHeight;
1202                               
1203                this.maxSize = scroll - 8;        // 8 = distance from top + distance from bottom
1204                this.size = Math.round(this.maxSize * this.maxSize / size) + this.offset;
1205                this.maxScroll = this.maxSize - this.size;
1206                this.bar.style[this.direction == "horizontal" ? "width" : "height"] = (this.size - this.offset) + "px";
1207            },
1208           
1209            setPosition: function (pos) {
1210                this.bar.style.webkitTransform = format(this.transform, 
1211                                                        this.direction == "horizontal" ? 
1212                                                        Math.round(pos) : 
1213                                                        0, 
1214                                                        this.direction == "horizontal" ? 
1215                                                        0 : 
1216                                                        Math.round(pos)
1217                                                        );
1218            },
1219           
1220            scrollTo: function (pos, runtime) {
1221                this.bar.style.webkitTransitionDuration = (runtime || "400ms") + ",300ms";
1222                this.setPosition(pos);
1223            },
1224           
1225            show: function () {
1226                this.visible = true;
1227                this.bar.style.opacity = "1";
1228            },
1229       
1230            hide: function () {
1231                this.visible = false;
1232                this.bar.style.opacity = "0";
1233            },
1234           
1235            remove: function () {
1236                this.bar.parentNode.removeChild(this.bar);
1237                return null;
1238            }
1239    };
1240   
1241    //load stylesheet(s)
1242    $(function() {
1243        window.scrollTo(0,0);
1244        var stringRules = "", 
1245            rules = cssRules, 
1246            o = window.innerHeight > window.innerWidth ? "portrait" : "landscape",
1247            buildProperties = function (name, value) {
1248                stringRules += name + ":" + ($.isFunction(value) ? value(rules.variables) : value) + ";";
1249            },
1250            buildRules = function (name, properties) {
1251                stringRules += name + "{";
1252               
1253                $.each(properties, buildProperties);
1254               
1255                stringRules += "}";
1256            };
1257       
1258        $.each(rules.defaults, buildRules);
1259        $.each(rules[o], buildRules);
1260       
1261       
1262        $(document.createElement("style"))
1263            .attr({type:"text/css",media:"screen"})
1264            .html(stringRules)
1265            .appendTo("head");
1266       
1267        $(window).one("orientationchange", function () {
1268            //ensure repaint
1269            setTimeout(function () {
1270                window.scrollTo(0,0);
1271                stringRules = "";
1272                o = window.innerHeight > window.innerWidth ? "portrait" : "landscape";
1273               
1274                $.each(rules[o], buildRules);
1275               
1276                $(document.createElement("style"))
1277                    .attr({type:"text/css",media:"screen"})
1278                    .html(stringRules)
1279                    .appendTo("head");
1280            },30)
1281        });
1282    });
1283   
1284})(this.jQuery, this, this.document, this.Number, this.Math);
Note: See TracBrowser for help on using the repository browser.