<commit_before>/*! jсarouselSwipe - v0.3.4 - 2016-02-18
* Copyright (c) 2015 Evgeniy Pelmenev; Licensed MIT */
(function($) {
    'use strict';

    $.jCarousel.plugin('jcarouselSwipe', {
        _options: {
            perSwipe: 1,
            draggable: true,
            method: 'scroll'
        },
        _init: function() {
            var self = this;
            this.carousel().on('jcarousel:reloadend', function() {
                self._reload();
            });
        },
        _create: function() {
            this._instance = this.carousel().data('jcarousel');
            this._instance._element.css('touch-action', (!this._instance.vertical ? 'pan-y' : 'pan-x'));
            this._carouselOffset = this.carousel().offset()[this._instance.lt] + parseInt(this.carousel().css((!this._instance.vertical ? 'border-left-width' : 'border-top-width'))) + parseInt(this.carousel().css((!this._instance.vertical ? 'padding-left' : 'padding-top')));
            this._slidesCount = this._instance.items().length;
            this.carousel().find('img, a')
                .attr('draggable', false)
                .css('user-select', 'none')
                .on('dragstart', function(event) { event.preventDefault() });

            this._destroy();

            if (this._instance.items().length > this._instance.fullyvisible().length) {
                this._initGestures();
            }
        },
        _initGestures: function() {
            var self = this;
            var startTouch = {};
            var currentTouch = {};
            var started = false;
            var animated = false;
            var xKey = !this._instance.vertical ? 'x' : 'y';
            var yKey = !this._instance.vertical ? 'y' : 'x';
            var edgeLT, lastItem;
            var startTarget;

            this._element.on('touchstart.jcarouselSwipe mousedown.jcarouselSwipe', dragStart);

            function dragStart(event) {
                event = event.originalEvent || event || window.event;
                startTouch = getTouches(event);
                startTarget = event.target || event.srcElement;

                if (self._options.draggable) {
                    $(document).on('touchmove.jcarouselSwipe mousemove.jcarouselSwipe', dragMove);
                }
                $(document).on('touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe', dragEnd);
            }

            function dragMove(event) {
                var delta, newLT, itemsOption;
                event = event.originalEvent || event || window.event;
                currentTouch = getTouches(event);

                if (started) {
                    event.preventDefault();
                }

                if (Math.abs(startTouch[yKey] - currentTouch[yKey]) > 10 && !started) {
                    $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe');
                    return;
                }

                if (!animated && Math.abs(startTouch[xKey] - currentTouch[xKey]) > 10) {
                    delta = startTouch[xKey] - currentTouch[xKey];

                    if (!started) {
                        started = true;
                        self._addClones();
                        self._currentLT = self._getListPosition();
                        itemsOption = self._instance.options('items');
                        lastItem = ($.isFunction(itemsOption) ? itemsOption.call(self._instance) : self._instance.list().find(itemsOption)).last();
                        edgeLT = self._instance.rtl && !self._instance.vertical ?
                            (self._instance.dimension(self._instance.list()) - lastItem.position()[self._instance.lt] - self._instance.clipping()) :
                            (lastItem.position()[self._instance.lt] + self._instance.dimension(lastItem) - self._instance.clipping()) * -1;
                    }

                    if (self._instance._options.wrap === 'circular') {
                        newLT = self._currentLT - delta;
                    } else if (self._instance.rtl && !self._instance.vertical) {
                        newLT = Math.max(0, Math.min(self._currentLT - delta, edgeLT));
                    } else {
                        newLT = Math.min(0, Math.max(self._currentLT - delta, edgeLT));
                    }

                    self._setListPosition(newLT + 'px');
                }
            }

            function dragEnd(event) {
                event = event.originalEvent || event || window.event;
                currentTouch = getTouches(event);
                if (started || (!self._options.draggable && Math.abs(startTouch[xKey] - currentTouch[xKey]) > 10)) {
                    var newTarget = self._getNewTarget(startTouch[xKey] - currentTouch[xKey] > 0);
                    newTarget = self._instance._options.wrap === 'circular' ? newTarget.relative : newTarget.static;

                    if (startTarget === event.target) {
                        $(event.target).on("click.disable", function (event) {
                            event.stopImmediatePropagation();
                            event.stopPropagation();
                            event.preventDefault();
                            $(event.target).off("click.disable");
                        });
                    }

                    if (self._instance._options.wrap === 'circular') {
                        self._removeClones();
                        self._instance._items = null;
                    }
                    animated = true;
                    self._instance[self._options.method](newTarget, function() {
                        started = false;
                        animated = false;
                        if (self._instance._options.wrap !== 'circular') {
                            self._removeClones();
                            self._instance._items = null;
                        }
                    });

                }

                $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe');
                $(document).off('touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe');
            }

            function getTouches(event) {
                if (event.touches !== undefined && event.touches.length > 0) {
                    return {
                        x: event.touches[0].pageX,
                        y: event.touches[0].pageY
                    }
                } else if (event.changedTouches !== undefined && event.changedTouches.length > 0) {
                    return {
                        x: event.changedTouches[0].pageX,
                        y: event.changedTouches[0].pageY
                    }
                } else {
                    if (event.pageX !== undefined) {
                        return {
                            x: event.pageX,
                            y: event.pageY
                        }
                    } else {
                        return {
                            x: event.clientX,
                            y: event.clientY
                        }
                    }
                }
            }
        },
        _getNewTarget: function(isSwipeToLT) {
            var target = this._instance.target();
            var staticTarget = this._instance.index(target);
            var relativeTarget = 0;
            var isToNext = this._instance.rtl && !this._instance.vertical ? !isSwipeToLT : isSwipeToLT;
            var offsetDiff;

            if (this._options.draggable) {
                while(true) {
                    if (this._instance.rtl && !this._instance.vertical) {
                        offsetDiff = (target.offset()[this._instance.lt] + this._instance.dimension(target)) - (this._carouselOffset + this._instance.clipping());
                    } else {
                        offsetDiff = target.offset()[this._instance.lt] - this._carouselOffset;
                    }

                    if (!target.length ||
                        isSwipeToLT && offsetDiff >= 0 ||
                        !isSwipeToLT && offsetDiff <= 0) {
                        break;
                    }

                    if (isToNext) {
                        target = target.next();
                        if (!target.length) break;
                        staticTarget = staticTarget + 1;
                    } else {
                        target = target.prev();
                        if (!target.length) break;
                        staticTarget = staticTarget - 1;
                    }

                    relativeTarget++;
                }
            } else {
                staticTarget = isToNext ? staticTarget + 1 : staticTarget - 1;
                relativeTarget = 1;
            }

            if (isToNext) {
                staticTarget = staticTarget + Math.abs(relativeTarget - this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe));
            } else {
                staticTarget = staticTarget - Math.abs(relativeTarget - this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe));
            }

            if (this._instance._options.wrap === 'first') {
                staticTarget = Math.min(this._slidesCount - 1, staticTarget);
            } else if (this._instance._options.wrap === 'last') {
                staticTarget = Math.max(0, staticTarget);
            } else if (!this._instance._options.wrap) {
                staticTarget = Math.max(0, Math.min(this._slidesCount - 1, staticTarget));
            }

            staticTarget = staticTarget % this._slidesCount;
            relativeTarget = this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe);

            return {
                static: staticTarget,
                relative: (isToNext ? '+' : '-') + '=' + relativeTarget
            };
        },
        _getListPosition: function() {
            var list = this._instance.list();
            var position = list.position();

            if (this._instance.rtl) {
                position.left = list.width() + position.left - this._carousel.width();
            }

            return position[this._instance.lt];
        },
        _setListPosition: function(position) {
            var option       = this._instance.options('transitions');
            var transforms   = !!option.transforms;
            var transforms3d = !!option.transforms3d;
            var css = {};
            var isLeft = this._instance.lt === 'left';
            position = position || 0;

            if (transforms3d) {
                css.transform = 'translate3d(' + (isLeft ? position : 0) + ',' + (isLeft ? 0 : position) + ',0)';
            } else if (transforms) {
                css.transform = 'translate(' + (isLeft ? position : 0) + ',' + (isLeft ? 0 : position) + ')';
            } else {
                css[this._instance.lt] = position;
            }

            this._instance.list().css(css);
        },
        _addClones: function() {
            var self = this;
            var inst = this._instance;
            var items = inst.items();
            var first = inst.first();
            var last = inst.last();
            var clip = inst.dimension($(window));
            var curr;
            var wh;
            var index;
            var clonesBefore = [];
            var clonesAfter = [];
            var lt = self._getListPosition();
            var moveObj = {};

            if (!inst._options.wrap) {
                return false;
            }

            if (inst._options.wrap !== 'last') {
                for (wh = 0, index = 0, curr = first; wh < clip;) {
                    curr = curr.prev();

                    if (curr.length === 0) {
                        index = --index < -items.length ? -1 : index;
                        wh += inst.dimension(items.eq(index));
                        clonesBefore.push(items.eq(index).clone().attr('data-jcarousel-clone', true));
                    } else {
                        wh += inst.dimension(curr);
                    }
                }

                lt = (inst.rtl ? Math.max(lt, wh) : Math.min(lt, - wh)) + 'px';
                inst._items.first().before(clonesBefore.reverse());
                moveObj[inst.lt] = lt;
                inst.move(moveObj);
            }

            if (inst._options.wrap !== 'first') {
                for (wh = 0, index = -1, curr = last; wh < clip;) {
                    curr = curr.next();

                    if (curr.length === 0) {
                        index = ++index > items.length - 1 ? 0 : index;
                        wh += inst.dimension(items.eq(index));
                        clonesAfter.push(items.eq(index).clone().attr('data-jcarousel-clone', true));
                    } else {
                        wh += inst.dimension(curr);
                    }
                }

                inst._items.last().after(clonesAfter);
            }
        },
        _removeClones: function() {
            var startPosition = this._instance.first().position()[this._instance.lt];
            var removeCLonesWidth;
            var moveObj = {};
            this._instance.list().find('[data-jcarousel-clone]').remove();
            removeCLonesWidth = startPosition - this._instance.first().position()[this._instance.lt];
            if (removeCLonesWidth) {
                moveObj[this._instance.lt] = this._getListPosition() + removeCLonesWidth + 'px';
                this._instance.move(moveObj);
            }
        },
        _destroy: function() {
            this._element.off('touchstart.jcarouselSwipe mousedown.jcarouselSwipe');
            $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe');
        },
        _reload: function() {
            this._create();
        }
    });
}(jQuery));
<commit_msg>fixed sensitivity of x-axis-swipe gestures - only swipe when swipe vector is within the coordinates diagonals<commit_after>/*! jсarouselSwipe - v0.3.4 - 2016-02-18
* Copyright (c) 2015 Evgeniy Pelmenev; Licensed MIT */
(function($) {
    'use strict';

    $.jCarousel.plugin('jcarouselSwipe', {
        _options: {
            perSwipe: 1,
            draggable: true,
            method: 'scroll'
        },
        _init: function() {
            var self = this;
            this.carousel().on('jcarousel:reloadend', function() {
                self._reload();
            });
        },
        _create: function() {
            this._instance = this.carousel().data('jcarousel');
            this._instance._element.css('touch-action', (!this._instance.vertical ? 'pan-y' : 'pan-x'));
            this._carouselOffset = this.carousel().offset()[this._instance.lt] + parseInt(this.carousel().css((!this._instance.vertical ? 'border-left-width' : 'border-top-width'))) + parseInt(this.carousel().css((!this._instance.vertical ? 'padding-left' : 'padding-top')));
            this._slidesCount = this._instance.items().length;
            this.carousel().find('img, a')
                .attr('draggable', false)
                .css('user-select', 'none')
                .on('dragstart', function(event) { event.preventDefault() });

            this._destroy();

            if (this._instance.items().length > this._instance.fullyvisible().length) {
                this._initGestures();
            }
        },
        _initGestures: function() {
            var self = this;
            var startTouch = {};
            var currentTouch = {};
            var started = false;
            var animated = false;
            var xKey = !this._instance.vertical ? 'x' : 'y';
            var yKey = !this._instance.vertical ? 'y' : 'x';
            var edgeLT, lastItem;
            var startTarget;

            this._element.on('touchstart.jcarouselSwipe mousedown.jcarouselSwipe', dragStart);

            function dragStart(event) {
                event = event.originalEvent || event || window.event;
                startTouch = getTouches(event);
                startTarget = event.target || event.srcElement;

                if (self._options.draggable) {
                    $(document).on('touchmove.jcarouselSwipe mousemove.jcarouselSwipe', dragMove);
                }
                $(document).on('touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe', dragEnd);
            }

            function dragMove(event) {
                var delta, newLT, itemsOption;
                event = event.originalEvent || event || window.event;
                currentTouch = getTouches(event);

                if (started) {
                    event.preventDefault();
                }

                if (Math.abs(startTouch[yKey] - currentTouch[yKey]) > 10 && !started) {
                    $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe');
                    return;
                }

                if (!animated && Math.abs(startTouch[xKey] - currentTouch[xKey]) > 10) {
                    delta = startTouch[xKey] - currentTouch[xKey];

                    if (!started) {
                        started = true;
                        self._addClones();
                        self._currentLT = self._getListPosition();
                        itemsOption = self._instance.options('items');
                        lastItem = ($.isFunction(itemsOption) ? itemsOption.call(self._instance) : self._instance.list().find(itemsOption)).last();
                        edgeLT = self._instance.rtl && !self._instance.vertical ?
                            (self._instance.dimension(self._instance.list()) - lastItem.position()[self._instance.lt] - self._instance.clipping()) :
                            (lastItem.position()[self._instance.lt] + self._instance.dimension(lastItem) - self._instance.clipping()) * -1;
                    }

                    if (self._instance._options.wrap === 'circular') {
                        newLT = self._currentLT - delta;
                    } else if (self._instance.rtl && !self._instance.vertical) {
                        newLT = Math.max(0, Math.min(self._currentLT - delta, edgeLT));
                    } else {
                        newLT = Math.min(0, Math.max(self._currentLT - delta, edgeLT));
                    }

                    self._setListPosition(newLT + 'px');
                }
            }

            function dragEnd(event) {
                event = event.originalEvent || event || window.event;
                currentTouch = getTouches(event);
                var xDiff = Math.abs(startTouch[xKey] - currentTouch[xKey]);
                var yDiff = Math.abs(startTouch[yKey] - currentTouch[yKey]);
                if (started || (!self._options.draggable && xDiff > 10 && xDiff > yDiff)) {
                    var newTarget = self._getNewTarget(startTouch[xKey] - currentTouch[xKey] > 0);
                    newTarget = self._instance._options.wrap === 'circular' ? newTarget.relative : newTarget.static;

                    if (startTarget === event.target) {
                        $(event.target).on("click.disable", function (event) {
                            event.stopImmediatePropagation();
                            event.stopPropagation();
                            event.preventDefault();
                            $(event.target).off("click.disable");
                        });
                    }

                    if (self._instance._options.wrap === 'circular') {
                        self._removeClones();
                        self._instance._items = null;
                    }
                    animated = true;
                    self._instance[self._options.method](newTarget, function() {
                        started = false;
                        animated = false;
                        if (self._instance._options.wrap !== 'circular') {
                            self._removeClones();
                            self._instance._items = null;
                        }
                    });

                }

                $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe');
                $(document).off('touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe');
            }

            function getTouches(event) {
                if (event.touches !== undefined && event.touches.length > 0) {
                    return {
                        x: event.touches[0].pageX,
                        y: event.touches[0].pageY
                    }
                } else if (event.changedTouches !== undefined && event.changedTouches.length > 0) {
                    return {
                        x: event.changedTouches[0].pageX,
                        y: event.changedTouches[0].pageY
                    }
                } else {
                    if (event.pageX !== undefined) {
                        return {
                            x: event.pageX,
                            y: event.pageY
                        }
                    } else {
                        return {
                            x: event.clientX,
                            y: event.clientY
                        }
                    }
                }
            }
        },
        _getNewTarget: function(isSwipeToLT) {
            var target = this._instance.target();
            var staticTarget = this._instance.index(target);
            var relativeTarget = 0;
            var isToNext = this._instance.rtl && !this._instance.vertical ? !isSwipeToLT : isSwipeToLT;
            var offsetDiff;

            if (this._options.draggable) {
                while(true) {
                    if (this._instance.rtl && !this._instance.vertical) {
                        offsetDiff = (target.offset()[this._instance.lt] + this._instance.dimension(target)) - (this._carouselOffset + this._instance.clipping());
                    } else {
                        offsetDiff = target.offset()[this._instance.lt] - this._carouselOffset;
                    }

                    if (!target.length ||
                        isSwipeToLT && offsetDiff >= 0 ||
                        !isSwipeToLT && offsetDiff <= 0) {
                        break;
                    }

                    if (isToNext) {
                        target = target.next();
                        if (!target.length) break;
                        staticTarget = staticTarget + 1;
                    } else {
                        target = target.prev();
                        if (!target.length) break;
                        staticTarget = staticTarget - 1;
                    }

                    relativeTarget++;
                }
            } else {
                staticTarget = isToNext ? staticTarget + 1 : staticTarget - 1;
                relativeTarget = 1;
            }

            if (isToNext) {
                staticTarget = staticTarget + Math.abs(relativeTarget - this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe));
            } else {
                staticTarget = staticTarget - Math.abs(relativeTarget - this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe));
            }

            if (this._instance._options.wrap === 'first') {
                staticTarget = Math.min(this._slidesCount - 1, staticTarget);
            } else if (this._instance._options.wrap === 'last') {
                staticTarget = Math.max(0, staticTarget);
            } else if (!this._instance._options.wrap) {
                staticTarget = Math.max(0, Math.min(this._slidesCount - 1, staticTarget));
            }

            staticTarget = staticTarget % this._slidesCount;
            relativeTarget = this._options.perSwipe * Math.ceil(relativeTarget / this._options.perSwipe);

            return {
                static: staticTarget,
                relative: (isToNext ? '+' : '-') + '=' + relativeTarget
            };
        },
        _getListPosition: function() {
            var list = this._instance.list();
            var position = list.position();

            if (this._instance.rtl) {
                position.left = list.width() + position.left - this._carousel.width();
            }

            return position[this._instance.lt];
        },
        _setListPosition: function(position) {
            var option       = this._instance.options('transitions');
            var transforms   = !!option.transforms;
            var transforms3d = !!option.transforms3d;
            var css = {};
            var isLeft = this._instance.lt === 'left';
            position = position || 0;

            if (transforms3d) {
                css.transform = 'translate3d(' + (isLeft ? position : 0) + ',' + (isLeft ? 0 : position) + ',0)';
            } else if (transforms) {
                css.transform = 'translate(' + (isLeft ? position : 0) + ',' + (isLeft ? 0 : position) + ')';
            } else {
                css[this._instance.lt] = position;
            }

            this._instance.list().css(css);
        },
        _addClones: function() {
            var self = this;
            var inst = this._instance;
            var items = inst.items();
            var first = inst.first();
            var last = inst.last();
            var clip = inst.dimension($(window));
            var curr;
            var wh;
            var index;
            var clonesBefore = [];
            var clonesAfter = [];
            var lt = self._getListPosition();
            var moveObj = {};

            if (!inst._options.wrap) {
                return false;
            }

            if (inst._options.wrap !== 'last') {
                for (wh = 0, index = 0, curr = first; wh < clip;) {
                    curr = curr.prev();

                    if (curr.length === 0) {
                        index = --index < -items.length ? -1 : index;
                        wh += inst.dimension(items.eq(index));
                        clonesBefore.push(items.eq(index).clone().attr('data-jcarousel-clone', true));
                    } else {
                        wh += inst.dimension(curr);
                    }
                }

                lt = (inst.rtl ? Math.max(lt, wh) : Math.min(lt, - wh)) + 'px';
                inst._items.first().before(clonesBefore.reverse());
                moveObj[inst.lt] = lt;
                inst.move(moveObj);
            }

            if (inst._options.wrap !== 'first') {
                for (wh = 0, index = -1, curr = last; wh < clip;) {
                    curr = curr.next();

                    if (curr.length === 0) {
                        index = ++index > items.length - 1 ? 0 : index;
                        wh += inst.dimension(items.eq(index));
                        clonesAfter.push(items.eq(index).clone().attr('data-jcarousel-clone', true));
                    } else {
                        wh += inst.dimension(curr);
                    }
                }

                inst._items.last().after(clonesAfter);
            }
        },
        _removeClones: function() {
            var startPosition = this._instance.first().position()[this._instance.lt];
            var removeCLonesWidth;
            var moveObj = {};
            this._instance.list().find('[data-jcarousel-clone]').remove();
            removeCLonesWidth = startPosition - this._instance.first().position()[this._instance.lt];
            if (removeCLonesWidth) {
                moveObj[this._instance.lt] = this._getListPosition() + removeCLonesWidth + 'px';
                this._instance.move(moveObj);
            }
        },
        _destroy: function() {
            this._element.off('touchstart.jcarouselSwipe mousedown.jcarouselSwipe');
            $(document).off('touchmove.jcarouselSwipe mousemove.jcarouselSwipe touchend.jcarouselSwipe touchcancel.jcarouselSwipe mouseup.jcarouselSwipe');
        },
        _reload: function() {
            this._create();
        }
    });
}(jQuery));
<|endoftext|>


