<commit_before>/*
 * Scrollbar - a jQuery plugin for custom scrollbars
 *
 * @author     Thomas Duerr, me@thomd.net
 * @date       03.2010
 * @requires   jquery v1.4.2
 *
 *
 * Usage:
 * ======
 *
 *
 *
 *
 *
 *
 * CSS:
 * ====
 *
 *
 */
;(function($){

    $.fn.scrollbar = function(options){

        // Extend default options
        var options = $.extend({}, $.fn.scrollbar.defaults, options);

        //
        // append scrollbar to every found container and return jquery object for chainability
        //
        return this.each(function(i){

            var container = $(this),
                props = {};

            // determine container height
            props.containerHeight = container.height();

            // determine inner content height
            props.contentHeight = 0;
            container.children().each(function(){
                props.contentHeight += $(this).outerHeight();
            });

            // do nothing and return if a scrollbar is not neccessary
            if(props.contentHeight <= props.containerHeight) return true;

            // set options via class attributes
            options.arrows = container.hasClass('no-arrows') ? false : true;

            // create scrollbar
            var scrollbar = new $.fn.scrollbar.Scrollbar(container, props, options);
        });
    }

    //
    // default options
    //
    $.fn.scrollbar.defaults = {
        arrows:          true,       // render up- / down-arrows
        handleMinHeight: 30,         // min-height of handle (height is actually dependent on content height)
        scrollSpeed:     100,        // TODO
        scrollStep:      10          // TODO
    };

    //
    // Scrollbar class properties
    //
    $.fn.scrollbar.Scrollbar = function(container, props, options){
        this.container = container;
        this.props =     props;
        this.opts =      options;
        this.mouse =     {};

        // initialize
        this.buildHtml();
        this.initHandle();
        this.appendEvents();
    };

    //
    // Scrollbar class methods
    //
    $.fn.scrollbar.Scrollbar.prototype = {

        //
        // build DOM nodes for pane and scroll-handle
        //
        //   from:
        //
        //
                             --> arbitrary element with class="scrollbar"
        //          [...]
        //

        //
        //   to:
        //
        //
                             --> this.container
        //
                    --> this.pane
        //              [...]
        //

        //
        --> this.handleContainer
        //

        --> this.handle
        //

        //

         --> this.handleArrows
        //

       --> this.handleArrows
        //

        //
        //
        // TODO: use detach-transform-attach or DOMfragment
        //
        buildHtml: function(){

            // build some DOM nodes
            this.container.children().wrapAll('
');
            this.container.append('

');
            this.opts.arrows && this.container.append('
').append('
');

            // set scrollbar-object properties
            this.pane =            this.container.find('.scrollbar-pane');
            this.handle =          this.container.find('.scrollbar-handle');
            this.handleContainer = this.container.find('.scrollbar-handle-container');
            this.handleArrows =    this.container.find('.scrollbar-handle-up, .scrollbar-handle-down');
            this.handleArrowUp =   this.container.find('.scrollbar-handle-up');
            this.handleArrowDown = this.container.find('.scrollbar-handle-down');

            // set some optional CSS attributes (may be overwritten by css definitions)
            this.container.defaultCss({
                'padding':  0
            });
            this.pane.defaultCss({
                'top':      0,
                'left':     0
            });
            this.handleContainer.defaultCss({
                'top':      this.handleArrowUp.outerHeight(),
                'right':    0
            });
            this.handle.defaultCss({
                'top':      0,
                'right':    0
            });
            this.handleArrows.defaultCss({
                'right':    0,
            });
            this.handleArrowUp.defaultCss({
                'top':      0
            });
            this.handleArrowDown.defaultCss({
                'bottom':   0
            });

            // set some necessary CSS attributes
            this.container.css({
                'position': this.container.css('position') === 'absolute' ? 'absolute' : 'relative',
                'overflow': 'hidden'
            });
            this.pane.css({
                'position': 'absolute',
                'overflow': 'visible',
                'height':   'auto'
            });
            this.handleContainer.css({
                'position': 'absolute',
                'height':   (this.props.containerHeight - this.handleArrowUp.outerHeight() - this.handleArrowDown.outerHeight()) + 'px'
            });
            this.handle.css({
                'position': 'absolute',
                'cursor':   'pointer'
            });
            this.handleArrows.css({
                'position': 'absolute',
                'cursor':   'pointer'
            });
        },

        //
        // append events on handle and handle-container
        //
        appendEvents: function(){

            // append hover event on scrollbar-handle
            this.handle.bind('mouseenter mouseleave', this.hoverHandle);

            // append hover event on scrollbar-arrows
            this.handleArrows.bind('mouseenter mouseleave', this.hoverHandle);

            // append drag-drop event on scrollbar-handle
            this.handle.bind('mousedown.handle', $.proxy(this, 'startOfHandleMove'));

            // append click event on scrollbar-handle-container
            this.handleContainer.bind('mousedown.handle', $.proxy(this, 'clickHandleContainer'));

            // append click event on scrollbar-up- and scrollbar-down-handles
            this.handleArrows.bind('mousedown.arrows', $.proxy(this, 'clickHandleArrows'));

            // appen mousewheel event on content container
            this.container.bind('mousewheel.container', $.proxy(this, 'onMouseWheel'));
        },

        //
        // calculate height of handle.
        // height of handle should indicate height of content.
        //
        initHandle: function(){
            this.props.handleContainerHeight = this.handleContainer.height();

            // we need to calculate content-height again: due to the added scrollbar, the width decreased - hence the height increased!
            var contentHeight = 0;
            this.pane.children().each(function(){
                contentHeight += $(this).outerHeight();
            });
            this.props.contentHeight = contentHeight;

            this.props.handleHeight = Math.max(this.props.containerHeight * this.props.handleContainerHeight / this.props.contentHeight, this.opts.handleMinHeight);
            this.props.handleTop = {
                min: 0,
                max: this.props.handleContainerHeight - this.props.handleHeight
            };
            this.handle.height(this.props.handleHeight);
            this.handle.top = 0;
            this.handleContentRatio = (this.props.contentHeight - this.props.containerHeight) / (this.props.handleContainerHeight - this.props.handleHeight);
        },

        //
        // get mouse position helper
        //
        mousePosition: function(ev) {
			return ev.pageY || (ev.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) || 0;
		},

        // ---------- event handler ---------------------------------------------------------------

        //
        // start moving of handle
        //
        startOfHandleMove: function(ev){
            ev.preventDefault();

            // set start position of mouse
            this.mouse.start = this.mousePosition(ev);

            // set start position of handle
            this.handle.start = this.handle.top;

            // bind mousemove- and mouseout-event to document (binding it to document allows having a mousepointer outside handle while moving)
    		$(document).bind('mousemove.handle', $.proxy(this, 'onHandleMove')).bind('mouseup.handle', $.proxy(this, 'endOfHandleMove'));

            // remove hover event on scrollbar-arrows (until end of handle move)
    		this.handleArrows.unbind('mouseenter mouseleave', this.hoverHandle);

    		// add class for visual change while moving handle
            this.handle.addClass('move');
        },

        //
        // on moving of handle
        //
        onHandleMove: function(ev){

            // calculate distance since last fireing of this handler
            var distance = this.mousePosition(ev) - this.mouse.start;

            // calculate new handle position
            this.handle.top = this.handle.start + distance;

            // update positions
            this.setHandlePosition();
            this.setContentPosition();
        },

        //
        // end moving of handle
        //
        endOfHandleMove: function(ev){

            // remove handle events
    		$(document).unbind('.handle');

            // re-attach hover event on scrollbar-arrows
            this.handleArrows.bind('mouseenter mouseleave', this.hoverHandle);

            // remove class for visual change
            this.handle.removeClass('move');
        },

        //
        // set position of handle
        //
        setHandlePosition: function(){

            // stay within range [handleTop.min, handleTop.max]
            this.handle.top = (this.handle.top > this.props.handleTop.max) ? this.props.handleTop.max : this.handle.top;
            this.handle.top = (this.handle.top < this.props.handleTop.min) ? this.props.handleTop.min : this.handle.top;

            this.handle[0].style.top = this.handle.top + 'px';
        },

        //
        // set position of content
        //
        setContentPosition: function(){

            // derive position of content from position of handle
            this.pane.top = -1 * this.handleContentRatio * this.handle.top;

            this.pane[0].style.top = this.pane.top + 'px';
        },

        //
        // mouse wheel movement
        //
        onMouseWheel: function(ev, delta){

            // calculate new handle position
            this.handle.top -= delta;

            this.setHandlePosition();
            this.setContentPosition();
        },

        //
        // TODO: document!
        // append click handler on handle-container (to click up and down the handle)
        //
        clickHandleContainer: function(ev){
            ev.preventDefault();
            if(!$(ev.target).hasClass('scrollbar-handle-container')) return false;

            var direction = (this.handle.offset().top < this.mousePosition(ev)) ? 1 : -1;
            this.handle.start = this.handle.top = direction == 1 ? this.handle.top + (this.props.handleTop.max - this.handle.top) * 0.5 : this.handle.top - (this.handle.top - this.props.handleTop.min) * 0.5;
            this.handle[0].style.top = this.handle.top + 'px';
            this.setContentPosition();
        },

        //
        // TODO: document!
        // append click handler on handle-arrows
        //
        clickHandleArrows: function(ev){
            ev.preventDefault();
            var direction = $(ev.target).hasClass('scrollbar-handle-up') ? -1 : 1;

            var timer = setInterval($.proxy(function(){
                this.handle.start = this.handle.top = direction == 1 ? Math.min(this.handle.top + this.opts.scrollStep, this.props.handleTop.max) : Math.max(this.handle.top - this.opts.scrollStep, this.props.handleTop.min);
                this.handle[0].style.top = this.handle.top + 'px';
                this.setContentPosition();
            }, this), this.opts.scrollSpeed);

    		var clearTimer = function(){
    		    clearInterval(timer);
        		$(document).unbind('mouseup.arrows', clearTimer);
    		}
    		$(document).bind('mouseup.arrows', clearTimer);
        },

        //
        // TODO: document!
        // event handler for hovering the scrollbar-handle
        //
        hoverHandle: function(ev){
            if(ev.type == 'mouseenter'){
                $(this).addClass('hover');
            } else {
                $(this).removeClass('hover');
            }
        }
    };

    // ----- default css ---------------------------------------------------------------------

    $.fn.defaultCss = function(styles){

        // 'not-defined'-values
        notdef = {
            'right':    'auto',
            'left':     'auto',
            'top':      'auto',
            'bottom':   'auto',
            'position': 'static',
            'margin':   '',
            'padding':  ''
        };

        // loop through all style definitions and check for a definition already set by css.
        // if no definition is found, apply the default css definition
        return this.each(function(){
            var elem = $(this);
            for(style in styles){
                if(elem.css(style) === notdef[style]){
                    elem.css(style, styles[style]);
                }
            }
        });
    }

    // ----- mousewheel event ---------------------------------------------------------------------

    $.event.special.mousewheel = {

        setup: function(){
            if (this.addEventListener){
                this.addEventListener('mousewheel', handler, false);
                this.addEventListener('DOMMouseScroll', handler, false);
            } else {
                this.onmousewheel = handler;
            }
        },

        teardown: function(){
            if (this.removeEventListener){
                this.removeEventListener('mousewheel', handler, false);
                this.removeEventListener('DOMMouseScroll', handler, false);
            } else {
                this.onmousewheel = null;
            }
        }
    };

    $.fn.extend({
        mousewheel: function(fn){
            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
        },

        unmousewheel: function(fn){
            return this.unbind("mousewheel", fn);
        }
    });

    function handler(event) {
        var orgEvent = event || window.event,
            args = [].slice.call(arguments, 1),
            delta = 0,
            returnValue = true,
            deltaX = 0,
            deltaY = 0;

        event = $.event.fix(orgEvent);
        event.type = "mousewheel";

        // Old school scrollwheel delta
        if(event.wheelDelta){
            delta = event.wheelDelta / 120;
        }
        if(event.detail){
            delta = -event.detail / 3;
        }

        // Gecko
        if(orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS){
            deltaY = 0;
            deltaX = -1 * delta;
        }

        // Webkit
        if(orgEvent.wheelDeltaY !== undefined){
            deltaY = orgEvent.wheelDeltaY / 120;
        }
        if(orgEvent.wheelDeltaX !== undefined){
            deltaX = -1 * orgEvent.wheelDeltaX / 120;
        }

        // Add event and delta to the front of the arguments
        args.unshift(event, delta, deltaX, deltaY);

        return $.event.handle.apply(this, args);
    }

})(jQuery);  // inject global jQuery object

<commit_msg>made code more JSLin conformt<commit_after>/*jslint eqeqeq: true, regexp: true */
/*global document, window, setInterval, clearInterval, handler, jQuery */

/*
 * Scrollbar - a jQuery plugin for custom scrollbars
 *
 * @author     Thomas Duerr, me@thomd.net
 * @date       03.2010
 * @requires   jquery v1.4.2
 *
 *
 * Usage:
 * ======
 *
 *
 *
 *
 *
 *
 * CSS:
 * ====
 *
 *
 */
(function($, document){

    $.fn.scrollbar = function(opts){

        // Extend default options
        var options = $.extend({}, $.fn.scrollbar.defaults, opts);

        //
        // append scrollbar to every found container and return jquery object for chainability
        //
        return this.each(function(){

            var container = $(this),
                props = {};

            // determine container height
            props.containerHeight = container.height();

            // determine inner content height
            props.contentHeight = 0;
            container.children().each(function(){
                props.contentHeight += $(this).outerHeight();
            });

            // do nothing and return if a scrollbar is not neccessary
            if(props.contentHeight <= props.containerHeight){
                return true;
            }

            // set options via class attributes
            options.arrows = container.hasClass('no-arrows') ? false : true;

            // create scrollbar
            var scrollbar = new $.fn.scrollbar.Scrollbar(container, props, options);
            return scrollbar;
        });
    };

    //
    // default options
    //
    $.fn.scrollbar.defaults = {
        arrows:          true,       // render up- / down-arrows
        handleMinHeight: 30,         // min-height of handle (height is actually dependent on content height)
        scrollSpeed:     100,        // TODO
        scrollStep:      10          // TODO
    };

    //
    // Scrollbar class properties
    //
    $.fn.scrollbar.Scrollbar = function(container, props, options){
        this.container = container;
        this.props =     props;
        this.opts =      options;
        this.mouse =     {};

        // initialize
        this.buildHtml();
        this.initHandle();
        this.appendEvents();
    };

    //
    // Scrollbar class methods
    //
    $.fn.scrollbar.Scrollbar.prototype = {

        //
        // build DOM nodes for pane and scroll-handle
        //
        //   from:
        //
        //
                             --> arbitrary element with class="scrollbar"
        //          [...]
        //

        //
        //   to:
        //
        //
                             --> this.container
        //
                    --> this.pane
        //              [...]
        //

        //
        --> this.handleContainer
        //

        --> this.handle
        //

        //

         --> this.handleArrows
        //

       --> this.handleArrows
        //

        //
        //
        // TODO: use detach-transform-attach or DOMfragment
        //
        buildHtml: function(){

            // build some DOM nodes
            this.container.children().wrapAll('
');
            this.container.append('

');
            if(this.opts.arrows){
                this.container.append('
').append('
');
            }

            // set scrollbar-object properties
            this.pane =            this.container.find('.scrollbar-pane');
            this.handle =          this.container.find('.scrollbar-handle');
            this.handleContainer = this.container.find('.scrollbar-handle-container');
            this.handleArrows =    this.container.find('.scrollbar-handle-up, .scrollbar-handle-down');
            this.handleArrowUp =   this.container.find('.scrollbar-handle-up');
            this.handleArrowDown = this.container.find('.scrollbar-handle-down');

            // set some optional CSS attributes (may be overwritten by css definitions)
            this.container.defaultCss({
                'padding':  0
            });
            this.pane.defaultCss({
                'top':      0,
                'left':     0
            });
            this.handleContainer.defaultCss({
                'top':      this.handleArrowUp.outerHeight(),
                'right':    0
            });
            this.handle.defaultCss({
                'top':      0,
                'right':    0
            });
            this.handleArrows.defaultCss({
                'right':    0
            });
            this.handleArrowUp.defaultCss({
                'top':      0
            });
            this.handleArrowDown.defaultCss({
                'bottom':   0
            });

            // set some necessary CSS attributes
            this.container.css({
                'position': this.container.css('position') === 'absolute' ? 'absolute' : 'relative',
                'overflow': 'hidden'
            });
            this.pane.css({
                'position': 'absolute',
                'overflow': 'visible',
                'height':   'auto'
            });
            this.handleContainer.css({
                'position': 'absolute',
                'height':   (this.props.containerHeight - this.handleArrowUp.outerHeight() - this.handleArrowDown.outerHeight()) + 'px'
            });
            this.handle.css({
                'position': 'absolute',
                'cursor':   'pointer'
            });
            this.handleArrows.css({
                'position': 'absolute',
                'cursor':   'pointer'
            });
        },

        //
        // append events on handle and handle-container
        //
        appendEvents: function(){

            // append hover event on scrollbar-handle
            this.handle.bind('mouseenter mouseleave', this.hoverHandle);

            // append hover event on scrollbar-arrows
            this.handleArrows.bind('mouseenter mouseleave', this.hoverHandle);

            // append drag-drop event on scrollbar-handle
            this.handle.bind('mousedown.handle', $.proxy(this, 'startOfHandleMove'));

            // append click event on scrollbar-handle-container
            this.handleContainer.bind('mousedown.handle', $.proxy(this, 'clickHandleContainer'));

            // append click event on scrollbar-up- and scrollbar-down-handles
            this.handleArrows.bind('mousedown.arrows', $.proxy(this, 'clickHandleArrows'));

            // appen mousewheel event on content container
            this.container.bind('mousewheel.container', $.proxy(this, 'onMouseWheel'));
        },

        //
        // calculate height of handle.
        // height of handle should indicate height of content.
        //
        initHandle: function(){
            this.props.handleContainerHeight = this.handleContainer.height();

            // we need to calculate content-height again: due to the added scrollbar, the width decreased - hence the height increased!
            var contentHeight = 0;
            this.pane.children().each(function(){
                contentHeight += $(this).outerHeight();
            });
            this.props.contentHeight = contentHeight;

            this.props.handleHeight = Math.max(this.props.containerHeight * this.props.handleContainerHeight / this.props.contentHeight, this.opts.handleMinHeight);
            this.props.handleTop = {
                min: 0,
                max: this.props.handleContainerHeight - this.props.handleHeight
            };
            this.handle.height(this.props.handleHeight);
            this.handle.top = 0;
            this.handleContentRatio = (this.props.contentHeight - this.props.containerHeight) / (this.props.handleContainerHeight - this.props.handleHeight);
        },

        //
        // get mouse position helper
        //
        mousePosition: function(ev) {
			return ev.pageY || (ev.clientY + (document.documentElement.scrollTop || document.body.scrollTop)) || 0;
		},

        // ---------- event handler ---------------------------------------------------------------

        //
        // start moving of handle
        //
        startOfHandleMove: function(ev){
            ev.preventDefault();

            // set start position of mouse
            this.mouse.start = this.mousePosition(ev);

            // set start position of handle
            this.handle.start = this.handle.top;

            // bind mousemove- and mouseout-event to document (binding it to document allows having a mousepointer outside handle while moving)
            $(document).bind('mousemove.handle', $.proxy(this, 'onHandleMove')).bind('mouseup.handle', $.proxy(this, 'endOfHandleMove'));

            // remove hover event on scrollbar-arrows (until end of handle move)
            this.handleArrows.unbind('mouseenter mouseleave', this.hoverHandle);

            // add class for visual change while moving handle
            this.handle.addClass('move');
        },

        //
        // on moving of handle
        //
        onHandleMove: function(ev){

            // calculate distance since last fireing of this handler
            var distance = this.mousePosition(ev) - this.mouse.start;

            // calculate new handle position
            this.handle.top = this.handle.start + distance;

            // update positions
            this.setHandlePosition();
            this.setContentPosition();
        },

        //
        // end moving of handle
        //
        endOfHandleMove: function(ev){

            // remove handle events
            $(document).unbind('.handle');

            // re-attach hover event on scrollbar-arrows
            this.handleArrows.bind('mouseenter mouseleave', this.hoverHandle);

            // remove class for visual change
            this.handle.removeClass('move');
        },

        //
        // set position of handle
        //
        setHandlePosition: function(){

            // stay within range [handleTop.min, handleTop.max]
            this.handle.top = (this.handle.top > this.props.handleTop.max) ? this.props.handleTop.max : this.handle.top;
            this.handle.top = (this.handle.top < this.props.handleTop.min) ? this.props.handleTop.min : this.handle.top;

            this.handle[0].style.top = this.handle.top + 'px';
        },

        //
        // set position of content
        //
        setContentPosition: function(){

            // derive position of content from position of handle
            this.pane.top = -1 * this.handleContentRatio * this.handle.top;

            this.pane[0].style.top = this.pane.top + 'px';
        },

        //
        // mouse wheel movement
        //
        onMouseWheel: function(ev, delta){

            // calculate new handle position
            this.handle.top -= delta;

            this.setHandlePosition();
            this.setContentPosition();
        },

        //
        // TODO: document!
        // append click handler on handle-container (to click up and down the handle)
        //
        clickHandleContainer: function(ev){
            ev.preventDefault();
            if(!$(ev.target).hasClass('scrollbar-handle-container')){
                return false;
            }

            var direction = (this.handle.offset().top < this.mousePosition(ev)) ? 1 : -1;
            this.handle.start = this.handle.top = (direction === 1) ? this.handle.top + (this.props.handleTop.max - this.handle.top) * 0.5 : this.handle.top - (this.handle.top - this.props.handleTop.min) * 0.5;
            this.handle[0].style.top = this.handle.top + 'px';
            this.setContentPosition();
        },

        //
        // TODO: document!
        // append click handler on handle-arrows
        //
        clickHandleArrows: function(ev){
            ev.preventDefault();
            var direction = $(ev.target).hasClass('scrollbar-handle-up') ? -1 : 1;

            var timer = setInterval($.proxy(function(){
                this.handle.start = this.handle.top = (direction === 1) ? Math.min(this.handle.top + this.opts.scrollStep, this.props.handleTop.max) : Math.max(this.handle.top - this.opts.scrollStep, this.props.handleTop.min);
                this.handle[0].style.top = this.handle.top + 'px';
                this.setContentPosition();
            }, this), this.opts.scrollSpeed);

            var clearTimer = function(){
                clearInterval(timer);
                $(document).unbind('mouseup.arrows', clearTimer);
            };
            $(document).bind('mouseup.arrows', clearTimer);
        },

        //
        // TODO: document!
        // event handler for hovering the scrollbar-handle
        //
        hoverHandle: function(ev){
            if(ev.type === 'mouseenter'){
                $(this).addClass('hover');
            } else {
                $(this).removeClass('hover');
            }
        }
    };

    // ----- default css ---------------------------------------------------------------------

    $.fn.defaultCss = function(styles){

        // 'not-defined'-values
        var notdef = {
            'right':    'auto',
            'left':     'auto',
            'top':      'auto',
            'bottom':   'auto',
            'position': 'static',
            'margin':   '',
            'padding':  ''
        };

        // loop through all style definitions and check for a definition already set by css.
        // if no definition is found, apply the default css definition
        return this.each(function(){
            var elem = $(this);
            for(var style in styles){
                if(elem.css(style) === notdef[style]){
                    elem.css(style, styles[style]);
                }
            }
        });
    };

    // ----- mousewheel event ---------------------------------------------------------------------

    $.event.special.mousewheel = {

        setup: function(){
            if (this.addEventListener){
                this.addEventListener('mousewheel', $.fn.scrollbar.mouseWheelHandler, false);
                this.addEventListener('DOMMouseScroll', $.fn.scrollbar.mouseWheelHandler, false);
            } else {
                this.onmousewheel = $.fn.scrollbar.mouseWheelHandler;
            }
        },

        teardown: function(){
            if (this.removeEventListener){
                this.removeEventListener('mousewheel', $.fn.scrollbar.mouseWheelHandler, false);
                this.removeEventListener('DOMMouseScroll', $.fn.scrollbar.mouseWheelHandler, false);
            } else {
                this.onmousewheel = null;
            }
        }
    };

    $.fn.extend({
        mousewheel: function(fn){
            return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
        },

        unmousewheel: function(fn){
            return this.unbind("mousewheel", fn);
        }
    });

    $.fn.scrollbar.mouseWheelHandler = function(event) {
        var orgEvent = event || window.event,
            args = [].slice.call(arguments, 1),
            delta = 0,
            returnValue = true,
            deltaX = 0,
            deltaY = 0;

        event = $.event.fix(orgEvent);
        event.type = "mousewheel";

        // Old school scrollwheel delta
        if(event.wheelDelta){
            delta = event.wheelDelta / 120;
        }
        if(event.detail){
            delta = -event.detail / 3;
        }

        // Gecko
        if(orgEvent.axis !== undefined && orgEvent.axis === orgEvent.HORIZONTAL_AXIS){
            deltaY = 0;
            deltaX = -1 * delta;
        }

        // Webkit
        if(orgEvent.wheelDeltaY !== undefined){
            deltaY = orgEvent.wheelDeltaY / 120;
        }
        if(orgEvent.wheelDeltaX !== undefined){
            deltaX = -1 * orgEvent.wheelDeltaX / 120;
        }

        // Add event and delta to the front of the arguments
        args.unshift(event, delta, deltaX, deltaY);

        return $.event.handle.apply(this, args);
    };

})(jQuery, document);  // inject global jQuery object

<|endoftext|>


<commit_before>// Subclass of Query. Represents a query of the report collection.

var Report = require('../report');
var Query = require('../query');
var util = require('util');
var _ = require('underscore');

var ReportQuery = function(options) {
  options = options || {};
  this.keywords = options.keywords;

  if (options.status) {
    this._parseStatus(options.status);
  }

  this._parseIncidentId(options.incidentId);

  this.after = options.after;
  this.before = options.before;
  this.sourceId = options.sourceId;
  this.sourceType = options.sourceType;
  this.author = options.author;
  this.event = 'reports';
};

_.extend(ReportQuery, Query);
util.inherits(ReportQuery, Query);

ReportQuery.prototype.run = function(callback) {
  Report.queryReports(this, function(err, results) {
    callback(err, results);
  });
};

// Normalize query for comparison
ReportQuery.prototype.normalize = function() {

  var query = _.pick(this, ['keywords', 'status', 'after', 'before', 'sourceId', 'sourceType', 'incidentId', 'author']);

  if (query.keywords) {
    // Make all keywords lowercase, then sort them alphabetically
    query.keywords = query.keywords.replace(/(,|\s)+/g, ' ').split(' ').map(function(w) {
      return w.toLowerCase();
    }).sort().join(' ');
  }

  return query;
};

ReportQuery.prototype._parseStatus = function(status) {
  switch(status) {
    case 'flagged':
      this.flagged = true;
      break;
    case 'unflagged':
      this.unflagged = true;
      break;
    case 'read':
      this.read = true;
      break;
    case 'unread':
      this.read = false;
      break;
    case 'read & unflagged':
      this.read = true;
      this.flagged = false;
      break;
  }
}

ReportQuery.prototype._parseIncidentId = function(incidentId) {
  if (incidentId == 'any') {
    this.incidentId = { $ne: null };
  }
  else if (incidentId == 'no') {
    this.incidentId = null;
  }
  else {
    this.incidentId = incidentId;
  }
}

module.exports = ReportQuery;
<commit_msg>more cleanup<commit_after>// Subclass of Query. Represents a query of the report collection.

var Report = require('../report');
var Query = require('../query');
var util = require('util');
var _ = require('underscore');

var ReportQuery = function(options) {
  options = options || {};
  this.keywords = options.keywords;

  if (options.status) {
    this._parseStatus(options.status);
  }

  this._parseIncidentId(options.incidentId);

  this.after = options.after;
  this.before = options.before;
  this.sourceId = options.sourceId;
  this.sourceType = options.sourceType;
  this.author = options.author;
  this.event = 'reports';
};

_.extend(ReportQuery, Query);
util.inherits(ReportQuery, Query);

ReportQuery.prototype.run = function(callback) {
  Report.queryReports(this, function(err, results) {
    callback(err, results);
  });
};

// Normalize query for comparison
ReportQuery.prototype.normalize = function() {

  var query = _.pick(this, ['keywords', 'status', 'after', 'before', 'sourceId', 'sourceType', 'incidentId', 'author']);

  if (query.keywords) {
    // Make all keywords lowercase, then sort them alphabetically
    query.keywords = query.keywords.replace(/(,|\s)+/g, ' ').split(' ').map(function(w) {
      return w.toLowerCase();
    }).sort().join(' ');
  }

  return query;
};

ReportQuery.prototype._parseStatus = function(status) {
  switch(status) {
    case 'flagged':
      this.flagged = true;
      break;
    case 'unflagged':
      this.unflagged = true;
      break;
    case 'read':
      this.read = true;
      break;
    case 'unread':
      this.read = false;
      break;
    case 'read & unflagged':
      this.read = true;
      this.flagged = false;
      break;
  }
}

ReportQuery.prototype._parseIncidentId = function(incidentId) {
  if (incidentId == 'a') {
    this.incidentId = { $ne: null };
  }
  else if (incidentId == 'n') {
    this.incidentId = null;
  }
  else {
    this.incidentId = incidentId;
  }
}

module.exports = ReportQuery;
<|endoftext|>


<commit_before>/**
 * @module Shape
 * @for Vertex
 * @requires core
 * @requires constants
 */
define(function (require) {

  'use strict';

  var p5 = require('core');
  var constants = require('constants');

  p5.prototype._shapeKind = null;
  p5.prototype._shapeInited = false;
  p5.prototype._contourInited = false;
  p5.prototype._contourVertices = [];

  /**
   * Use the beginContour() and endContour() function to create negative shapes
   * within shapes. For instance, the center of the letter 'O'. beginContour()
   * begins recording vertices for the shape and endContour() stops recording.
   * These functions can only be within a beginShape()/endShape() pair and they
   * only work with the P2D and P3D renderers.
   *
   * Transformations such as translate(), rotate(), and scale() do not work
   * within a beginContour()/endContour() pair. It is also not possible to use
   * other shapes, such as ellipse() or rect() within.
   *
   * @method beginContour
   * @return {Object} the p5 object
   */
  p5.prototype.beginContour = function() {
    this._contourVertices = [];
    this._contourInited = true;

    return this;
  };

  /**
   * Using the beginShape() and endShape() functions allow creating more
   * complex forms. beginShape() begins recording vertices for a shape and
   * endShape() stops recording. The value of the kind parameter tells it which
   * types of shapes to create from the provided vertices. With no mode
   * specified, the shape can be any irregular polygon. The parameters
   * available for beginShape() are POINTS, LINES, TRIANGLES, TRIANGLE_FAN,
   * TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the beginShape()
   * function, a series of vertex() commands must follow. To stop drawing the
   * shape, call endShape(). The vertex() function with two parameters
   * specifies a position in 2D and the vertex() function with three parameters
   * specifies a position in 3D. Each shape will be outlined with the current
   * stroke color and filled with the fill color.
   *
   * Transformations such as translate(), rotate(), and scale() do not work
   * within beginShape(). It is also not possible to use other shapes, such as
   * ellipse() or rect() within beginShape().
   *
   * @method beginShape
   * @param  {Number/Constant} kind either POINTS, LINES, TRIANGLES,
   *                                TRIANGLE_FAN, TRIANGLE_STRIP, QUADS,
   *                                or QUAD_STRIP
   * @return {Object}               the p5 object
   */
  p5.prototype.beginShape = function(kind) {
    if (kind === constants.POINTS ||
      kind === constants.LINES ||
      kind === constants.TRIANGLES ||
      kind === constants.TRIANGLE_FAN ||
      kind === constants.TRIANGLE_STRIP ||
      kind === constants.QUADS ||
      kind === constants.QUAD_STRIP) {
      this._shapeKind = kind;
    } else {
      this._shapeKind = null;
    }

    this._shapeInited = true;
    this._curElement.context.beginPath();

    return this;
  };

  /**
   * Specifies vertex coordinates for Bezier curves. Each call to
   * bezierVertex() defines the position of two control points and
   * one anchor point of a Bezier curve, adding a new segment to a
   * line or shape. The first time bezierVertex() is used within a
   * beginShape() call, it must be prefaced with a call to vertex()
   * to set the first anchor point. This function must be used between
   * beginShape() and endShape() and only when there is no MODE
   * parameter specified to beginShape().
   *
   * @method bezierVertex
   * @param  {Number} x2 x-coordinate for the first control point
   * @param  {Number} y2 y-coordinate for the first control point
   * @param  {Number} x3 x-coordinate for the second control point
   * @param  {Number} y3 y-coordinate for the second control point
   * @param  {Number} x4 x-coordinate for the anchor point
   * @param  {Number} y4 y-coordinate for the anchor point
   * @return {Object}    the p5 object
   */
  p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) {
    if(this._contourInited) {
      var pt = {};
      pt.x = x2;
      pt.y = y2;
      pt.x3 = x3;
      pt.y3 = y3;
      pt.x4 = x4;
      pt.y4 = y4;
      pt.type = constants.BEZIER;
      this._contourVertices.push(pt);

      return this;
    }

    this._curElement.context.bezierCurveTo(x2, y2, x3, y3, x4, y4);

    return this;
  };

  p5.prototype.curveVertex = function() {
    // TODO
    throw 'not yet implemented';
  };

  /**
   * Use the beginContour() and endContour() function to create negative
   * shapes within shapes. For instance, the center of the letter 'O'.
   * beginContour() begins recording vertices for the shape and endContour()
   * stops recording. These functions can only be within a
   * beginShape()/endShape() pair and they only work with the P2D and P3D
   * renderers.
   *
   * @method endContour
   * @return {Object} the p5 object
   */
  p5.prototype.endContour = function() {
    //In order for the contour fill to work correctly, the inside points must
    // be drawn in the reverse order of the parents
    this._contourVertices.reverse();
    this._curElement.context.moveTo(
      this._contourVertices[0].x,
      this._contourVertices[0].y
    );
    var ctx = this._curElement.context;
    this._contourVertices.slice(1).forEach(function(pt, i) {
      switch(pt.type) {
      case constants.LINEAR:
        ctx.lineTo(pt.x,pt.y);
        break;
      case constants.QUADRATIC:
        ctx.quadraticCurveTo(pt.x, pt.y, pt.x3, pt.y3);
        break;
      case constants.BEZIER:
        ctx.bezierCurveTo(pt.x, pt.y, pt.x3, pt.y3, pt.x4, pt.y4);
        break;
      case constants.CURVE:
        //TODO: Curve... curve
        break;
      }
    });
    this._curElement.context.closePath();

    this._contourInited = false;

    return this;
  };

  /**
   * The endShape() function is the companion to beginShape() and may only be
   * called after beginShape(). When endshape() is called, all of image data
   * defined since the previous call to beginShape() is written into the image
   * buffer. The constant CLOSE as the value for the MODE parameter to close
   * the shape (to connect the beginning and the end).
   *
   * @method endShape
   * @param  {Number/Constant} mode use CLOSE to close the shape
   * @return {Object}               the p5 object
   */
  p5.prototype.endShape = function(mode) {
    if (mode === constants.CLOSE) {
      this._curElement.context.closePath();
      this._curElement.context.fill();
    }
    this._curElement.context.stroke();

    return this;
  };

  /**
   * Specifies vertex coordinates for quadratic Bezier curves. Each call to
   * quadraticVertex() defines the position of one control points and one
   * anchor point of a Bezier curve, adding a new segment to a line or shape.
   * The first time quadraticVertex() is used within a beginShape() call, it
   * must be prefaced with a call to vertex() to set the first anchor point.
   * This function must be used between beginShape() and endShape() and only
   * when there is no MODE parameter specified to beginShape().
   *
   * @method quadraticVertex
   * @param  {Number} cx x-coordinate for the control point
   * @param  {Number} cy y-coordinate for the control point
   * @param  {Number} x3 x-coordinate for the anchor point
   * @param  {Number} y3 y-coordinate for the anchor point
   * @return {Object}    the p5 object
   */
  p5.prototype.quadraticVertex = function(cx, cy, x3, y3) {
    //if we're drawing a contour, put the points into an
    // array for inside drawing
    if(this._contourInited) {
      var pt = {};
      pt.x = cx;
      pt.y = cy;
      pt.x3 = x3;
      pt.y3 = y3;
      pt.type = constants.QUADRATIC;
      this._contourVertices.push(pt);

      return this;
    }

    this._curElement.context.quadraticCurveTo(cx, cy, x3, y3);

    return this;
  };

  /**
   * All shapes are constructed by connecting a series of vertices. vertex()
   * is used to specify the vertex coordinates for points, lines, triangles,
   * quads, and polygons. It is used exclusively within the beginShape() and
   * endShape() functions.
   *
   * @method vertex
   * @param  {Number} x x-coordinate of the vertex
   * @param  {Number} y y-coordinate of the vertex
   * @return {Object}   the p5 object
   */
  p5.prototype.vertex = function(x, y) {
    //if we're drawing a contour, put the points into an array for inside
    // drawing
    if(this._contourInited) {
      var pt = {};
      pt.x = x;
      pt.y = y;
      pt.type = constants.LINEAR;
      this._contourVertices.push(pt);

      return this;
    }

    if (this._shapeInited) {
      this._curElement.context.moveTo(x, y);
    } else {
      // pend this is where check for kind and do other stuff
      this._curElement.context.lineTo(x, y);
    }
    this._shapeInited = false;

    return this;
  };

  return p5;

});<commit_msg>implemeny curvevertex for issue #25<commit_after>/**
 * @module Shape
 * @for Vertex
 * @requires core
 * @requires constants
 */
define(function (require) {

  'use strict';

  var p5 = require('core');
  var constants = require('constants');

  p5.prototype._shapeKind = null;
  p5.prototype._shapeInited = false;
  p5.prototype._contourInited = false;
  p5.prototype._contourVertices = [];
  p5.prototype._curveVertices = [];

  /**
   * Use the beginContour() and endContour() function to create negative shapes
   * within shapes. For instance, the center of the letter 'O'. beginContour()
   * begins recording vertices for the shape and endContour() stops recording.
   * These functions can only be within a beginShape()/endShape() pair and they
   * only work with the P2D and P3D renderers.
   *
   * Transformations such as translate(), rotate(), and scale() do not work
   * within a beginContour()/endContour() pair. It is also not possible to use
   * other shapes, such as ellipse() or rect() within.
   *
   * @method beginContour
   * @return {Object} the p5 object
   */
  p5.prototype.beginContour = function() {
    this._contourVertices = [];
    this._contourInited = true;

    return this;
  };

  /**
   * Using the beginShape() and endShape() functions allow creating more
   * complex forms. beginShape() begins recording vertices for a shape and
   * endShape() stops recording. The value of the kind parameter tells it which
   * types of shapes to create from the provided vertices. With no mode
   * specified, the shape can be any irregular polygon. The parameters
   * available for beginShape() are POINTS, LINES, TRIANGLES, TRIANGLE_FAN,
   * TRIANGLE_STRIP, QUADS, and QUAD_STRIP. After calling the beginShape()
   * function, a series of vertex() commands must follow. To stop drawing the
   * shape, call endShape(). The vertex() function with two parameters
   * specifies a position in 2D and the vertex() function with three parameters
   * specifies a position in 3D. Each shape will be outlined with the current
   * stroke color and filled with the fill color.
   *
   * Transformations such as translate(), rotate(), and scale() do not work
   * within beginShape(). It is also not possible to use other shapes, such as
   * ellipse() or rect() within beginShape().
   *
   * @method beginShape
   * @param  {Number/Constant} kind either POINTS, LINES, TRIANGLES,
   *                                TRIANGLE_FAN, TRIANGLE_STRIP, QUADS,
   *                                or QUAD_STRIP
   * @return {Object}               the p5 object
   */
  p5.prototype.beginShape = function(kind) {
    if (kind === constants.POINTS ||
      kind === constants.LINES ||
      kind === constants.TRIANGLES ||
      kind === constants.TRIANGLE_FAN ||
      kind === constants.TRIANGLE_STRIP ||
      kind === constants.QUADS ||
      kind === constants.QUAD_STRIP) {
      this._shapeKind = kind;
    } else {
      this._shapeKind = null;
    }

    this._shapeInited = true;
    this._curElement.context.beginPath();

    return this;
  };

  /**
   * Specifies vertex coordinates for Bezier curves. Each call to
   * bezierVertex() defines the position of two control points and
   * one anchor point of a Bezier curve, adding a new segment to a
   * line or shape. The first time bezierVertex() is used within a
   * beginShape() call, it must be prefaced with a call to vertex()
   * to set the first anchor point. This function must be used between
   * beginShape() and endShape() and only when there is no MODE
   * parameter specified to beginShape().
   *
   * @method bezierVertex
   * @param  {Number} x2 x-coordinate for the first control point
   * @param  {Number} y2 y-coordinate for the first control point
   * @param  {Number} x3 x-coordinate for the second control point
   * @param  {Number} y3 y-coordinate for the second control point
   * @param  {Number} x4 x-coordinate for the anchor point
   * @param  {Number} y4 y-coordinate for the anchor point
   * @return {Object}    the p5 object
   */
  p5.prototype.bezierVertex = function(x2, y2, x3, y3, x4, y4) {
    if(this._contourInited) {
      var pt = {};
      pt.x = x2;
      pt.y = y2;
      pt.x3 = x3;
      pt.y3 = y3;
      pt.x4 = x4;
      pt.y4 = y4;
      pt.type = constants.BEZIER;
      this._contourVertices.push(pt);

      return this;
    }

    this._curElement.context.bezierCurveTo(x2, y2, x3, y3, x4, y4);

    return this;
  };

  p5.prototype.curveVertex = function(x,y) {
    var pt = {};
    pt.x = x;
    pt.y = y;
    this._curveVertices.push(pt);

    if(this._curveVertices.length >= 4) {
      this.curve(this._curveVertices[0].x,
                 this._curveVertices[0].y,
                 this._curveVertices[1].x,
                 this._curveVertices[1].y,
                 this._curveVertices[2].x,
                 this._curveVertices[2].y,
                 this._curveVertices[3].x,
                 this._curveVertices[3].y);
      this._curveVertices.shift();
    }

    return this;
  };

  /**
   * Use the beginContour() and endContour() function to create negative
   * shapes within shapes. For instance, the center of the letter 'O'.
   * beginContour() begins recording vertices for the shape and endContour()
   * stops recording. These functions can only be within a
   * beginShape()/endShape() pair and they only work with the P2D and P3D
   * renderers.
   *
   * @method endContour
   * @return {Object} the p5 object
   */
  p5.prototype.endContour = function() {
    //In order for the contour fill to work correctly, the inside points must
    // be drawn in the reverse order of the parents
    this._contourVertices.reverse();
    this._curElement.context.moveTo(
      this._contourVertices[0].x,
      this._contourVertices[0].y
    );
    var ctx = this._curElement.context;
    this._contourVertices.slice(1).forEach(function(pt, i) {
      switch(pt.type) {
      case constants.LINEAR:
        ctx.lineTo(pt.x,pt.y);
        break;
      case constants.QUADRATIC:
        ctx.quadraticCurveTo(pt.x, pt.y, pt.x3, pt.y3);
        break;
      case constants.BEZIER:
        ctx.bezierCurveTo(pt.x, pt.y, pt.x3, pt.y3, pt.x4, pt.y4);
        break;
      case constants.CURVE:
        //TODO: Curve... curve
        break;
      }
    });
    this._curElement.context.closePath();

    this._contourInited = false;

    return this;
  };

  /**
   * The endShape() function is the companion to beginShape() and may only be
   * called after beginShape(). When endshape() is called, all of image data
   * defined since the previous call to beginShape() is written into the image
   * buffer. The constant CLOSE as the value for the MODE parameter to close
   * the shape (to connect the beginning and the end).
   *
   * @method endShape
   * @param  {Number/Constant} mode use CLOSE to close the shape
   * @return {Object}               the p5 object
   */
  p5.prototype.endShape = function(mode) {
    if (mode === constants.CLOSE) {
      this._curElement.context.closePath();
      this._curElement.context.fill();
    }
    if (this._curveVertices.length <= 0) {
      this._curElement.context.stroke();
    } else {
      this._curveVertices = [];
    }

    return this;
  };

  /**
   * Specifies vertex coordinates for quadratic Bezier curves. Each call to
   * quadraticVertex() defines the position of one control points and one
   * anchor point of a Bezier curve, adding a new segment to a line or shape.
   * The first time quadraticVertex() is used within a beginShape() call, it
   * must be prefaced with a call to vertex() to set the first anchor point.
   * This function must be used between beginShape() and endShape() and only
   * when there is no MODE parameter specified to beginShape().
   *
   * @method quadraticVertex
   * @param  {Number} cx x-coordinate for the control point
   * @param  {Number} cy y-coordinate for the control point
   * @param  {Number} x3 x-coordinate for the anchor point
   * @param  {Number} y3 y-coordinate for the anchor point
   * @return {Object}    the p5 object
   */
  p5.prototype.quadraticVertex = function(cx, cy, x3, y3) {
    //if we're drawing a contour, put the points into an
    // array for inside drawing
    if(this._contourInited) {
      var pt = {};
      pt.x = cx;
      pt.y = cy;
      pt.x3 = x3;
      pt.y3 = y3;
      pt.type = constants.QUADRATIC;
      this._contourVertices.push(pt);

      return this;
    }

    this._curElement.context.quadraticCurveTo(cx, cy, x3, y3);

    return this;
  };

  /**
   * All shapes are constructed by connecting a series of vertices. vertex()
   * is used to specify the vertex coordinates for points, lines, triangles,
   * quads, and polygons. It is used exclusively within the beginShape() and
   * endShape() functions.
   *
   * @method vertex
   * @param  {Number} x x-coordinate of the vertex
   * @param  {Number} y y-coordinate of the vertex
   * @return {Object}   the p5 object
   */
  p5.prototype.vertex = function(x, y) {
    //if we're drawing a contour, put the points into an array for inside
    // drawing
    if(this._contourInited) {
      var pt = {};
      pt.x = x;
      pt.y = y;
      pt.type = constants.LINEAR;
      this._contourVertices.push(pt);

      return this;
    }

    if (this._shapeInited) {
      this._curElement.context.moveTo(x, y);
    } else {
      // pend this is where check for kind and do other stuff
      this._curElement.context.lineTo(x, y);
    }
    this._shapeInited = false;

    return this;
  };

  return p5;

});<|endoftext|>


<commit_before>/**
 * This module rappresent my personal utility, that i use to develop
 * my web sites
 *
 * @module dmUtil
 */
var dmUtil = dmUtil || {};
/**
 * Rappresent the globl object. In broswer enviroment is the window object
 *
 * @class global
 * @static
 *
 */
dmUtil.global = this;
/**
 * Rappresent the docuemnt DOM object
 *
 * @class doc
 * @static
 *
 */
dmUtil.doc = document;
/**
 * It's a collection of events utilities
 *
 * @class EventUtil
 * @static
 *
 */
dmUtil.EventUtil = {
    /**
     * This method is used in the addListener to create a specific id to
     * the envent. It's only an internal method
     *
     * @method getUniqueId
     * @private
     * @param {Object} element DOM element
     * @return {Integer} unique ID  of the element
     *
    */
    getUniqueId  : (function () {
        "use strict";
        if (typeof document.documentElement.uniqueID !== 'undefined') {
            return function (element) {
                return element.uniqueID;
            };
        }
        var uID = 0;
        return function (element) {
            return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uID++);
        };
    }()),
    /**
     * Check if the object has the specific method
     *
     *  @method isHostMethod
     *  @param {Object} obj An object
     *  @param {String} The name of the method we wanto to check
     *  @return {Boolean} True if the object has the method, false otherwise
     */
    isHostMethod: function (obj, methodName) {
        "use strict";
        var tp = typeof obj[methodName];
        return ((tp === 'function' || tp === 'object') && !!obj[methodName]) || tp === 'unknown';
    },
    /**
     * This method is used to format
     * the envent object so it's proprities are almost the same in all broswer.
     *
     * @method formatEvent
     * @param {Object} event Object
     * @return {Object} The event object
     *
    */
    formatEvent: function (evt) {
        "use strict";
        evt.charCode = (evt.type === "keypress") ? evt.keyCode : 0;
        evt.evntPhase = 2;
        evt.isChar = (evt.charCode > 0);
        evt.pageX = evt.clientX + dmUtil.doc.body.scrollLeft;
        evt.pageY = evt.clientY + dmUtil.doc.body.scrollTop;
        evt.preventDefault = function () {
            this.returnvalue = false;
        };
        switch (evt.type) {
        case "mouseout":
            evt.relatedTarget = evt.toElement;
            break;
        case "mouseover":
            evt.relatedTarget = evt.fromElement;
            break;
        default:
            break;
        }
        evt.stopPropagation = function () {
            this.cancelBubble = true;
        };
        evt.target = evt.srcElement;
        evt.time = (new Date()).getTime();

        return evt;
    }
};
/**
 * The object that handles the cross Broswer add and remove envent listeners
 *
 * @namespace EventUtil
 * @class aboutHandler
 * @static
 *
 */
dmUtil.EventUtil.aboutHandler = (function (){
        var docE=dmUtil.doc.documentElement;

        if(dmUtil.EventUtil.isHostMethod(docE,'addEventListener') &&
        dmUtil.EventUtil.isHostMethod(docE,'removeEventListener')){
            docE=null;
            return {
                /**
                 * This method add the event listener to a DOM object
                 *
                 * @method addListener
                 * @param {Object} element DOM element that handles the event
                 * @param {String} eventName The name of the event
                 * @param {String}[capture=false] If it's supported rappresent
                 * the bubbling fase.True=(down to up).False=(up to down).
                 * @return {Void}
                 */
                addListener : function(element,eventName,handler,capture){
                    element.addEventListener(eventName,handler,capture);
                },
                /**
                 * This method remove the event listener from a DOM object
                 *
                 * @method removeListener
                 * @param {Object} element DOM element that handles the event
                 * @param {String} eventName The name of the event
                 * @param {String}[capture=false] If it's supported rappresent
                 * the bubbling fase.True=(down to up).False=(up to down).
                 *  This value must be the same of that used in addListener.
                 * @return {Void}
                 */
                removeListener: function(element,eventName,handler,capture){
                    element.removeEventListener(eventName,handler,capture);
                }
            };
        } else if(dmUtil.EventUtil.isHostMethod(docE,'attachEvent')&&
        dmUtil.EventUtil.isHostMethod(docE,'deatachEvent')){

            var eventListeners={},elements={},
            getElement = function(uid){
                return elements[uid];
            },
            setElement=function(uid,element){
                elements[uid]=element;
            },
            createListener=function(uid,handler){
                return {
                    handler: handler,
                    wrapperHandeler: wrapper(uid,handler)
                };
            },
            wrapper = function(uid,handler){
                if(handler.handlerEvent){
                    return function(e){
                        handler.handlerEvent(e);
                    };
                } else {
                    return function(e){
                        handler.call(getElement(uid),
                        dmUtil.formatEvent(e || dmUtil.global.event));
                    };
                }
            };
            docE=null;
            return{
                addListener : function(element,eventName,handler){
                    var uid = dmUtil.EventUtil.getUniqueId(element);
                    setElement(uid,element);
                    if(!eventListeners[uid]){
                        eventListeners[uid]={};
                    }
                    if(!eventListeners[uid][eventName]){
                        eventListeners[uid][eventName]=[];
                    }
                    var listener=createListener(uid,handler);
                    eventListeners[uid][eventName].push(listener);
                    element.attachEvent('on'+eventName,listener.wrapperHandeler);
                },
                removeListener: function(element,eventName,handler){
                    var uid =getUniqueId(element),listener;
                    if(eventListeners[uid] && eventListeners[uid][eventName]){
                        var i=eventListeners[uid][eventName].length -1;
                        do{
                            listener=eventListeners[uid][eventName][i];
                            if(listener && listener.handler ===handler){
                                element.deatachEvent('on'+eventName,listener.wrapperHandeler);
                                eventListeners[uid][eventName][i]=null;
                            }
                        } while(i--);
                    }
                }
            };
        } else {
            docE=null;
            var createDispatcher=function(uid,eventName){
                return function(e){
                    if(handlers[uid]&&handlers[uid][eventName]){
                        var handlersForEvent =handlers[uid][eventName];
                        for(var i=0,len=handlersForEvent.length; i<len;i++){
                            handlersForEvent[i].call(this, e || dmUtil.global.event);
                        }
                    }
                };
            };
            var handlers ={};
            return {
                addListener: function(element,eventName,handler){
                    var uid=dmUtil.EventUtil.getUniqueId(element);
                    if(!handlers[uid]){
                        handlers[uid]={};
                    }
                    if(!handler[uid][eventName]){
                        handlers[uid][eventName]=[];
                        var existingHandler=element['on'+eventName];
                        if(existingHandler){
                            handlers[uid][eventName].push(existingHandler);
                        }
                        element['on'+eventName]=createDispatcher(uid,eventName);
                    }
                    handlers[uid][eventName].push(handler);
                },
                removeListener: function(element,eventName,handler){
                    var uid=dmUtil.EventUtil.getUniqueId(element);
                    if(handlers[uid]&&handlers[uid][eventName]){
                        var handlersForEvent=handlerEvent[uid][eventName];
                        var i=handlersForEvent.length-1;
                        do{
                            if(handlerEvent[i]===handler){
                                handlersForEvent.splice(i,1);
                            }
                        } while(i--);
                    }
                }
            };
        }
})();
dmUtil.stringUtil ={
    trim : (function(){
        var reTrimTop=/^\s+/,reTrimBottom=/\s\s*$/;
        return function(str){
            return str.replace(reTrimTop,"").replace(reTrimBottom,"");
        };
    })(),
    stripHtml :(function(){
        var stripReg = /<(?=((?:.|\s)*?>))\1/g;
        return function(str){
            return str.replace(stripReg,"");
        };
    })()
};
dmUtil.arrayUtil={
    IndexOf: (function(){
        if(!Array.prototype.indexOf){
            return function(arr,ele,fromIndex){
                if(arr === null){
                    return -1;
                }
                var k,O=Object(arr);
                var len= O.length >>> 0;

                if(len === 0){
                    return -1;
                }
                var n=+fromIndex || 0;
                if(n >= len){
                    return -1;
                }
                k = Math.max(n>=0? n: len + n,0);
                do{
                    if(k in O && O[k] === ele){
                        return  k;
                    }
                    k++;
                } while(k<len);

                return -1;
            };
        } else {
            return function(arr,ele,fromIndex){
                return arr.indexOf(ele,fromIndex);
            };
        }

    })()
};
dmUtil.classList = (function(){
    if(!("classList" in document.createElement("_"))){
        var checkTokenAndGetIndex=function(classList,token){
            if(token ===""){
                return -2;
            }
            if(/s/.test(token)){
                return -3;
            }
            return dmUtil.arrayUtil.IndexOf(classList,token);
        }
        ,classList =function(elem){
            var trimmedClasses = dmUtil.stringUtil.trim(elem.getAttribute("class")|| "")
            ,classes = trimmedClasses?trimmedClasses.split(/s+/): []
            ,i=0
            ,len =classes.length;
            for(;i<len;i++){
                this.push(classes[i]);
            }
            this._updateClassName = function(){
                elem.setAttribute("class",this.toString());
            };
        }
        ,classListProto=classList.prototype = [];
        classListProto.item = function(i){
            return this[i] || null;
        };
        classListProto.contains = function(token){
            token += "";
            return checkTokenAndGetIndex(this,token) !== -1;
        };
        classListProto.add = function(){
            var tokens = arguments
            ,i=0
            ,l=tokens.length
            ,token
            ,update = false;
            do{
                token= tokens[i]+ "";
                if(checkTokenAndGetIndex(this,token)===-1){
                    this.push(token);
                    update=true;
                }
            }while(i++<l);
            if(update){
                this._updateClassName();
            }
        };
        classListProto.remove=function(){
            var tokens=arguments
            ,i=0
            ,l=tokens.length
            ,token
            ,update=false
            ,index;
            do{
                token =tokens[i]+ "";
                index=checkTokenAndGetIndex(this,token);
                while(index!==-1){
                    this.split(index,1);
                    update=true;
                    index=checkTokenAndGetIndex(this,token);
                }
            }while(++i<l);
            if(update){
                this._updateClassName();
            }
        };
        classListProto.toggle=function(token,force){
            token += "";
            var result = this.contains(token)
            ,method = result?
                force !== true && "remove"
            :
                force !==false && "add";
            if(method){
                this[method](token);
            }
            if(force===true || force ===false){
                return force;
            } else {
                return !result;
            }
        };
        classListProto.toString=function(){
            return this.join(" ");
        };
        return function(ele){
            return new classList(ele);
        };
    } else {
        var testElement = dmUtil.doc.createElement("_");
        testElement.classList.add("c1","c2");
        if(!testElement.classList.contains("c2")){
            var createMethod=function(method){
                var original=DOMTokenList.prototype[method];
                DOMTokenList.prototype[method]=function(token){
                    var i,len=arguments.length;
                    for(i=0;i<len;i++){
                        token=arguments[i];
                        original.call(this,token);
                    }
                };
            };
            createElement("add");
            createElement("remove");
        }
        testElement.classList.toggle("c3",false);
        if(testElement.classList.contains("c3")){
            var _toggle=DOMTokenList.prototype.toggle;
            DOMTokenList.prototype.toggle=function(token,force){
                if(1 in arguments && !this.contains(token)=== !force){
                    return force;
                }else{
                    return _toggle.call(this,token);
                }
            };
        }
        testElement =null;

        return function(ele){
            return ele.classList;
        };
    }
})();
dmUtil.animation={
    Frame: (function(){
        var lastTime=0;
        var vendors=['webkit','moz'];
        var testExistence = dmUtil.global.requestAnimationFrame;
        for(var x=vendors.length;--x && !testExistence;){
            testExistence=dmUtil.global[vendors[x]+'RequestAnimationFrame'];
        }

    })()
};
<commit_msg>Add YUIDoc Comment<commit_after>/**
 * This module rappresent my personal utility, that i use to develop
 * my web sites
 *
 * @module dmUtil
 */
var dmUtil = dmUtil || {};
/**
 * Rappresent the globl object. In broswer enviroment is the window object
 *
 *
 * @class global
 * @static
 *
 */
dmUtil.global = this;
/**
 * Rappresent the docuemnt DOM object
 *
 * @class doc
 * @static
 *
 */
dmUtil.doc = document;
/**
 * It's a collection of events utilities
 *
 * @class EventUtil
 * @static
 *
 */
dmUtil.EventUtil = {
    /**
     * This method is used in the addListener to create a specific id to
     * the envent. It's only an internal method
     *
     * @method getUniqueId
     * @private
     * @param {Object} element DOM element
     * @return {Integer} unique ID  of the element
     *
    */
    getUniqueId  : (function () {
        "use strict";
        if (typeof document.documentElement.uniqueID !== 'undefined') {
            return function getUniqueId(element) {
                return element.uniqueID;
            };
        }
        var uID = 0;
        return function getUniqueId(element) {
            return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uID++);
        };
    }()),
    /**
     * Check if the object has the specific method
     *
     *  @method isHostMethod
     *  @param {Object} obj An object
     *  @param {String} method The name of the method we wanto to check
     *  @return {Boolean} True if the object has the method, false otherwise
     */
    isHostMethod: function isHostMethod(obj, methodName) {
        "use strict";
        var tp = typeof obj[methodName];
        return ((tp === 'function' || tp === 'object') && !!obj[methodName]) || tp === 'unknown';
    },
    /**
     * This method is used to format
     * the envent object so it's proprities are almost the same in all broswer.
     *
     * @method formatEvent
     * @param {Object} event Object
     * @return {Object} The event object
     *
    */
    formatEvent: function formatEvent(evt) {
        "use strict";
        evt.charCode = (evt.type === "keypress") ? evt.keyCode : 0;
        evt.evntPhase = 2;
        evt.isChar = (evt.charCode > 0);
        evt.pageX = evt.clientX + dmUtil.doc.body.scrollLeft;
        evt.pageY = evt.clientY + dmUtil.doc.body.scrollTop;
        evt.preventDefault = function () {
            this.returnvalue = false;
        };
        switch (evt.type) {
        case "mouseout":
            evt.relatedTarget = evt.toElement;
            break;
        case "mouseover":
            evt.relatedTarget = evt.fromElement;
            break;
        default:
            break;
        }
        evt.stopPropagation = function () {
            this.cancelBubble = true;
        };
        evt.target = evt.srcElement;
        evt.time = (new Date()).getTime();

        return evt;
    },
     /**
    * The object that handles the cross Broswer add and remove envent listeners
    *
    *
    * @property aboutHandler
    * @type Class
    * @static
    * @final
    *
    */

    /**
    * The object that handles the cross Broswer add and remove envent listeners
    *
    *
    * @class aboutHandler
    * @static
    * @for EventUtil
    *
    */

    aboutHandler: (function () {
    "use strict";

    var docE = dmUtil.doc.documentElement;

    if (dmUtil.EventUtil.isHostMethod(docE, 'addEventListener') && dmUtil.EventUtil.isHostMethod(docE, 'removeEventListener')) {
        docE = null;
        return {
            /**
            * This method add the event listener to a DOM object
            *
            * @method addListener
            * @for aboutHandler
            * @param {Object} element DOM element that handles the event
            * @param {String} eventName The name of the event
            * @param {Boolean}[capture=false] If it's supported rappresent
            * the bubbling fase.True=(down to up).False=(up to down).
            * @return {Void}
            */
            addListener : function addListener(element, eventName, handler, capture) {
                element.addEventListener(eventName, handler, capture);
            },
            /**
            * This method remove the event listener from a DOM object
            *
            *
            * @method removeListener
            * @for aboutHandler
            * @param {Object} element DOM element that handles the event
            * @param {String} eventName The name of the event
            * @param {Boolean}[capture=false] If it's supported rappresent
            * the bubbling fase.True=(down to up).False=(up to down).
            *  This value must be the same of that used in addListener.
            * @return {Void}
            *
            */
            removeListener: function removeListener(element, eventName, handler, capture) {
                element.removeEventListener(eventName, handler, capture);
            }
        };
    } else if (dmUtil.EventUtil.isHostMethod(docE, 'attachEvent') && dmUtil.EventUtil.isHostMethod(docE, 'deatachEvent')) {

        var eventListeners = {}
        ,elements = {}
        ,getElement = function (uid) {
            return elements[uid];
        }
        ,setElement = function (uid, element) {
            elements[uid] = element;
        }
        ,wrapper = function (uid, handler) {
            if (handler.handlerEvent) {
                return function (e) {
                    handler.handlerEvent(e);
                };
            } else {
                return function (e) {
                    handler.call(getElement(uid), dmUtil.formatEvent(e || dmUtil.global.event));
                };
            }
        }
        ,createListener = function (uid, handler) {
            return {
                handler: handler,
                wrapperHandeler: wrapper(uid, handler)
            };
        };
        docE = null;
        return {
            addListener : function addListener(element, eventName, handler) {
                var uid = dmUtil.EventUtil.getUniqueId(element);
                setElement(uid, element);
                if (!eventListeners[uid]) {
                    eventListeners[uid] = {};
                }
                if (!eventListeners[uid][eventName]) {
                    eventListeners[uid][eventName] = [];
                }
                var listener = createListener(uid, handler);
                eventListeners[uid][eventName].push(listener);
                element.attachEvent('on' + eventName, listener.wrapperHandeler);
            },
            removeListener: function removeListener(element, eventName, handler) {
                var uid = dmUtil.EventUtil.getUniqueId(element), listener;
                if (eventListeners[uid] && eventListeners[uid][eventName]) {
                    var i = eventListeners[uid][eventName].length - 1;
                    do {
                        listener = eventListeners[uid][eventName][i];
                        if (listener && listener.handler === handler) {
                            element.deatachEvent('on' + eventName, listener.wrapperHandeler);
                            eventListeners[uid][eventName][i] = null;
                        }
                    } while (i--);
                }
            }
        };
    } else {
        docE = null;
        var handlers = {};
        var createDispatcher = function (uid, eventName) {
            return function (e) {
                if (handlers[uid] && handlers[uid][eventName]) {
                    var handlersForEvent = handlers[uid][eventName];
                    var i, len;
                    for (i = 0, len = handlersForEvent.length; i < len; i++) {
                        handlersForEvent[i].call(this, e || dmUtil.global.event);
                    }
                }
            };
        };
        return {
            addListener: function addListener(element, eventName, handler) {
                var uid = dmUtil.EventUtil.getUniqueId(element);
                if (!handlers[uid]) {
                    handlers[uid] = {};
                }
                if (!handler[uid][eventName]) {
                    handlers[uid][eventName] = [];
                    var existingHandler = element['on' + eventName];
                    if (existingHandler) {
                        handlers[uid][eventName].push(existingHandler);
                    }
                    element['on' + eventName] = createDispatcher(uid, eventName);
                }
                handlers[uid][eventName].push(handler);
            },
            removeListener: function removeListener(element, eventName, handler) {
                var uid = dmUtil.EventUtil.getUniqueId(element);
                if (handlers[uid] && handlers[uid][eventName]) {
                    var handlersForEvent = handlerEvent[uid][eventName];
                    var i = handlersForEvent.length - 1;
                    do {
                        if (handlersForEvent[i] === handler) {
                            handlersForEvent.splice(i, 1);
                        }
                    } while (i--);
                }
            }
        };
    }
}())
};
/**
 * It's a collection of string utilities
 *
 *
 * @class StringUtil
 * @static
 *
 */

dmUtil.stringUtil ={
    /**
     * The trim(str) function removes whitespace from both sides of a string
     *
     *  @method trim
     *  @param {String} str A string
     *  @return {String} String without top and bottom white space
     */
    trim : (function(){
        "use strict";
        var reTrimTop = /^\s+/, reTrimBottom = /\s\s*$/;
        return function trim(str) {
            return str.replace(reTrimTop, "").replace(reTrimBottom, "");
        };
    }()),
    /**
     * The stripHtml(str) function strip html tags
     *
     *  @method stripHtml
     *  @param {String} str A string
     *  @return {String}
     */
    stripHtml :(function () {
        "use strict";
        var stripReg = /<(?=((?:.|\s)*?>))\1/g;
        return function stripHtml(str) {
            return str.replace(stripReg, "");
        };
    }())
};
/**
 * It's a collection of array utilities
 *
 *
 * @class ArrayUtil
 * @static
 *
 */
dmUtil.arrayUtil={
    /**
     * The IndexOf(arr,ele,fromIndex) function return the index of the element in the array.
     *
     *  @method IndexOf
     *  @param {Array} arr An array
     *  @param{Object} obj The element of the Array
     *  @param{Integer} index The index from with begin the count
     *  @return {Integer} The index of the element in the array
     */
    IndexOf: (function () {
        "use strict";
        if (!Array.prototype.indexOf) {
            return function indexOf(arr, ele, fromIndex) {
                if(arr === null){
                    return -1;
                }
                var k , O = Object.create(arr);
                var len = (O.length >>> 0);

                if (len === 0) {
                    return - 1;
                }
                var n =+ fromIndex || 0;
                if (n >= len) {
                    return - 1;
                }
                k = Math.max(n >= 0 ? n : len + n, 0);
                do {
                    if (O.hasOwnProperty(k) && O[k] === ele) {
                        return  k;
                    }
                    k++;
                } while(k < len);

                return - 1;
            };
        } else {
            return function(arr, ele, fromIndex){
                return arr.indexOf(ele, fromIndex);
            };
        }

    }()),
    /**
     * The isArray(obj) check if an object is an array.
     *
     *  @method isArray
     *  @param {Object} obj An Object
     *  @return {Boolean} True if the Object is an Array false if not.
     */
    isArray: (function () {
        "use strict";
        if(typeof Array.isArray === 'undefined') {
            return function isArray (arg) {
                return Object.prototype.toString.call(arg) === "[Object Array]";
            };
        } else {
            return Array.isArray;
        }
    }())
};
/**
 * It's a cross broswer compatible class List function. You don't need to use new in the
 * constructor, simple call the function and you'll have a cass list object.
 *
 *
 * @class classList
 * @constructor
 * @parem{Element} ele Rappresent the DOM element of which create the class list
 *
 */
dmUtil.classList = (function(){
    "use strict";
    if (!("classList" in document.createElement("_"))) {
        var checkTokenAndGetIndex=function (classList, token) {
            if(token === ""){
                return -2;
            }
            if(/s/.test(token)){
                return -3;
            }
            return dmUtil.arrayUtil.IndexOf(classList, token);
        }
        ,classList =function (elem) {
            var trimmedClasses = dmUtil.stringUtil.trim(elem.getAttribute("class") || "")
            ,classes = trimmedClasses ? trimmedClasses.split(/s+/): []
            ,i = 0
            ,len = classes.length;
            for(; i < len; i++){
                this.push(classes[i]);
            }
            this._updateClassName = function () {
                elem.setAttribute("class",this.toString());
            };
        }
        ,classListProto=classList.prototype = [];
        classListProto.item = function (i) {
            return this[i] || null;
        };
        /**
        * Checks if an element's list of classes contains a specific class
        *
        *  @method contains
        *  @param {String} token The name of a class
        *  @return {Boolean} True if the class is in the list false otherwise
        */
        classListProto.contains = function (token) {
            token += "";
            return checkTokenAndGetIndex(this,token) !== -1;
        };
        /**
        * Adds a class to an element's list of classes.
        * If class already exists in the element's list of classes,
        * it will not add the class again
        *
        *  @method add
        *  @param {String} token The name of  a class. The param can be more than one
        *  @return {Void}
        */
        classListProto.add = function () {
            var tokens = arguments
            ,i = 0
            ,l = tokens.length
            ,token
            ,update = false;
            do {
                token = tokens[i] + "";
                if (checkTokenAndGetIndex(this,token) === -1) {
                    this.push(token);
                    update = true;
                }
            } while(i++ < l);
            if(update){
                this._updateClassName();
            }
        };
         /**
        *  Removes a class from an element's list of classes.
        *  If class does not exist in the element's list of classes,
        *  it will not throw an error or exception
        *
        *  @method remove
        *  @param {String} token The name of  a class. The param can be more than one
        *  @return {Void}
        */
        classListProto.remove=function(){
            var tokens = arguments
            ,i = 0
            ,l = tokens.length
            ,token
            ,update = false
            ,index;
            do{
                token = tokens[i] + "";
                index=checkTokenAndGetIndex(this, token);
                while (index !== -1) {
                    this.split(index, 1);
                    update = true;
                    index = checkTokenAndGetIndex(this,token);
                }
            } while(++i < l);
            if (update) {
                this._updateClassName();
            }
        };
         /**
        * Toggles the existence of a class in an element's list of classes.
        * The second argument will force the class name to be added or removed based
        * on the truthiness of the second argument:
        *   true  -> add
        *   false -> remove
        *
        *  @method toggle
        *  @param {String} token The name of  a class. The param can be more than one
        *  @param {Boolean} force True add the class, false remove the class
        *  @return {Boolean} return second argument
        */
        classListProto.toggle=function(token, force){
            token += "";
            var result = this.contains(token)
            ,method = result ?
                force !== true && "remove"
            :
                force !== false && "add";
            if(method){
                this[method](token);
            }
            if(force === true || force ===false){
                return force;
            } else {
                return !result;
            }
        };
        classListProto.toString=function(){
            return this.join(" ");
        };
        return function (ele){
            return new classList(ele);
        };
    } else {
        var testElement = dmUtil.doc.createElement("_");
        testElement.classList.add("c1","c2");
        if (!testElement.classList.contains("c2")) {
            var createMethod = function(method){
                var original = DOMTokenList.prototype[method];
                DOMTokenList.prototype[method] = function (token) {
                    var i,len = arguments.length;
                    for(i=0;i<len;i++){
                        token = arguments[i];
                        original.call(this,token);
                    }
                };
            };
            createElement("add");
            createElement("remove");
        }
        testElement.classList.toggle("c3", false);
        if(testElement.classList.contains("c3")){
            var _toggle = DOMTokenList.prototype.toggle;
            DOMTokenList.prototype.toggle = function(token, force){
                if (1 in arguments && !this.contains(token) === !force) {
                    return force;
                } else {
                    return _toggle.call(this,token);
                }
            };
        }
        testElement =null;

        return function(ele){
            return ele.classList;
        };
    }
}());
dmUtil.animation={
    Frame: (function(){
        var lastTime=0;
        var vendors=['webkit','moz'];
        var testExistence = dmUtil.global.requestAnimationFrame;
        for(var x=vendors.length;--x && !testExistence;){
            testExistence=dmUtil.global[vendors[x]+'RequestAnimationFrame'];
        }

    })()
};
<|endoftext|>


<commit_before>require('whatwg-fetch')
require('babel-polyfill')
/*
TODO
make a single pause/unpause button
textbox for the number of minutes until the timer goes off
timer textbox is only a textbox when timer is paused, otherwise paragraph element or similar
alert when timer goes off
notification when timer goes off
Done? Put up on heroku
blog about it
*/

const
    R = require('ramda'),
    Rx = require('rx'),
    tap = x => { console.log(x); return x },
    React = require('react'),
    ReactDOM = require('react-dom'),
    {createStore, applyMiddleware} = require('redux'),
    {default: createSagaMiddleware, takeEvery, effects: {put, call}} = require('redux-saga'),
    sagaMiddleware = createSagaMiddleware(),
    reducer = (state = {time: 0, paused: true}, action) => {
        switch(action.type) {
            case 'INCREMENT':
                return {
                    time: (state.time + 1) % 26
                }
            case 'STARTED_RESUMED':
                return {
                    ...state,
                    paused: false
                }
            case 'PAUSED':
                return {
                    ...state,
                    paused: true
                }
            default:
                return state
        }
    },
    store = createStore(reducer, applyMiddleware(sagaMiddleware)),
    timer = Rx.Observable.interval(1000).pausable(new Rx.Subject()),
    notificationSaga = function* (action) {
        alert(action.notification)
        yield put({type: 'NOTIFIED'})
    },
    timerSaga = function* (action) {
        if(action.type === 'START_RESUME' && store.getState().paused) {
            timer.resume()
            yield put({type: 'STARTED_RESUMED'})
        } else if(action.type === 'PAUSE' && !store.getState().paused) {
            timer.pause()
            yield put({type: 'PAUSED'})
        }
    },
    rootSaga = function* () {
        yield takeEvery('NOTIFICATION', notificationSaga)
        yield takeEvery('START_RESUME', timerSaga)
        yield takeEvery('PAUSE', timerSaga)
    },
    render = () =>
        ReactDOM.render(

{store.getState().time}

                <button
                    onClick={() => store.dispatch({
                        type: 'NOTIFICATION',
                        notification: 'I\'ve put you on notice!'
                    })}
                    type="button">
                        notify
                </button>
                <button
                    onClick={() => store.dispatch({
                        type: 'START_RESUME'
                    })}
                    type="button">
                        Start/Resume
                </button>
                <button
                    onClick={() => store.dispatch({
                        type: 'PAUSE'
                    })}
                    type="button">
                        Pause
                </button>

,
            document.getElementById('root'))

sagaMiddleware.run(rootSaga)
store.subscribe(render)
timer.subscribe(() => store.dispatch({type: 'INCREMENT'}))
render()
<commit_msg>added notes<commit_after>require('whatwg-fetch')
require('babel-polyfill')
/*
TODO
make a single pause/unpause button
textbox for the number of minutes until the timer goes off
timer textbox is only a textbox when timer is paused, otherwise paragraph element or similar
format into minutes and seconds
alert when timer goes off
notification when timer goes off
Done? Put up on heroku
blog about it
*/

const
    R = require('ramda'),
    Rx = require('rx'),
    tap = x => { console.log(x); return x },
    React = require('react'),
    ReactDOM = require('react-dom'),
    {createStore, applyMiddleware} = require('redux'),
    {default: createSagaMiddleware, takeEvery, effects: {put, call}} = require('redux-saga'),
    sagaMiddleware = createSagaMiddleware(),
    reducer = (state = {time: 0, paused: true}, action) => {
        switch(action.type) {
            case 'INCREMENT':
                return {
                    time: (state.time + 1) % 26
                }
            case 'STARTED_RESUMED':
                return {
                    ...state,
                    paused: false
                }
            case 'PAUSED':
                return {
                    ...state,
                    paused: true
                }
            default:
                return state
        }
    },
    store = createStore(reducer, applyMiddleware(sagaMiddleware)),
    timer = Rx.Observable.interval(1000).pausable(new Rx.Subject()),
    notificationSaga = function* (action) {
        alert(action.notification)
        yield put({type: 'NOTIFIED'})
    },
    timerSaga = function* (action) {
        if(action.type === 'START_RESUME' && store.getState().paused) {
            timer.resume()
            yield put({type: 'STARTED_RESUMED'})
        } else if(action.type === 'PAUSE' && !store.getState().paused) {
            timer.pause()
            yield put({type: 'PAUSED'})
        }
    },
    rootSaga = function* () {
        yield takeEvery('NOTIFICATION', notificationSaga)
        yield takeEvery('START_RESUME', timerSaga)
        yield takeEvery('PAUSE', timerSaga)
    },
    render = () =>
        ReactDOM.render(

{store.getState().time}

                <button
                    onClick={() => store.dispatch({
                        type: 'NOTIFICATION',
                        notification: 'I\'ve put you on notice!'
                    })}
                    type="button">
                        notify
                </button>
                <button
                    onClick={() => store.dispatch({
                        type: 'START_RESUME'
                    })}
                    type="button">
                        Start/Resume
                </button>
                <button
                    onClick={() => store.dispatch({
                        type: 'PAUSE'
                    })}
                    type="button">
                        Pause
                </button>

,
            document.getElementById('root'))

sagaMiddleware.run(rootSaga)
store.subscribe(render)
timer.subscribe(() => store.dispatch({type: 'INCREMENT'}))
render()
<|endoftext|>


<commit_before>/**
 * Bootstrap
 * (sails.config.bootstrap)
 *
 * An asynchronous bootstrap function that runs before your Sails app gets lifted.
 * This gives you an opportunity to set up your data model, run jobs, or perform some special logic.
 *
 * For more information on bootstrapping your app, check out:
 * http://sailsjs.org/#!/documentation/reference/sails.config/sails.config.bootstrap.html
 */

module.exports.bootstrap = function(cb) {

  //need this otherwise won't return
  cb();
};
<commit_msg>disabled bluebird warning<commit_after>/**
 * Bootstrap
 * (sails.config.bootstrap)
 *
 * An asynchronous bootstrap function that runs before your Sails app gets lifted.
 * This gives you an opportunity to set up your data model, run jobs, or perform some special logic.
 */

const Promise = require('sequelize').Promise;

module.exports.bootstrap = function(cb) {

  //bluebird promises
  Promise.config({
      warnings: false,
  });

  //need this otherwise won't return
  cb();
};
<|endoftext|>


<commit_before>/**
 * scrolling.js
 * @author      Marc-André Appel <marcandre.appel@gmail.com>
 * @copyright   2015 Sudimage Communication
 * @link        http://www.lastoctoberday.com
 * @licence     http://opensource.org/licenses/MIT MIT
 */

(function ($) {
    "use strict";
    var scrolling = {
        currentPosition: 0,
        scrollDirection: 'down',
        run: function () {
            var scrollPos = $('html').scrollTop() || $('body').scrollTop();

            if (scrollPos > scrolling.currentPosition) {
                scrolling.scrollDirection = 'down';
            } else {
                scrolling.scrollDirection = 'up';
            }
            scrolling.currentPosition = scrollPos;
            scrolling.toggle();
        },
        toggle: function () {
            if (scrolling.scrollDirection === 'down' && $('body').hasClass('scrolling-up')) {
                $('body')
                    .removeClass('scrolling-up')
                    .addClass('scrolling-down');
            } else if (scrolling.scrollDirection === 'up' && $('body').hasClass('scrolling-down')) {
                $('body')
                    .removeClass('scrolling-down')
                    .addClass('scrolling-up');
            }
        },
        init: function () {
            $('body').addClass('scrolling-' + scrolling.scrollDirection);
        }
    };

    function Scrolling() {
        $(document).scroll(function () {
            scrolling.run();
        });
        return this;
    }

    Scrolling.prototype.position = function () {
        return scrolling.currentPosition;
    };

    Scrolling.prototype.direction = function () {
        return scrolling.scrollDirection;
    };

    window.Scrolling = new Scrolling();
})(jQuery);
<commit_msg>Release of v1.0.0<commit_after>/**
 * jquery.scrolling.js
 * @author      Marc-André Appel <marcandre.appel@gmail.com>
 * @copyright   2015 Sudimage Communication
 * @link        http://www.lastoctoberday.com
 * @licence     http://opensource.org/licenses/MIT MIT
 * @version     1.0.0
 */

(function ($) {
    "use strict";
    var scrolling = {
        currentPosition: 0,
        scrollDirection: 'down',
        run: function () {
            var scrollPos = $('html').scrollTop() || $('body').scrollTop();

            if (scrollPos > scrolling.currentPosition) {
                scrolling.scrollDirection = 'down';
            } else {
                scrolling.scrollDirection = 'up';
            }
            scrolling.currentPosition = scrollPos;
            scrolling.toggle();
        },
        toggle: function () {
            if (scrolling.scrollDirection === 'down' && $('body').hasClass('scrolling-up')) {
                $('body')
                    .removeClass('scrolling-up')
                    .addClass('scrolling-down');
            } else if (scrolling.scrollDirection === 'up' && $('body').hasClass('scrolling-down')) {
                $('body')
                    .removeClass('scrolling-down')
                    .addClass('scrolling-up');
            }
        },
        init: function () {
            $('body').addClass('scrolling-' + scrolling.scrollDirection);
        }
    };

    function Scrolling() {
        $(document).scroll(function () {
            scrolling.run();
        });
        return this;
    }

    Scrolling.prototype.position = function () {
        return scrolling.currentPosition;
    };

    Scrolling.prototype.direction = function () {
        return scrolling.scrollDirection;
    };

    window.Scrolling = new Scrolling();
})(jQuery);
<|endoftext|>


<commit_before>'use strict';

var httpProxy = require('http-proxy')
global.$proxy

module.exports.bootstrap = function bootstrap(next) {
    /**
     * It's very important to trigger this 'next' method when you are finished with the bootstrap!
     * (otherwise your server will never lift, since it's waiting on the bootstrap)
     */
    sails.services.passport.loadStrategies();
    global.$proxy = httpProxy.createProxyServer({});

    global.$proxy.on('proxyRes', function (proxyRes, req, res) {
        console.log('RAW Response from the target', {
            headers : proxyRes.headers,
            statusCode : proxyRes.statusCode,
        });
    });

    next();
};
<commit_msg>removed http-proxy initialization<commit_after>'use strict';

//var httpProxy = require('http-proxy')
//global.$proxy

module.exports.bootstrap = function bootstrap(next) {
    /**
     * It's very important to trigger this 'next' method when you are finished with the bootstrap!
     * (otherwise your server will never lift, since it's waiting on the bootstrap)
     */
    sails.services.passport.loadStrategies();
    //global.$proxy = httpProxy.createProxyServer({});
    //
    //global.$proxy.on('proxyRes', function (proxyRes, req, res) {
    //    console.log('RAW Response from the target', {
    //        headers : proxyRes.headers,
    //        statusCode : proxyRes.statusCode,
    //    });
    //});

    next();
};
<|endoftext|>