<commit_before>/**
 * @license jQuery Text Highlighter
 * Copyright (C) 2011 by mirz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

(function($) {
    var context = null;
    var options = {};
    var methods = {
        init: function(opts) {
            context = this;
            options = $.extend({}, $.fn.textHighlighter.defaults, opts);
            saveState();

            $(context).addClass(options.contextClass);
            bindEvents();
        },
        destroy: function() {
            unbindEvents();
            teardown();
        },
        setColor: function(color) {
            options.color = color;
            saveState();
        },
        getColor: function() {
            return options.color;
        },
        removeHighlights: function(element) {
            var container = (element != undefined ? element : context);
            removeHighlights(container);
        }
    }
    var nodeTypes = {
        ELEMENT_NODE: 1,
        TEXT_NODE: 3
    };

    /**
     * Associates plugin's options with context element.
     */
    function saveState() {
        $(context).data('textHighlighter', options);
    }

    /**
     * Restores plugin's options from data associated with context element.
     */
    function restoreState(ctx) {
        context = ctx;
        options = $(context).data('textHighlighter');
    }

    function bindEvents() {
        $(context).mouseup(doHighlight);
    }

    function unbindEvents() {
        $(context).unbind('mouseup', doHighlight);
    }

    function teardown() {
        $(context).removeClass(options.contextClass);
    }

    /**
     * Highlights currently selected text.
     */
    function doHighlight() {
        restoreState(this);

        var range = getCurrentRange();
        if (!range || range.collapsed) return;

        if (options.onBeforeHighlight(range) == true) {
            var $wrapper = $.fn.textHighlighter.createWrapper(options);

            var createdHighlights = highlightRange(range, $wrapper);
            var normalizedHighlights = normalizeHighlights(createdHighlights);

            options.onAfterHighlight(normalizedHighlights);
        }

        removeAllRanges();
    }

    /**
     * Highlights given range, i.e. wraps it in given wrapper.
     */
    function highlightRange(range, $wrapper) {
        if (range.collapsed) return;

        // Don't highlight content of these tags
        var ignoreTags = ['SCRIPT', 'STYLE', 'SELECT', 'BUTTON', 'OBJECT', 'APPLET'];
        var startContainer = range.startContainer;
        var endContainer = range.endContainer;
        var ancestor = range.commonAncestorContainer;
        var goDeeper = true;

        if (range.endOffset == 0) {
            while (!endContainer.previousSibling && endContainer.parentNode != ancestor) {
                endContainer = endContainer.parentNode;
            }
            endContainer = endContainer.previousSibling;
        } else if (endContainer.nodeType == nodeTypes.TEXT_NODE) {
            if (range.endOffset < endContainer.nodeValue.length) {
                endContainer.splitText(range.endOffset);
            }
        } else if (range.endOffset > 0) {
            endContainer = endContainer.childNodes.item(range.endOffset - 1);
        }

        if (startContainer.nodeType == nodeTypes.TEXT_NODE) {
            if (range.startOffset == startContainer.nodeValue.length) {
                goDeeper = false;
            } else if (range.startOffset > 0) {
                startContainer = startContainer.splitText(range.startOffset);
                if (endContainer == startContainer.previousSibling) endContainer = startContainer;
            }
        } else if (range.startOffset < startContainer.childNodes.length) {
            startContainer = startContainer.childNodes.item(range.startOffset);
        } else {
            startContainer = startContainer.nextSibling;
        }

        var done = false;
        var node = startContainer;
        var highlights = [];

        do {
            if (goDeeper && node.nodeType == nodeTypes.TEXT_NODE) {
                if(/\S/.test(node.nodeValue)) {
                    var wrapper = $wrapper.clone(true).get(0);
                    var highlight = $(node).wrap(wrapper).parent().get(0);
                    highlights.push(highlight);
                }

                goDeeper = false;
            }
            if (node == endContainer && (!endContainer.hasChildNodes() || !goDeeper)) {
                done = true;
            }

            if ($.inArray(node.tagName, ignoreTags) != -1) {
                goDeeper = false;
            }
            if (goDeeper && node.hasChildNodes()) {
                node = node.firstChild;
            } else if (node.nextSibling != null) {
                node = node.nextSibling;
                goDeeper = true;
            } else {
                node = node.parentNode;
                goDeeper = false;
            }
        } while (!done);

        return highlights;
    }

    /**
     * Normalizes highlights, i.e. nested highlights are flattened and sibling higlights are merged.
     */
    function normalizeHighlights(highlights) {
        flattenNestedHighlights(highlights);
        mergeSiblingHighlights(highlights);

        // omit removed nodes
        var normalizedHighlights = $.map(highlights, function(hl) {
            if (typeof hl.parentElement != 'undefined') { // IE
              return hl.parentElement != null ? hl : null;
            } else {
              return hl.parentNode != null ? hl : null;
            }
        });

        return normalizedHighlights;
    }

    function flattenNestedHighlights(highlights) {
        $.each(highlights, function(i) {
            var $highlight = $(this);

            if($highlight.parent().hasClass(options.highlightedClass)) {
                var $parent = $highlight.parent();
                var parentTxt = $parent.text();
                var newNode = document.createTextNode(parentTxt);

                $parent.empty();
                $parent.append(newNode);
                $(highlights[i]).remove();
            }
        });
    }

    function mergeSiblingHighlights(highlights) {
        function shouldMerge(node) {
            return node && node.nodeType == nodeTypes.ELEMENT_NODE &&
                $(node).hasClass(options.highlightedClass) ? true : false;
        }

        $.each(highlights, function() {
            var highlight = this;

            var prev = highlight.previousSibling;
            var next = highlight.nextSibling;

            if (shouldMerge(prev)) {
                var mergedTxt = $(prev).text() + $(highlight).text();
                $(highlight).text(mergedTxt);
                $(prev).remove();
            }
            if(shouldMerge(next)) {
                var mergedTxt = $(highlight).text() + $(next).text();
                $(highlight).text(mergedTxt);
                $(next).remove();
            }
        });
    }

    /**
     * Returns all highlights in given container. If container is a highlight itself and andSelf is
     * true, container will be also returned
     */
    function getAllHighlights(container, andSelf) {
        var classSelectorStr = '.' + options.highlightedClass;
        var $highlights = $(container).find(classSelectorStr);
        if (andSelf == true && $(container).hasClass(options.highlightedClass)) {
            $highlights = $highlights.add(container);
        }
        return $highlights;
    }

    function removeHighlights(container) {
        var unwrapHighlight = function(highlight) {
            return $(highlight).contents().unwrap().get(0);
        };

        var mergeSiblingTextNodes = function(textNode) {
            var prev = textNode.previousSibling;
            var next = textNode.nextSibling;

            if (prev && prev.nodeType == nodeTypes.TEXT_NODE) {
                textNode.nodeValue = prev.nodeValue + textNode.nodeValue;
                prev.parentNode.removeChild(prev);
            }
            if (next && next.nodeType == nodeTypes.TEXT_NODE) {
                textNode.nodeValue = textNode.nodeValue + next.nodeValue;
                next.parentNode.removeChild(next);
            }
        };

        var $highlights = getAllHighlights(container, true);
        $highlights.each(function() {
            if (options.onRemoveHighlight(this) == true) {
                var textNode = unwrapHighlight(this);
                mergeSiblingTextNodes(textNode);
            }
        });
    }

    /**
     * Returns context's owner document.
     */
    function getCurrentDocument() {
        // if ownerDocument is null then context is document
        return context.ownerDocument ? context.ownerDocument : context;
    }

    /**
     * Returns context's owner window.
     */
    function getCurrentWindow() {
        var currentDoc = getCurrentDocument();
        if (currentDoc.defaultView) {
            return currentDoc.defaultView; // Non-IE
        } else {
            return currentDoc.parentWindow; // IE
        }
    }

    /**
     * Returns current selection object.
     */
    function getCurrentSelection() {
        var currentWindow = getCurrentWindow();
        var selection = null;

        if (currentWindow.getSelection) {
            selection = currentWindow.getSelection();
        } else if ($('iframe').length > 0) {
            $('iframe', top.document).each(function() {
                if (this.contentWindow === currentWindow) {
                    selection = rangy.getIframeSelection(this);
                    return false;
                }
            });
        } else {
            selection = rangy.getSelection();
        }

        return selection;
    }

    function getCurrentRange() {
        var selection = getCurrentSelection();
        var range = null;
        if (selection.rangeCount > 0) {
            range = selection.getRangeAt(0);
        }
        return range;
    }

    function removeAllRanges() {
        var selection = getCurrentSelection();
        selection.removeAllRanges();
    }

    $.fn.textHighlighter = function(method) {
        var args = arguments;

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(args, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, args);
        } else {
            $.error('Method ' +  method + ' does not exist on jQuery.textHighlighter');
        }
    };

    /**
     * Returns HTML element to wrap selected text in.
     */
    $.fn.textHighlighter.createWrapper = function(opts) {
        return $('<span>')
            .css('backgroundColor', opts.color)
            .addClass(opts.highlightedClass);
    };

    $.fn.textHighlighter.defaults = {
        color: '#ffff7b',
        highlightedClass: 'highlighted',
        contextClass: 'highlighter-context',
        onRemoveHighlight: function() { return true },
        onBeforeHighlight: function() { return true },
        onAfterHighlight: function() { }
    };
})(jQuery);
<commit_msg>highlighting only inside context<commit_after>/**
 * @license jQuery Text Highlighter
 * Copyright (C) 2011 by mirz
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

(function($) {
    var context = null;
    var options = {};
    var methods = {
        init: function(opts) {
            context = this;
            options = $.extend({}, $.fn.textHighlighter.defaults, opts);
            saveState();

            $(context).addClass(options.contextClass);
            bindEvents();
        },
        destroy: function() {
            unbindEvents();
            teardown();
        },
        setColor: function(color) {
            options.color = color;
            saveState();
        },
        getColor: function() {
            return options.color;
        },
        removeHighlights: function(element) {
            var container = (element != undefined ? element : context);
            removeHighlights(container);
        }
    }
    var nodeTypes = {
        ELEMENT_NODE: 1,
        TEXT_NODE: 3
    };

    /**
     * Associates plugin's options with context element.
     */
    function saveState() {
        $(context).data('textHighlighter', options);
    }

    /**
     * Restores plugin's options from data associated with context element.
     */
    function restoreState(ctx) {
        context = ctx;
        options = $(context).data('textHighlighter');
    }

    function bindEvents() {
        $(context).mouseup(doHighlight);
    }

    function unbindEvents() {
        $(context).unbind('mouseup', doHighlight);
    }

    function teardown() {
        $(context).removeClass(options.contextClass);
    }

    /**
     * Highlights currently selected text.
     */
    function doHighlight() {
        restoreState(this);

        var range = getCurrentRange();
        if (!range || range.collapsed) return;
        if (!isInsideContext(range)) return;

        if (options.onBeforeHighlight(range) == true) {
            var $wrapper = $.fn.textHighlighter.createWrapper(options);

            var createdHighlights = highlightRange(range, $wrapper);
            var normalizedHighlights = normalizeHighlights(createdHighlights);

            options.onAfterHighlight(normalizedHighlights);
        }

        removeAllRanges();
    }

    /**
     * Highlights given range, i.e. wraps it in given wrapper.
     */
    function highlightRange(range, $wrapper) {
        if (range.collapsed) return;

        // Don't highlight content of these tags
        var ignoreTags = ['SCRIPT', 'STYLE', 'SELECT', 'BUTTON', 'OBJECT', 'APPLET'];
        var startContainer = range.startContainer;
        var endContainer = range.endContainer;
        var ancestor = range.commonAncestorContainer;
        var goDeeper = true;

        if (range.endOffset == 0) {
            while (!endContainer.previousSibling && endContainer.parentNode != ancestor) {
                endContainer = endContainer.parentNode;
            }
            endContainer = endContainer.previousSibling;
        } else if (endContainer.nodeType == nodeTypes.TEXT_NODE) {
            if (range.endOffset < endContainer.nodeValue.length) {
                endContainer.splitText(range.endOffset);
            }
        } else if (range.endOffset > 0) {
            endContainer = endContainer.childNodes.item(range.endOffset - 1);
        }

        if (startContainer.nodeType == nodeTypes.TEXT_NODE) {
            if (range.startOffset == startContainer.nodeValue.length) {
                goDeeper = false;
            } else if (range.startOffset > 0) {
                startContainer = startContainer.splitText(range.startOffset);
                if (endContainer == startContainer.previousSibling) endContainer = startContainer;
            }
        } else if (range.startOffset < startContainer.childNodes.length) {
            startContainer = startContainer.childNodes.item(range.startOffset);
        } else {
            startContainer = startContainer.nextSibling;
        }

        var done = false;
        var node = startContainer;
        var highlights = [];

        do {
            if (goDeeper && node.nodeType == nodeTypes.TEXT_NODE) {
                if(/\S/.test(node.nodeValue)) {
                    var wrapper = $wrapper.clone(true).get(0);
                    var highlight = $(node).wrap(wrapper).parent().get(0);
                    highlights.push(highlight);
                }

                goDeeper = false;
            }
            if (node == endContainer && (!endContainer.hasChildNodes() || !goDeeper)) {
                done = true;
            }

            if ($.inArray(node.tagName, ignoreTags) != -1) {
                goDeeper = false;
            }
            if (goDeeper && node.hasChildNodes()) {
                node = node.firstChild;
            } else if (node.nextSibling != null) {
                node = node.nextSibling;
                goDeeper = true;
            } else {
                node = node.parentNode;
                goDeeper = false;
            }
        } while (!done);

        return highlights;
    }

    /**
     * Normalizes highlights, i.e. nested highlights are flattened and sibling higlights are merged.
     */
    function normalizeHighlights(highlights) {
        flattenNestedHighlights(highlights);
        mergeSiblingHighlights(highlights);

        // omit removed nodes
        var normalizedHighlights = $.map(highlights, function(hl) {
            if (typeof hl.parentElement != 'undefined') { // IE
              return hl.parentElement != null ? hl : null;
            } else {
              return hl.parentNode != null ? hl : null;
            }
        });

        return normalizedHighlights;
    }

    function flattenNestedHighlights(highlights) {
        $.each(highlights, function(i) {
            var $highlight = $(this);

            if($highlight.parent().hasClass(options.highlightedClass)) {
                var $parent = $highlight.parent();
                var parentTxt = $parent.text();
                var newNode = document.createTextNode(parentTxt);

                $parent.empty();
                $parent.append(newNode);
                $(highlights[i]).remove();
            }
        });
    }

    function mergeSiblingHighlights(highlights) {
        function shouldMerge(node) {
            return node && node.nodeType == nodeTypes.ELEMENT_NODE &&
                $(node).hasClass(options.highlightedClass) ? true : false;
        }

        $.each(highlights, function() {
            var highlight = this;

            var prev = highlight.previousSibling;
            var next = highlight.nextSibling;

            if (shouldMerge(prev)) {
                var mergedTxt = $(prev).text() + $(highlight).text();
                $(highlight).text(mergedTxt);
                $(prev).remove();
            }
            if(shouldMerge(next)) {
                var mergedTxt = $(highlight).text() + $(next).text();
                $(highlight).text(mergedTxt);
                $(next).remove();
            }
        });
    }

    /**
     * Returns all highlights in given container. If container is a highlight itself and andSelf is
     * true, container will be also returned
     */
    function getAllHighlights(container, andSelf) {
        var classSelectorStr = '.' + options.highlightedClass;
        var $highlights = $(container).find(classSelectorStr);
        if (andSelf == true && $(container).hasClass(options.highlightedClass)) {
            $highlights = $highlights.add(container);
        }
        return $highlights;
    }

    function removeHighlights(container) {
        var unwrapHighlight = function(highlight) {
            return $(highlight).contents().unwrap().get(0);
        };

        var mergeSiblingTextNodes = function(textNode) {
            var prev = textNode.previousSibling;
            var next = textNode.nextSibling;

            if (prev && prev.nodeType == nodeTypes.TEXT_NODE) {
                textNode.nodeValue = prev.nodeValue + textNode.nodeValue;
                prev.parentNode.removeChild(prev);
            }
            if (next && next.nodeType == nodeTypes.TEXT_NODE) {
                textNode.nodeValue = textNode.nodeValue + next.nodeValue;
                next.parentNode.removeChild(next);
            }
        };

        var $highlights = getAllHighlights(container, true);
        $highlights.each(function() {
            if (options.onRemoveHighlight(this) == true) {
                var textNode = unwrapHighlight(this);
                mergeSiblingTextNodes(textNode);
            }
        });
    }

    /**
     * Returns context's owner document.
     */
    function getCurrentDocument() {
        // if ownerDocument is null then context is document
        return context.ownerDocument ? context.ownerDocument : context;
    }

    /**
     * Returns context's owner window.
     */
    function getCurrentWindow() {
        var currentDoc = getCurrentDocument();
        if (currentDoc.defaultView) {
            return currentDoc.defaultView; // Non-IE
        } else {
            return currentDoc.parentWindow; // IE
        }
    }

    /**
     * Returns current selection object.
     */
    function getCurrentSelection() {
        var currentWindow = getCurrentWindow();
        var selection = null;

        if (currentWindow.getSelection) {
            selection = currentWindow.getSelection();
        } else if ($('iframe').length > 0) {
            $('iframe', top.document).each(function() {
                if (this.contentWindow === currentWindow) {
                    selection = rangy.getIframeSelection(this);
                    return false;
                }
            });
        } else {
            selection = rangy.getSelection();
        }

        return selection;
    }

    function getCurrentRange() {
        var selection = getCurrentSelection();
        var range = null;
        if (selection.rangeCount > 0) {
            range = selection.getRangeAt(0);
        }
        return range;
    }

    /**
     * Returns true if range.startContainer and range.endContainer is inside context.
     */
    function isInsideContext(range) {
        var isStartContainerInContext = $.contains(context, range.startContainer);
        var isEndContainerInContext = $.contains(context, range.endContainer);
        return isStartContainerInContext && isEndContainerInContext;
    }

    function removeAllRanges() {
        var selection = getCurrentSelection();
        selection.removeAllRanges();
    }

    $.fn.textHighlighter = function(method) {
        var args = arguments;

        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(args, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, args);
        } else {
            $.error('Method ' +  method + ' does not exist on jQuery.textHighlighter');
        }
    };

    /**
     * Returns HTML element to wrap selected text in.
     */
    $.fn.textHighlighter.createWrapper = function(opts) {
        return $('<span>')
            .css('backgroundColor', opts.color)
            .addClass(opts.highlightedClass);
    };

    $.fn.textHighlighter.defaults = {
        color: '#ffff7b',
        highlightedClass: 'highlighted',
        contextClass: 'highlighter-context',
        onRemoveHighlight: function() { return true },
        onBeforeHighlight: function() { return true },
        onAfterHighlight: function() { }
    };
})(jQuery);
<|endoftext|>


<commit_before>exports.BattleFormatsData = {
	abra: {
		randomBattleMoves: {"metronome":1}
	},
	aipom: {
		randomBattleMoves: {"metronome":1}
	},
	alakazam: {
		randomBattleMoves: {"metronome":1}
	},
	alakazammega: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Alakazite"
	},
	ambipom: {
		randomBattleMoves: {"metronome":1}
	},
	banette: {
		randomBattleMoves: {"metronome":1}
	},
	banettemega: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Banettite"
	},
	blissey: {
		randomBattleMoves: {"metronome":1}
	},
	celebi: {
		randomBattleMoves: {"metronome":1}
	},
	chansey: {
		randomBattleMoves: {"metronome":1}
	},
	clefable: {
		randomBattleMoves: {"metronome":1}
	},
	clefairy: {
		randomBattleMoves: {"metronome":1}
	},
	cleffa: {
		randomBattleMoves: {"metronome":1}
	},
	drowzee: {
		randomBattleMoves: {"metronome":1}
	},
	dusclops: {
		randomBattleMoves: {"metronome":1}
	},
	gengar: {
		randomBattleMoves: {"metronome":1}
	},
	gengarmega: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Gengarite"
	},
	geodude: {
		randomBattleMoves: {"metronome":1}
	},
	golem: {
		randomBattleMoves: {"metronome":1}
	},
	granbull: {
		randomBattleMoves: {"metronome":1}
	},
	graveler: {
		randomBattleMoves: {"metronome":1}
	},
	happiny: {
		randomBattleMoves: {"metronome":1}
	},
	hariyama: {
		randomBattleMoves: {"metronome":1}
	},
	hitmonchan: {
		randomBattleMoves: {"metronome":1}
	},
	hitmonlee: {
		randomBattleMoves: {"metronome":1}
	},
	hypno: {
		randomBattleMoves: {"metronome":1}
	},
	illumise: {
		randomBattleMoves: {"metronome":1}
	},
	jirachi: {
		randomBattleMoves: {"metronome":1}
	},
	jynx: {
		randomBattleMoves: {"metronome":1}
	},
	kadabra: {
		randomBattleMoves: {"metronome":1}
	},
	kecleon: {
		randomBattleMoves: {"metronome":1}
	},
	ludicolo: {
		randomBattleMoves: {"metronome":1}
	},
	machamp: {
		randomBattleMoves: {"metronome":1}
	},
	machoke: {
		randomBattleMoves: {"metronome":1}
	},
	machop: {
		randomBattleMoves: {"metronome":1}
	},
	makuhita: {
		randomBattleMoves: {"metronome":1}
	},
	mankey: {
		randomBattleMoves: {"metronome":1}
	},
	medicham: {
		randomBattleMoves: {"metronome":1}
	},
	medichammega: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Medichamite"
	},
	meditite: {
		randomBattleMoves: {"metronome":1}
	},
	mew: {
		randomBattleMoves: {"metronome":1}
	},
	mewtwo: {
		randomBattleMoves: {"metronome":1}
	},
	mewtwomegax: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Mewtwonite X"
	},
	mewtwomegay: {
		randomBattleMoves: {"metronome":1},
		requiredItem: "Mewtwonite Y"
	},
	miltank: {
		randomBattleMoves: {"metronome":1}
	},
	minun: {
		randomBattleMoves: {"metronome":1}
	},
	mrmime: {
		randomBattleMoves: {"metronome":1}
	},
	munchlax: {
		randomBattleMoves: {"metronome":1}
	},
	plusle: {
		randomBattleMoves: {"metronome":1}
	},
	politoed: {
		randomBattleMoves: {"metronome":1}
	},
	poliwhirl: {
		randomBattleMoves: {"metronome":1}
	},
	poliwrath: {
		randomBattleMoves: {"metronome":1}
	},
	primeape: {
		randomBattleMoves: {"metronome":1}
	},
	sableye: {
		randomBattleMoves: {"metronome":1}
	},
	smoochum: {
		randomBattleMoves: {"metronome":1}
	},
	snorlax: {
		randomBattleMoves: {"metronome":1}
	},
	snubbull: {
		randomBattleMoves: {"metronome":1}
	},
	spinda: {
		randomBattleMoves: {"metronome":1}
	},
	teddiursa: {
		randomBattleMoves: {"metronome":1}
	},
	togekiss: {
		randomBattleMoves: {"metronome":1}
	},
	togepi: {
		randomBattleMoves: {"metronome":1}
	},
	togetic: {
		randomBattleMoves: {"metronome":1}
	},
	ursaring: {
		randomBattleMoves: {"metronome":1}
	},
	volbeat: {
		randomBattleMoves: {"metronome":1}
	}
};
<commit_msg>Update formats-data.js<commit_after>exports.BattleFormatsData = {
	abra: {
		randomBattleMoves: {"metronome"}
	},
	aipom: {
		randomBattleMoves: {"metronome"}
	},
	alakazam: {
		randomBattleMoves: {"metronome"}
	},
	alakazammega: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Alakazite"
	},
	ambipom: {
		randomBattleMoves: {"metronome"}
	},
	banette: {
		randomBattleMoves: {"metronome"}
	},
	banettemega: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Banettite"
	},
	blissey: {
		randomBattleMoves: {"metronome"}
	},
	celebi: {
		randomBattleMoves: {"metronome"}
	},
	chansey: {
		randomBattleMoves: {"metronome"}
	},
	clefable: {
		randomBattleMoves: {"metronome"}
	},
	clefairy: {
		randomBattleMoves: {"metronome"}
	},
	cleffa: {
		randomBattleMoves: {"metronome"}
	},
	drowzee: {
		randomBattleMoves: {"metronome"}
	},
	dusclops: {
		randomBattleMoves: {"metronome"}
	},
	gengar: {
		randomBattleMoves: {"metronome"}
	},
	gengarmega: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Gengarite"
	},
	geodude: {
		randomBattleMoves: {"metronome"}
	},
	golem: {
		randomBattleMoves: {"metronome"}
	},
	granbull: {
		randomBattleMoves: {"metronome"}
	},
	graveler: {
		randomBattleMoves: {"metronome"}
	},
	happiny: {
		randomBattleMoves: {"metronome"}
	},
	hariyama: {
		randomBattleMoves: {"metronome"}
	},
	hitmonchan: {
		randomBattleMoves: {"metronome"}
	},
	hitmonlee: {
		randomBattleMoves: {"metronome"}
	},
	hypno: {
		randomBattleMoves: {"metronome"}
	},
	illumise: {
		randomBattleMoves: {"metronome"}
	},
	jirachi: {
		randomBattleMoves: {"metronome"}
	},
	jynx: {
		randomBattleMoves: {"metronome"}
	},
	kadabra: {
		randomBattleMoves: {"metronome"}
	},
	kecleon: {
		randomBattleMoves: {"metronome"}
	},
	ludicolo: {
		randomBattleMoves: {"metronome"}
	},
	machamp: {
		randomBattleMoves: {"metronome"}
	},
	machoke: {
		randomBattleMoves: {"metronome"}
	},
	machop: {
		randomBattleMoves: {"metronome"}
	},
	makuhita: {
		randomBattleMoves: {"metronome"}
	},
	mankey: {
		randomBattleMoves: {"metronome"}
	},
	medicham: {
		randomBattleMoves: {"metronome"}
	},
	medichammega: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Medichamite"
	},
	meditite: {
		randomBattleMoves: {"metronome"}
	},
	mew: {
		randomBattleMoves: {"metronome"}
	},
	mewtwo: {
		randomBattleMoves: {"metronome"}
	},
	mewtwomegax: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Mewtwonite X"
	},
	mewtwomegay: {
		randomBattleMoves: {"metronome"},
		requiredItem: "Mewtwonite Y"
	},
	miltank: {
		randomBattleMoves: {"metronome"}
	},
	minun: {
		randomBattleMoves: {"metronome"}
	},
	mrmime: {
		randomBattleMoves: {"metronome"}
	},
	munchlax: {
		randomBattleMoves: {"metronome"}
	},
	plusle: {
		randomBattleMoves: {"metronome"}
	},
	politoed: {
		randomBattleMoves: {"metronome"}
	},
	poliwhirl: {
		randomBattleMoves: {"metronome"}
	},
	poliwrath: {
		randomBattleMoves: {"metronome"}
	},
	primeape: {
		randomBattleMoves: {"metronome"}
	},
	sableye: {
		randomBattleMoves: {"metronome"}
	},
	smoochum: {
		randomBattleMoves: {"metronome"}
	},
	snorlax: {
		randomBattleMoves: {"metronome"}
	},
	snubbull: {
		randomBattleMoves: {"metronome"}
	},
	spinda: {
		randomBattleMoves: {"metronome"}
	},
	teddiursa: {
		randomBattleMoves: {"metronome"}
	},
	togekiss: {
		randomBattleMoves: {"metronome"}
	},
	togepi: {
		randomBattleMoves: {"metronome"}
	},
	togetic: {
		randomBattleMoves: {"metronome"}
	},
	ursaring: {
		randomBattleMoves: {"metronome"}
	},
	volbeat: {
		randomBattleMoves: {"metronome"}
	}
};
<|endoftext|>


<commit_before>import React, { Component } from "react"
import PropTypes from "prop-types"
import SplitPane from "react-split-pane"
import { observer, inject } from "mobx-react"

import mapBeats from "helpers/mapBeats"
import fitToContainer from "hocs/fitToContainer"
import NoteCoordTransform from "model/NoteCoordTransform"

import PianoNotes from "./PianoNotes/PianoNotes"
import PencilMouseHandler from "./PianoNotes/PencilMouseHandler"
import SelectionMouseHandler from "./PianoNotes/SelectionMouseHandler"

import PianoKeys from "./PianoKeys"
import PianoGrid from "./PianoGrid"
import PianoLines from "./PianoLines"
import PianoRuler from "./PianoRuler"
import PianoSelection from "./PianoSelection"
import PianoCursor from "./PianoCursor"
import ControlPane from "./ControlPane"

import { VerticalScrollBar, HorizontalScrollBar, BAR_WIDTH } from "components/inputs/ScrollBar"

import "./PianoRoll.css"

const SCROLL_KEY_SPEED = 4

function PianoRoll({
  dispatch,
  mouseHandler,
  theme,
  track,
  transform,
  onClickKey,
  beats,
  endTick,
  mouseMode,
  selection,
  containerWidth,
  containerHeight,
  alphaHeight,
  scrollLeft,
  scrollTop,
  setScrollLeft,
  setScrollTop,
  controlMode,
  notesCursor,
  cursorPosition,
  onMountAlpha
}) {
  const { keyWidth, rulerHeight } = theme

  const width = containerWidth
  const widthTick = Math.max(endTick, transform.getTicks(containerWidth))
  const startTick = scrollLeft / transform.pixelsPerTick
  const mappedBeats = mapBeats(beats, transform.pixelsPerTick, startTick, widthTick)
  const events = track.events

  const contentWidth = widthTick * transform.pixelsPerTick
  const contentHeight = transform.getMaxY()

  const cursorPositionX = transform.getX(cursorPosition)

  function clampScroll(maxOffset, scroll) {
    return Math.floor(Math.min(maxOffset, Math.max(0, scroll)))
  }

  scrollLeft = clampScroll(contentWidth - containerWidth, scrollLeft)
  scrollTop = clampScroll(contentHeight - alphaHeight, scrollTop)

  return

    <SplitPane split="horizontal" defaultSize={180} primary="second">

 {
          e.preventDefault()
          const scrollLineHeight = transform.pixelsPerKey * SCROLL_KEY_SPEED
          const delta = scrollLineHeight * (e.deltaY > 0 ? 1 : -1)
          setScrollTop(scrollTop + delta)
        }}>

          <PianoLines
            theme={theme}
            width={width}
            pixelsPerKey={transform.pixelsPerKey}
            numberOfKeys={transform.numberOfKeys} />
          <PianoGrid
            theme={theme}
            width={width}
            height={contentHeight}
            scrollLeft={scrollLeft}
            beats={mappedBeats} />
          <PianoNotes
            events={events}
            selectedEventIds={selection.noteIds}
            transform={transform}
            width={width}
            cursor={notesCursor}
            dispatch={dispatch}
            mouseMode={mouseMode}
            scrollLeft={scrollLeft}
            isDrumMode={track.isRhythmTrack}
            mouseHandler={mouseHandler} />
          <PianoSelection
            color={theme.themeColor}
            width={width}
            height={contentHeight}
            selectionBounds={selection.enabled ? selection.getBounds(transform) : null}
            scrollLeft={scrollLeft} />
          <PianoCursor
            width={width}
            height={contentHeight}
            position={cursorPositionX - scrollLeft} />
          <PianoKeys
            theme={theme}
            width={keyWidth}
            keyHeight={transform.pixelsPerKey}
            numberOfKeys={transform.numberOfKeys}
            onClickKey={onClickKey} />

          <PianoRuler
            width={width}
            theme={theme}
            height={rulerHeight}
            endTick={widthTick}
            beats={mappedBeats}
            onMouseDown={({ tick }) => dispatch("SET_PLAYER_POSITION", { tick })}
            scrollLeft={scrollLeft}
            pixelsPerTick={transform.pixelsPerTick} />

        <VerticalScrollBar
          scrollOffset={scrollTop}
          contentLength={contentHeight}
          onScroll={({ scroll }) => setScrollTop(scroll)}
        />

        <ControlPane
          mode={controlMode}
          theme={theme}
          beats={mappedBeats}
          events={events}
          dispatch={dispatch}
          transform={transform}
          scrollLeft={scrollLeft}
          paddingBottom={BAR_WIDTH}
        />
        <HorizontalScrollBar
          scrollOffset={scrollLeft}
          contentLength={contentWidth}
          onScroll={({ scroll }) => setScrollLeft(scroll)}
        />

    </SplitPane>

}

class stateful extends Component {
  constructor(props) {
    super(props)

    this.pencilMouseHandler = new PencilMouseHandler()
    this.selectionMouseHandler = new SelectionMouseHandler()
  }

  componentDidMount() {
    this.props.player.on("change-position", this.onTick)
  }

  componentWillUnmount() {
    this.props.player.off("change-position", this.onTick)
  }

  onTick = tick => {
    const { autoScroll, scrollLeft, containerWidth, setCursorPosition, setScrollLeft, theme, scaleX } = this.props
    const transform = createTransform(theme.keyHeight, scaleX)
    const x = transform.getX(tick)

    setCursorPosition(tick)

    // keep scroll position to cursor
    if (autoScroll) {
      const screenX = x - scrollLeft
      if (screenX > containerWidth * 0.7 || screenX < 0) {
        setScrollLeft(x)
      }
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return true
  }

  render() {
    const { dispatch, selection, theme, scaleX } = this.props
    const transform = createTransform(theme.keyHeight, scaleX)

    this.pencilMouseHandler.dispatch = dispatch
    this.pencilMouseHandler.transform = transform
    this.selectionMouseHandler.dispatch = dispatch
    this.selectionMouseHandler.transform = transform
    this.selectionMouseHandler.selection = selection

    const mouseHandler = this.props.mouseMode === 0 ?
      this.pencilMouseHandler : this.selectionMouseHandler

    return <PianoRoll {...this.props} {...this.state}
      transform={transform}
      mouseHandler={mouseHandler}
      onMountAlpha={c => this.alpha = c}
      alphaHeight={this.alpha ? this.alpha.getBoundingClientRect().height : 0}
    />
  }
}

function createTransform(keyHeight, scaleX) {
  const pixelsPerTick = 0.1 * scaleX
  return new NoteCoordTransform(
    pixelsPerTick,
    keyHeight,
    127)
}

PianoRoll.propTypes = {
  player: PropTypes.object.isRequired,
  quantizer: PropTypes.object.isRequired,
  endTick: PropTypes.number.isRequired,
  scaleX: PropTypes.number.isRequired,
  scaleY: PropTypes.number.isRequired,
  autoScroll: PropTypes.bool.isRequired,
  onClickKey: PropTypes.func.isRequired,
  mouseMode: PropTypes.number.isRequired
}

PianoRoll.defaultProps = {
  endTick: 400,
  scaleX: 1,
  scaleY: 1,
  autoScroll: false
}

export default fitToContainer({
  width: "100%",
  height: "100%"
})(inject(({ rootStore: {
  song: { selectedTrack: track, endOfSong: endTick, measureList: { beats } },
  pianoRollStore: s,
  rootViewStore: { theme },
  services: { player, quantizer },
  dispatch
} }) => ({
    track,
    endTick,
    beats,
    theme,
    scaleX: s.scaleX,
    scaleY: s.scaleY,
    autoScroll: s.autoScroll,
    selection: s.selection,
    scrollLeft: s.scrollLeft,
    setScrollLeft: v => s.scrollLeft = v,
    scrollTop: s.scrollTop,
    setScrollTop: v => s.scrollTop = v,
    controlMode: s.controlMode,
    setControlMode: v => s.controlMode = v,
    cursorPosition: s.cursorPosition,
    setCursorPosition: v => s.cursorPosition = v,
    notesCursor: s.notesCursor,
    setNotesCursor: v => s.notesCursor = v,
    mouseMode: s.mouseMode,
    quantizer,
    player,
    dispatch,
    onChangeTool: () => s.mouseMode = (s.mouseMode === 0 ? 1 : 0),
    onClickKey: (noteNumber) => { console.log(noteNumber) }
  }))(observer(stateful)))
<commit_msg>fix to react to notes changing<commit_after>import React, { Component } from "react"
import PropTypes from "prop-types"
import SplitPane from "react-split-pane"
import { observer, inject } from "mobx-react"

import mapBeats from "helpers/mapBeats"
import fitToContainer from "hocs/fitToContainer"
import NoteCoordTransform from "model/NoteCoordTransform"

import PianoNotes from "./PianoNotes/PianoNotes"
import PencilMouseHandler from "./PianoNotes/PencilMouseHandler"
import SelectionMouseHandler from "./PianoNotes/SelectionMouseHandler"

import PianoKeys from "./PianoKeys"
import PianoGrid from "./PianoGrid"
import PianoLines from "./PianoLines"
import PianoRuler from "./PianoRuler"
import PianoSelection from "./PianoSelection"
import PianoCursor from "./PianoCursor"
import ControlPane from "./ControlPane"

import { VerticalScrollBar, HorizontalScrollBar, BAR_WIDTH } from "components/inputs/ScrollBar"

import "./PianoRoll.css"

const SCROLL_KEY_SPEED = 4

function PianoRoll({
  dispatch,
  mouseHandler,
  theme,
  track,
  events,
  transform,
  onClickKey,
  beats,
  endTick,
  mouseMode,
  selection,
  containerWidth,
  containerHeight,
  alphaHeight,
  scrollLeft,
  scrollTop,
  setScrollLeft,
  setScrollTop,
  controlMode,
  notesCursor,
  cursorPosition,
  onMountAlpha
}) {
  const { keyWidth, rulerHeight } = theme

  const width = containerWidth
  const widthTick = Math.max(endTick, transform.getTicks(containerWidth))
  const startTick = scrollLeft / transform.pixelsPerTick
  const mappedBeats = mapBeats(beats, transform.pixelsPerTick, startTick, widthTick)

  const contentWidth = widthTick * transform.pixelsPerTick
  const contentHeight = transform.getMaxY()

  const cursorPositionX = transform.getX(cursorPosition)

  function clampScroll(maxOffset, scroll) {
    return Math.floor(Math.min(maxOffset, Math.max(0, scroll)))
  }

  scrollLeft = clampScroll(contentWidth - containerWidth, scrollLeft)
  scrollTop = clampScroll(contentHeight - alphaHeight, scrollTop)

  return

    <SplitPane split="horizontal" defaultSize={180} primary="second">

 {
          e.preventDefault()
          const scrollLineHeight = transform.pixelsPerKey * SCROLL_KEY_SPEED
          const delta = scrollLineHeight * (e.deltaY > 0 ? 1 : -1)
          setScrollTop(scrollTop + delta)
        }}>

          <PianoLines
            theme={theme}
            width={width}
            pixelsPerKey={transform.pixelsPerKey}
            numberOfKeys={transform.numberOfKeys} />
          <PianoGrid
            theme={theme}
            width={width}
            height={contentHeight}
            scrollLeft={scrollLeft}
            beats={mappedBeats} />
          <PianoNotes
            events={events}
            selectedEventIds={selection.noteIds}
            transform={transform}
            width={width}
            cursor={notesCursor}
            dispatch={dispatch}
            mouseMode={mouseMode}
            scrollLeft={scrollLeft}
            isDrumMode={track.isRhythmTrack}
            mouseHandler={mouseHandler} />
          <PianoSelection
            color={theme.themeColor}
            width={width}
            height={contentHeight}
            selectionBounds={selection.enabled ? selection.getBounds(transform) : null}
            scrollLeft={scrollLeft} />
          <PianoCursor
            width={width}
            height={contentHeight}
            position={cursorPositionX - scrollLeft} />
          <PianoKeys
            theme={theme}
            width={keyWidth}
            keyHeight={transform.pixelsPerKey}
            numberOfKeys={transform.numberOfKeys}
            onClickKey={onClickKey} />

          <PianoRuler
            width={width}
            theme={theme}
            height={rulerHeight}
            endTick={widthTick}
            beats={mappedBeats}
            onMouseDown={({ tick }) => dispatch("SET_PLAYER_POSITION", { tick })}
            scrollLeft={scrollLeft}
            pixelsPerTick={transform.pixelsPerTick} />

        <VerticalScrollBar
          scrollOffset={scrollTop}
          contentLength={contentHeight}
          onScroll={({ scroll }) => setScrollTop(scroll)}
        />

        <ControlPane
          mode={controlMode}
          theme={theme}
          beats={mappedBeats}
          events={events}
          dispatch={dispatch}
          transform={transform}
          scrollLeft={scrollLeft}
          paddingBottom={BAR_WIDTH}
        />
        <HorizontalScrollBar
          scrollOffset={scrollLeft}
          contentLength={contentWidth}
          onScroll={({ scroll }) => setScrollLeft(scroll)}
        />

    </SplitPane>

}

class stateful extends Component {
  constructor(props) {
    super(props)

    this.pencilMouseHandler = new PencilMouseHandler()
    this.selectionMouseHandler = new SelectionMouseHandler()
  }

  componentDidMount() {
    this.props.player.on("change-position", this.onTick)
  }

  componentWillUnmount() {
    this.props.player.off("change-position", this.onTick)
  }

  onTick = tick => {
    const { autoScroll, scrollLeft, containerWidth, setCursorPosition, setScrollLeft, theme, scaleX } = this.props
    const transform = createTransform(theme.keyHeight, scaleX)
    const x = transform.getX(tick)

    setCursorPosition(tick)

    // keep scroll position to cursor
    if (autoScroll) {
      const screenX = x - scrollLeft
      if (screenX > containerWidth * 0.7 || screenX < 0) {
        setScrollLeft(x)
      }
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return true
  }

  render() {
    const { dispatch, selection, theme, scaleX } = this.props
    const transform = createTransform(theme.keyHeight, scaleX)

    this.pencilMouseHandler.dispatch = dispatch
    this.pencilMouseHandler.transform = transform
    this.selectionMouseHandler.dispatch = dispatch
    this.selectionMouseHandler.transform = transform
    this.selectionMouseHandler.selection = selection

    const mouseHandler = this.props.mouseMode === 0 ?
      this.pencilMouseHandler : this.selectionMouseHandler

    return <PianoRoll {...this.props} {...this.state}
      transform={transform}
      mouseHandler={mouseHandler}
      onMountAlpha={c => this.alpha = c}
      alphaHeight={this.alpha ? this.alpha.getBoundingClientRect().height : 0}
    />
  }
}

function createTransform(keyHeight, scaleX) {
  const pixelsPerTick = 0.1 * scaleX
  return new NoteCoordTransform(
    pixelsPerTick,
    keyHeight,
    127)
}

PianoRoll.propTypes = {
  player: PropTypes.object.isRequired,
  quantizer: PropTypes.object.isRequired,
  endTick: PropTypes.number.isRequired,
  scaleX: PropTypes.number.isRequired,
  scaleY: PropTypes.number.isRequired,
  autoScroll: PropTypes.bool.isRequired,
  onClickKey: PropTypes.func.isRequired,
  mouseMode: PropTypes.number.isRequired
}

PianoRoll.defaultProps = {
  endTick: 400,
  scaleX: 1,
  scaleY: 1,
  autoScroll: false
}

export default fitToContainer({
  width: "100%",
  height: "100%"
})(inject(({ rootStore: {
  song: { selectedTrack: track, endOfSong: endTick, measureList: { beats } },
  pianoRollStore: s,
  rootViewStore: { theme },
  services: { player, quantizer },
  dispatch
} }) => ({
    track,
    endTick,
    beats,
    theme,
    events: track.events.toJS(), // 変更が反映されるように toJS() する
    scaleX: s.scaleX,
    scaleY: s.scaleY,
    autoScroll: s.autoScroll,
    selection: s.selection,
    scrollLeft: s.scrollLeft,
    setScrollLeft: v => s.scrollLeft = v,
    scrollTop: s.scrollTop,
    setScrollTop: v => s.scrollTop = v,
    controlMode: s.controlMode,
    setControlMode: v => s.controlMode = v,
    cursorPosition: s.cursorPosition,
    setCursorPosition: v => s.cursorPosition = v,
    notesCursor: s.notesCursor,
    setNotesCursor: v => s.notesCursor = v,
    mouseMode: s.mouseMode,
    quantizer,
    player,
    dispatch,
    onChangeTool: () => s.mouseMode = (s.mouseMode === 0 ? 1 : 0),
    onClickKey: (noteNumber) => { console.log(noteNumber) }
  }))(observer(stateful)))
<|endoftext|>


<commit_before>import Immutable from 'immutable'
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { POST } from '../constants/action_types'
import * as MAPPING_TYPES from '../constants/mapping_types'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectParamsToken, selectParamsUsername } from '../selectors/params'
import { selectPost } from '../selectors/post'
import { selectStreamType } from '../selectors/stream'
import { loadComments, loadPostDetail, toggleLovers, toggleReposters } from '../actions/posts'
import { ErrorState4xx } from '../components/errors/Errors'
import { Paginator } from '../components/streams/Paginator'
import { PostDetail, PostDetailError } from '../components/views/PostDetail'

export function shouldContainerUpdate(thisProps, nextProps, thisState, nextState) {
  if (!nextProps.author || !nextProps.post) { return false }
  return !Immutable.is(nextProps.post, thisProps.post) ||
    ['isLoggedIn', 'paramsToken', 'paramsUsername'].some(prop =>
      nextProps[prop] !== thisProps[prop],
    ) ||
    ['renderType'].some(prop => nextState[prop] !== thisState[prop])
}

export function mapStateToProps(state, props) {
  const post = selectPost(state, props, true)
  return {
    author: state.json.getIn([MAPPING_TYPES.USERS, post.get('authorId')], null),
    isLoggedIn: selectIsLoggedIn(state),
    paramsToken: selectParamsToken(state, props),
    paramsUsername: selectParamsUsername(state, props),
    post,
    streamType: selectStreamType(state),
  }
}

class PostDetailContainer extends Component {

  static propTypes = {
    author: PropTypes.object,
    dispatch: PropTypes.func.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    post: PropTypes.object,
    paramsToken: PropTypes.string.isRequired,
    paramsUsername: PropTypes.string.isRequired,
  }

  static defaultProps = {
    author: null,
    post: null,
  }

  static preRender = (store, routerState) => {
    const params = routerState.params
    return store.dispatch(loadPostDetail(`~${params.token}`, `~${params.username}`))
  }

  componentWillMount() {
    const { dispatch, paramsToken, paramsUsername, post } = this.props
    if (post) {
      this.lovesWasOpen = post.get('showLovers')
      this.repostsWasOpen = post.get('showReposters')
    }
    this.state = { renderType: POST.DETAIL_REQUEST }
    dispatch(loadPostDetail(`~${paramsToken}`, `~${paramsUsername}`))
  }

  componentWillReceiveProps(nextProps) {
    const { dispatch, paramsToken, paramsUsername } = this.props
    if (paramsToken !== nextProps.paramsToken || paramsUsername !== nextProps.paramsUsername) {
      dispatch(loadPostDetail(`~${nextProps.paramsToken}`, `~${nextProps.paramsUsername}`))
    }
    switch (nextProps.streamType) {
      case POST.DETAIL_FAILURE:
      case POST.DETAIL_REQUEST:
      case POST.DETAIL_SUCCESS:
        this.setState({ renderType: nextProps.streamType })
        break
      default:
        break
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shouldContainerUpdate(this.props, nextProps, this.state, nextState)
  }

  componentWillUnmount() {
    const { dispatch, isLoggedIn, post } = this.props
    // this prevents the lover/reposters from firing since logout clears the json store
    if (!isLoggedIn) { return }
    if (!this.lovesWasOpen) {
      dispatch(toggleLovers(post, false))
    }
    if (!this.repostsWasOpen) {
      dispatch(toggleReposters(post, false))
    }
  }

  render() {
    const { author, paramsToken, post } = this.props
    const { renderType } = this.state
    // render loading/failure if we don't have an initial post
    if (!post || !post.get('id')) {
      if (renderType === POST.DETAIL_REQUEST) {
        return (

            <Paginator className="isBusy" />

        )
      } else if (renderType === POST.DETAIL_FAILURE) {
        return (
          <PostDetailError>
            <ErrorState4xx />
          </PostDetailError>
        )
      }
      return null
    }
    const props = {
      author,
      hasEditor: author && author.get('hasCommentingEnabled') && !(post.get('isReposting') || post.get('isEditing')),
      key: `postDetail_${paramsToken}`,
      post,
      streamAction: author && author.get('hasCommentingEnabled') ? loadComments(post.get('id'), false) : null,
    }
    return <PostDetail {...props} />
  }
}

export default connect(mapStateToProps)(PostDetailContainer)

<commit_msg>Remove a non-used argument<commit_after>import Immutable from 'immutable'
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { POST } from '../constants/action_types'
import * as MAPPING_TYPES from '../constants/mapping_types'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectParamsToken, selectParamsUsername } from '../selectors/params'
import { selectPost } from '../selectors/post'
import { selectStreamType } from '../selectors/stream'
import { loadComments, loadPostDetail, toggleLovers, toggleReposters } from '../actions/posts'
import { ErrorState4xx } from '../components/errors/Errors'
import { Paginator } from '../components/streams/Paginator'
import { PostDetail, PostDetailError } from '../components/views/PostDetail'

export function shouldContainerUpdate(thisProps, nextProps, thisState, nextState) {
  if (!nextProps.author || !nextProps.post) { return false }
  return !Immutable.is(nextProps.post, thisProps.post) ||
    ['isLoggedIn', 'paramsToken', 'paramsUsername'].some(prop =>
      nextProps[prop] !== thisProps[prop],
    ) ||
    ['renderType'].some(prop => nextState[prop] !== thisState[prop])
}

export function mapStateToProps(state, props) {
  const post = selectPost(state, props)
  return {
    author: state.json.getIn([MAPPING_TYPES.USERS, post.get('authorId')], null),
    isLoggedIn: selectIsLoggedIn(state),
    paramsToken: selectParamsToken(state, props),
    paramsUsername: selectParamsUsername(state, props),
    post,
    streamType: selectStreamType(state),
  }
}

class PostDetailContainer extends Component {

  static propTypes = {
    author: PropTypes.object,
    dispatch: PropTypes.func.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    post: PropTypes.object,
    paramsToken: PropTypes.string.isRequired,
    paramsUsername: PropTypes.string.isRequired,
  }

  static defaultProps = {
    author: null,
    post: null,
  }

  static preRender = (store, routerState) => {
    const params = routerState.params
    return store.dispatch(loadPostDetail(`~${params.token}`, `~${params.username}`))
  }

  componentWillMount() {
    const { dispatch, paramsToken, paramsUsername, post } = this.props
    if (post) {
      this.lovesWasOpen = post.get('showLovers')
      this.repostsWasOpen = post.get('showReposters')
    }
    this.state = { renderType: POST.DETAIL_REQUEST }
    dispatch(loadPostDetail(`~${paramsToken}`, `~${paramsUsername}`))
  }

  componentWillReceiveProps(nextProps) {
    const { dispatch, paramsToken, paramsUsername } = this.props
    if (paramsToken !== nextProps.paramsToken || paramsUsername !== nextProps.paramsUsername) {
      dispatch(loadPostDetail(`~${nextProps.paramsToken}`, `~${nextProps.paramsUsername}`))
    }
    switch (nextProps.streamType) {
      case POST.DETAIL_FAILURE:
      case POST.DETAIL_REQUEST:
      case POST.DETAIL_SUCCESS:
        this.setState({ renderType: nextProps.streamType })
        break
      default:
        break
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return shouldContainerUpdate(this.props, nextProps, this.state, nextState)
  }

  componentWillUnmount() {
    const { dispatch, isLoggedIn, post } = this.props
    // this prevents the lover/reposters from firing since logout clears the json store
    if (!isLoggedIn) { return }
    if (!this.lovesWasOpen) {
      dispatch(toggleLovers(post, false))
    }
    if (!this.repostsWasOpen) {
      dispatch(toggleReposters(post, false))
    }
  }

  render() {
    const { author, paramsToken, post } = this.props
    const { renderType } = this.state
    // render loading/failure if we don't have an initial post
    if (!post || !post.get('id')) {
      if (renderType === POST.DETAIL_REQUEST) {
        return (

            <Paginator className="isBusy" />

        )
      } else if (renderType === POST.DETAIL_FAILURE) {
        return (
          <PostDetailError>
            <ErrorState4xx />
          </PostDetailError>
        )
      }
      return null
    }
    const props = {
      author,
      hasEditor: author && author.get('hasCommentingEnabled') && !(post.get('isReposting') || post.get('isEditing')),
      key: `postDetail_${paramsToken}`,
      post,
      streamAction: author && author.get('hasCommentingEnabled') ? loadComments(post.get('id'), false) : null,
    }
    return <PostDetail {...props} />
  }
}

export default connect(mapStateToProps)(PostDetailContainer)

<|endoftext|>


<commit_before>// based on feross/run-parallel
module.exports = function (tasks, cb) {
  var results, pending, errors = []
  if (Array.isArray(tasks)) {
    results = []
    pending = tasks.length
  }

  function done (err, result) {
  	if (result) {
    	results.push(result)
    }
    if (err) {
    	errors.push(err);
    }
    if (--pending === 0) {
      cb && cb(errors.length ? errors : null, results)
      cb = null
    }
  }

  if (!pending) {
    // empty
    cb && cb(null, results)
    cb = null
  } else {
    // array
    tasks.forEach(function (task) {
      task(done)
    })
  }
}<commit_msg>[=] only one call of done callback per task<commit_after>// based on feross/run-parallel
module.exports = function (tasks, cb) {
  var results, pending, completed, errors = [];
  if (Array.isArray(tasks)) {
    results = []
    pending = tasks.length
    completed = Array.apply(null, new Array(tasks.length))
  }

  function done (i, err, result) {
  	if (completed[i]) {
  		return;
  	}
  	completed[i] = true;
  	if (err) {
    	errors.push(err);
    } else if (result) {
    	results.push(result);
    }
    if (--pending === 0) {
      cb && cb(errors.length ? errors : null, results)
      cb = null
    }
  }

  if (!pending) {
    // empty
    cb && cb(null, results)
    cb = null
  } else {
    // array
    tasks.forEach(function (task, i) {
      task(done.bind(undefined, i))
    })
  }
}<|endoftext|>