<commit_before>;(function () {
    var Map = function () {
        this.keys = [];
        this.values = [];
    };

    Map.prototype.set = function (key, value) {
        this.keys.push(key);
        this.values.push(value);
        return value;
    };

    Map.prototype.get = function (key) {
        var index = -1;
        for (var i = 0; i < this.keys.length; i++) {
            if (this.keys[i] === key) {
                index = i;
                break;
            }
        }
        if (index >= 0) {
            return this.values[i];
        }
    };

    Map.prototype.remove = function (key) {
        var index = -1;
        for (var i = 0; i < this.keys.length; i++) {
            if (this.keys[i] === key) {
                index = i;
                break;
            }
        }
        if (index >= 0) {
            this.keys.splice(index, 1);
            this.values.splice(index, 1);
        }
    };

    var Utility = (function (){
        return {
            each: function (obj, iterator) {
                if (obj && obj.length) {
                    obj.forEach(iterator);
                } else if (typeof obj === 'object') {
                    for (var i in obj) {
                        if (obj.hasOwnProperty(i) && iterator(i, obj[i]) === false) {
                            return;
                        }
                    }
                }
            },
            keys: function (obj) {
                var keys = [];
                Utility.each(obj, function (key) {
                    keys.push(key);
                });
                return keys;
            },

            css: function (dom, styles, value) {
                var wrapProperty = function (property) {
                    var needCompatible = [
                        'transitionDelay',
                        'transitionProperty',
                        'transitionDuration',
                        'transitionTimingFunction',
                        'transform'
                    ];
                    if (needCompatible.indexOf(property) > -1 && eventPrefix) {
                        property = eventPrefix + Utility.firstUppercase(property);
                    }
                    return property;
                };

                if (typeof styles === 'object') {
                    Utility.each(styles, function (property, value) {
                        dom.style[wrapProperty(property)] = value;
                    });
                } else if (typeof styles === 'string') {
                    if (value !== undefined) {
                        dom.style[wrapProperty(styles)] = value;
                    }
                    return dom.style[wrapProperty(styles)];
                }
            },
            extend: function (obj) {
                var toExtendObjs = [];
                for (var i = 1; i < arguments.length; i ++) {
                    toExtendObjs.unshift(arguments[i]);
                }
                Utility.each(toExtendObjs, function (toExtendObj) {
                    Utility.each(toExtendObj, function (key, value) {
                        obj[key] = value;
                    });
                });
                return obj;
            },
            getComputedStyle: function (dom) {
                return window.getComputedStyle(dom);
            },
            firstUppercase: function (string) {
                return string.replace(/^\w/, function (letter) {
                    return letter.toUpperCase();
                });
            },
            addEvent: function (dom, eventType, listener, capture) {
                dom.addEventListener(eventType, listener, capture);
            },
            removeEvent: function (dom, eventType, listener, capture) {
                dom.removeEventListener(eventType, listener, capture);
            },
            // need be attention to background-size, max-height, vertical-align
            diffStyle: function (dom, targetClassName, deep) {
                 var diff = function (originDom, targetDom) {
                    var originStyles = Utility.getComputedStyle(originDom);
                    var targetStyles = Utility.getComputedStyle(targetDom);
                    var properties = [];
                    var needDiffStyles = ['width', 'height', 'padding', 'margin',
                    'lineHeight', 'border-width', 'font-size','letter-space', 'word-space',
                    'left', 'right', 'top', 'bottom', 'border-radius', 'background-color',
                    'color', 'border-color', 'opacity', 'transform', 'text-shadow', 'box-shadow',
                    'background-size', 'background-position', 'border-spacing', 'clip',
                    'max-width', 'max-height', 'min-width', 'min-height', 'outline',
                    'text-indent', 'vertical-align', 'z-index'];

                    for (var i = 0; i < needDiffStyles.length; i++) {
                        if ((needDiffStyles[i] === 'left' ||
                            needDiffStyles[i] === 'right' ||
                            needDiffStyles[i] === 'top' ||
                            needDiffStyles[i] === 'bottom') && originStyles[needDiffStyles[i]] === 'auto') {
                            continue;
                        }

                        if (originStyles[needDiffStyles[i]] !== targetStyles[needDiffStyles[i]]) {
                            properties.push(needDiffStyles[i]);
                        }
                    }

                    targetTestElem.remove();
                    return properties;
                };

                var targetTestElem = deep ? dom.cloneNode(true): document.createElement(dom.tagName);
                targetTestElem.style.visibility = 'hidden';
                targetTestElem.className = targetClassName;
                dom.parentNode.appendChild(targetTestElem);

                var diffResult = [];
                if (deep) {
                    var stack = [{
                        node: dom,
                        targetNode: targetTestElem
                    }];
                    while (stack.length) {
                        var item = stack.pop();
                        diffResult.push({
                            elem: item.node,
                            properties: diff(item.node, item.targetNode)
                        });

                        var nodeChildren = item.node.children;
                        var targetNodeChildren = item.targetNode.children;

                        for (var i = 0; i < nodeChildren.length; i++) {
                            stack.push({
                                node: nodeChildren[i],
                                targetNode: targetNodeChildren[i]
                            });
                        }

                    }
                } else {
                    diffResult.push({
                        elem: dom,
                        properties: diff(dom, targetTestElem)
                    });
                }
                return diffResult;
            },
            getTransition: function (properties, options) {
                var delay = options.delay || '0ms';
                var duration = 0;
                if (options.duration !== 0) {
                    duration = options.duration || '300ms';
                }

                var ease = options.ease || 'linear';
                if (typeof delay === 'number') {
                    delay = delay + 'ms';
                }
                if (typeof duration === 'number') {
                    duration = duration + 'ms';
                }

                return {
                    transitionProperty: properties.join(','),
                    transitionDelay: delay,
                    transitionDuration: duration,
                    transitionTimingFunction: ease
                };
            },
            invokeIfExists: function (func, args, context) {
                if (typeof func === 'function') {
                    func.apply(context, args);
                }
            },
            relayout: function (dom) {
                Utility.getComputedStyle(dom).width;
            }
        };
    })();

    var list = [],
        vendors = { Webkit: 'webkit', Moz: '', O: 'o' },
        cssPrefix = '',
        eventPrefix = '',
        testEl = document.createElement('div'),
        simpleanMap = new Map();

    Utility.each(vendors, function(vendor, event) {
        if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
          cssPrefix = '-' + vendor.toLowerCase() + '-';
          eventPrefix = event;
          return false;
        }
    });

    var Simplean = function (dom) {
        if (!dom instanceof HTMLElement) {
            throw new Error('Simplean must initialize by dom');
        }
        var simplean = simpleanMap.get(dom);
        if (simplean) {
            return simplean;
        } else {
            return simpleanMap.set(dom, new _Simplean(dom));
        }

    };

    Simplean.destroy = function (dom) {
        simpleanMap.remove(dom);
    };

    var _Simplean = function (dom) {
        this._dom = dom;
        this._phaseList = [];
        this._phaseIndex = 0;
        this._status = 'unstart';
    };

    _Simplean.prototype._start = function () {
        if (this._status === 'start') {
            return;
        }
        var self = this;
        this._status = 'start';
        var start = function () {
            var phase = self._phaseList[self._phaseIndex];
            if (!phase || phase.status !== 'unstart') {
                self._status ='stop';
                return;
            }
            self._phaseIndex += 1;

            if (phase.diffClassName) {
                var originClassName = self._dom.className;
                var targetClassName = originClassName;

                var classNames = phase.diffClassName.split(' ');

                if (classNames[0] === '-') {
                    for (var i = 1; i < classNames.length; i++) {
                        if (self._dom.classList.contains(classNames[i])) {
                            targetClassName = targetClassName.replace(classNames[i], '');
                        }
                    }
                } else if (classNames[0] === '+') {
                    for (var i = 1; i < classNames.length; i++) {
                        if (!self._dom.classList.contains(classNames[i])) {
                            targetClassName += ' ' + classNames[i];
                        }
                    }
                }
                if (targetClassName === originClassName) {
                    setTimeout(function () {
                        start();
                    }, 0);
                    return;
                }

                var diffResult = Utility.diffStyle(self._dom, targetClassName, phase.options.deep);
                phase.transitionList = diffResult.map(function (result) {
                    return {
                        elem: result.elem,
                        transition: Utility.getTransition(result.properties, phase.options)
                    };
                });
                phase.targetClassName = targetClassName;
            }

            self._step(phase, function () {
                Utility.invokeIfExists(phase.onStart);
            }, function () {
                Utility.invokeIfExists(phase.onStop);
                start();
            });
        };
        start();
    };

    _Simplean.prototype._step = function (phase, onStart, onStop) {
        var self = this;
        var eventType = eventPrefix ? eventPrefix + Utility.firstUppercase('transitionEnd') : 'transitionend';

        var throughPhase = function () {
            phase.status = 'start';
            Utility.invokeIfExists(onStart);

            Utility.addEvent(self._dom, eventType, onPhaseEnd);

            Utility.relayout(self._dom);

            Utility.each(phase.transitionList, function (item) {
                if (item.transition.transitionProperty) {
                    Utility.css(item.elem, item.transition);
                }
            });

            if (phase.styles) {
                Utility.css(self._dom, phase.styles);
            } else if (phase.targetClassName) {
                self._dom.className = phase.targetClassName;
            }
            Utility.relayout(self._dom);

            if (phase.transitionList[0].transition.transitionDuration === '0ms') {
                setTimeout(function () {
                    onPhaseEnd();
                }, 0);
            } else {
                setTimeout(function () {
                    if (phase.status !== 'stop') {
                        onPhaseEnd();
                    }
                }, phase.transitionList[0].transition.transitionDuration.replace('ms', ''));
            }
        };
        var onPhaseEnd = function () {
            if (phase.status === 'stop') {
                return;
            }
            phase.status = 'stop';

            Utility.each(phase.transitionList, function (item) {
                if (item.transition.transitionProperty) {
                    Utility.css(item.elem, 'transition', '');
                }
            });

            Utility.removeEvent(self._dom, eventType, onPhaseEnd);
            setTimeout(function () {
                Utility.invokeIfExists(onStop);
            }, 0);
        };
        throughPhase();
    };

    _Simplean.prototype._setClass = function (diffClassName, options) {
        if (!diffClassName) {
            return;
        }
        options = options || {};

        this._phaseList.push({
            diffClassName: diffClassName,
            options: options,
            onStart: options.onStart,
            onStop: options.onStop,
            status: 'unstart'
        });
        this._start();
    };

    _Simplean.prototype.addClass = function (className, options) {
        this._setClass('+ ' + className, options);
        return this;
    };

    _Simplean.prototype.removeClass = function (className, options) {
        this._setClass('- ' + className, options);
        return this;
    };

    _Simplean.prototype.to = function (styles, options) {
        var self = this;
        styles = styles || {};
        options = options || {};

        self._phaseList.push({
            styles: styles,
            transitionList: [{
                elem: self._dom,
                transition: Utility.getTransition(Utility.keys(styles), options)
            }],
            options: options,
            onStart: options.onStart,
            onStop: options.onStop,
            status: 'unstart'
        });
        self._start();
        return self;
    };

    window.Simplean = Simplean;
    if (typeof define !== 'undefined' &&  define.amd) {
        define(function () {
            return Simplean;
        });
    }
})();<commit_msg>add some comment<commit_after>;(function () {
    /**
    * Map
    * CLASS
    **/
    var Map = function () {
        this.keys = [];
        this.values = [];
    };

    /**
    * Map.set
    **/
    Map.prototype.set = function (key, value) {
        this.keys.push(key);
        this.values.push(value);
        return value;
    };

    /**
    * Map.get
    **/
    Map.prototype.get = function (key) {
        var index = -1;
        for (var i = 0; i < this.keys.length; i++) {
            if (this.keys[i] === key) {
                index = i;
                break;
            }
        }
        if (index >= 0) {
            return this.values[i];
        }
    };

    /**
    * Map.remove
    **/
    Map.prototype.remove = function (key) {
        var index = -1;
        for (var i = 0; i < this.keys.length; i++) {
            if (this.keys[i] === key) {
                index = i;
                break;
            }
        }
        if (index >= 0) {
            this.keys.splice(index, 1);
            this.values.splice(index, 1);
        }
    };

    var Utility = (function (){
        return {
            each: function (obj, iterator) {
                if (obj && obj.length) {
                    obj.forEach(iterator);
                } else if (typeof obj === 'object') {
                    for (var i in obj) {
                        if (obj.hasOwnProperty(i) && iterator(i, obj[i]) === false) {
                            return;
                        }
                    }
                }
            },
            keys: function (obj) {
                var keys = [];
                Utility.each(obj, function (key) {
                    keys.push(key);
                });
                return keys;
            },

            css: function (dom, styles, value) {
                var wrapProperty = function (property) {
                    var needCompatible = [
                        'transitionDelay',
                        'transitionProperty',
                        'transitionDuration',
                        'transitionTimingFunction',
                        'transform'
                    ];
                    if (needCompatible.indexOf(property) > -1 && eventPrefix) {
                        property = eventPrefix + Utility.firstUppercase(property);
                    }
                    return property;
                };

                if (typeof styles === 'object') {
                    Utility.each(styles, function (property, value) {
                        dom.style[wrapProperty(property)] = value;
                    });
                } else if (typeof styles === 'string') {
                    if (value !== undefined) {
                        dom.style[wrapProperty(styles)] = value;
                    }
                    return dom.style[wrapProperty(styles)];
                }
            },
            extend: function (obj) {
                var toExtendObjs = [];
                for (var i = 1; i < arguments.length; i ++) {
                    toExtendObjs.unshift(arguments[i]);
                }
                Utility.each(toExtendObjs, function (toExtendObj) {
                    Utility.each(toExtendObj, function (key, value) {
                        obj[key] = value;
                    });
                });
                return obj;
            },
            getComputedStyle: function (dom) {
                return window.getComputedStyle(dom);
            },
            firstUppercase: function (string) {
                return string.replace(/^\w/, function (letter) {
                    return letter.toUpperCase();
                });
            },
            addEvent: function (dom, eventType, listener, capture) {
                dom.addEventListener(eventType, listener, capture);
            },
            removeEvent: function (dom, eventType, listener, capture) {
                dom.removeEventListener(eventType, listener, capture);
            },
            // need be attention to background-size, max-height, vertical-align
            diffStyle: function (dom, targetClassName, deep) {
                 var diff = function (originDom, targetDom) {
                    var originStyles = Utility.getComputedStyle(originDom);
                    var targetStyles = Utility.getComputedStyle(targetDom);
                    var properties = [];
                    var needDiffStyles = ['width', 'height', 'padding', 'margin',
                    'lineHeight', 'border-width', 'font-size','letter-space', 'word-space',
                    'left', 'right', 'top', 'bottom', 'border-radius', 'background-color',
                    'color', 'border-color', 'opacity', 'transform', 'text-shadow', 'box-shadow',
                    'background-size', 'background-position', 'border-spacing', 'clip',
                    'max-width', 'max-height', 'min-width', 'min-height', 'outline',
                    'text-indent', 'vertical-align', 'z-index'];

                    for (var i = 0; i < needDiffStyles.length; i++) {
                        if ((needDiffStyles[i] === 'left' ||
                            needDiffStyles[i] === 'right' ||
                            needDiffStyles[i] === 'top' ||
                            needDiffStyles[i] === 'bottom') && originStyles[needDiffStyles[i]] === 'auto') {
                            continue;
                        }

                        if (originStyles[needDiffStyles[i]] !== targetStyles[needDiffStyles[i]]) {
                            properties.push(needDiffStyles[i]);
                        }
                    }

                    targetTestElem.remove();
                    return properties;
                };

                var targetTestElem = deep ? dom.cloneNode(true): document.createElement(dom.tagName);
                targetTestElem.style.visibility = 'hidden';
                targetTestElem.className = targetClassName;
                dom.parentNode.appendChild(targetTestElem);

                var diffResult = [];
                if (deep) {
                    var stack = [{
                        node: dom,
                        targetNode: targetTestElem
                    }];
                    while (stack.length) {
                        var item = stack.pop();
                        diffResult.push({
                            elem: item.node,
                            properties: diff(item.node, item.targetNode)
                        });

                        var nodeChildren = item.node.children;
                        var targetNodeChildren = item.targetNode.children;

                        for (var i = 0; i < nodeChildren.length; i++) {
                            stack.push({
                                node: nodeChildren[i],
                                targetNode: targetNodeChildren[i]
                            });
                        }

                    }
                } else {
                    diffResult.push({
                        elem: dom,
                        properties: diff(dom, targetTestElem)
                    });
                }
                return diffResult;
            },
            getTransition: function (properties, options) {
                var delay = options.delay || '0ms';
                var duration = 0;
                if (options.duration !== 0) {
                    duration = options.duration || '300ms';
                }

                var ease = options.ease || 'linear';
                if (typeof delay === 'number') {
                    delay = delay + 'ms';
                }
                if (typeof duration === 'number') {
                    duration = duration + 'ms';
                }

                return {
                    transitionProperty: properties.join(','),
                    transitionDelay: delay,
                    transitionDuration: duration,
                    transitionTimingFunction: ease
                };
            },
            invokeIfExists: function (func, args, context) {
                if (typeof func === 'function') {
                    func.apply(context, args);
                }
            },
            relayout: function (dom) {
                Utility.getComputedStyle(dom).width;
            }
        };
    })();

    var list = [],
        vendors = { Webkit: 'webkit', Moz: '', O: 'o' },
        cssPrefix = '',
        eventPrefix = '',
        testEl = document.createElement('div'),
        simpleanMap = new Map();

    Utility.each(vendors, function(vendor, event) {
        if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
          cssPrefix = '-' + vendor.toLowerCase() + '-';
          eventPrefix = event;
          return false;
        }
    });

    var Simplean = function (dom) {
        if (!dom instanceof HTMLElement) {
            throw new Error('Simplean must initialize by dom');
        }
        var simplean = simpleanMap.get(dom);
        if (simplean) {
            return simplean;
        } else {
            return simpleanMap.set(dom, new _Simplean(dom));
        }

    };

    Simplean.destroy = function (dom) {
        simpleanMap.remove(dom);
    };

    var _Simplean = function (dom) {
        this._dom = dom;
        this._phaseList = [];
        this._phaseIndex = 0;
        this._status = 'unstart';
    };

    _Simplean.prototype._start = function () {
        if (this._status === 'start') {
            return;
        }
        var self = this;
        this._status = 'start';
        var start = function () {
            // get phase
            var phase = self._phaseList[self._phaseIndex];
            if (!phase || phase.status !== 'unstart') {
                self._status ='stop';
                return;
            }
            self._phaseIndex += 1;

            /**
            * calculate transitionList. If phase.diffClassName is a string, calculate dom target class also.
            */
            if (phase.diffClassName) {
                var originClassName = self._dom.className;
                var targetClassName = originClassName;

                var classNames = phase.diffClassName.split(' ');

                if (classNames[0] === '-') {
                    for (var i = 1; i < classNames.length; i++) {
                        if (self._dom.classList.contains(classNames[i])) {
                            targetClassName = targetClassName.replace(classNames[i], '');
                        }
                    }
                } else if (classNames[0] === '+') {
                    for (var i = 1; i < classNames.length; i++) {
                        if (!self._dom.classList.contains(classNames[i])) {
                            targetClassName += ' ' + classNames[i];
                        }
                    }
                }
                if (targetClassName === originClassName) {
                    setTimeout(function () {
                        start();
                    }, 0);
                    return;
                }

                var diffResult = Utility.diffStyle(self._dom, targetClassName, phase.options.deep);
                phase.transitionList = diffResult.map(function (result) {
                    return {
                        elem: result.elem,
                        transition: Utility.getTransition(result.properties, phase.options)
                    };
                });
                phase.targetClassName = targetClassName;
            } else {

            }

            // start one animation
            self._step(phase, function () {
                Utility.invokeIfExists(phase.onStart);
            }, function () {
                Utility.invokeIfExists(phase.onStop);
                start();
            });
        };
        start();
    };

    _Simplean.prototype._step = function (phase, onStart, onStop) {
        var self = this;
        var eventType = eventPrefix ? eventPrefix + Utility.firstUppercase('transitionEnd') : 'transitionend';

        var throughPhase = function () {
            phase.status = 'start';
            Utility.invokeIfExists(onStart);

            Utility.addEvent(self._dom, eventType, onPhaseEnd);

            Utility.relayout(self._dom);

            Utility.each(phase.transitionList, function (item) {
                if (item.transition.transitionProperty) {
                    Utility.css(item.elem, item.transition);
                }
            });

            if (phase.styles) {
                Utility.css(self._dom, phase.styles);
            } else if (phase.targetClassName) {
                self._dom.className = phase.targetClassName;
            }
            Utility.relayout(self._dom);

            if (phase.transitionList[0].transition.transitionDuration === '0ms') {
                setTimeout(function () {
                    onPhaseEnd();
                }, 0);
            } else {
                setTimeout(function () {
                    if (phase.status !== 'stop') {
                        onPhaseEnd();
                    }
                }, phase.transitionList[0].transition.transitionDuration.replace('ms', ''));
            }
        };
        var onPhaseEnd = function () {
            if (phase.status === 'stop') {
                return;
            }
            phase.status = 'stop';

            Utility.each(phase.transitionList, function (item) {
                if (item.transition.transitionProperty) {
                    Utility.css(item.elem, 'transition', '');
                }
            });

            Utility.removeEvent(self._dom, eventType, onPhaseEnd);
            setTimeout(function () {
                Utility.invokeIfExists(onStop);
            }, 0);
        };
        throughPhase();
    };

    _Simplean.prototype._setClass = function (diffClassName, options) {
        if (!diffClassName) {
            return;
        }
        options = options || {};

        this._phaseList.push({
            diffClassName: diffClassName,
            options: options,
            onStart: options.onStart,
            onStop: options.onStop,
            status: 'unstart'
        });
        this._start();
    };

    _Simplean.prototype.addClass = function (className, options) {
        this._setClass('+ ' + className, options);
        return this;
    };

    _Simplean.prototype.removeClass = function (className, options) {
        this._setClass('- ' + className, options);
        return this;
    };

    _Simplean.prototype.to = function (styles, options) {
        var self = this;
        styles = styles || {};
        options = options || {};

        self._phaseList.push({
            styles: styles,
            transitionList: [{
                elem: self._dom,
                transition: Utility.getTransition(Utility.keys(styles), options)
            }],
            options: options,
            onStart: options.onStart,
            onStop: options.onStop,
            status: 'unstart'
        });
        self._start();
        return self;
    };

    window.Simplean = Simplean;
    if (typeof define !== 'undefined' &&  define.amd) {
        define(function () {
            return Simplean;
        });
    }
})();<|endoftext|>


<commit_before>/**
 *

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

 * */
/**
 * 配对信息管理对象
 */
function MatchInfoMgr(window, parent) {
	this.wnd = window;
	this.parent = parent;
	this._init();
}
MatchInfoMgr.prototype._init = function() {
	this.sameUser={};
	this.opsiteUser={};
	this.users={};
	this.opsiteUl = $('
');
	this.opsiteUl.addClass('list');
	this.opsiteUl.addClass('clearfix');

	this.sameUl = $('
');
	this.sameUl.addClass('list');
	this.sameUl.addClass('clearfix');

	this.parent.append(this.opsiteUl);
	this.parent.append(this.sameUl);
	/**
	 *

            <button class="btn btn-default btn-wide" id="refresh-btn">换一组</button>
            <button type="submit" class="btn btn-primary btn-wide">确定</button>

	 */
	this.btnArea=$('
');
	this.btnArea.addClass('submit-area');
	//换一组 按钮
	this.refreshBtn=$('<button>');
	this.refreshBtn.addClass('btn');
	this.refreshBtn.addClass('btn-default');
	this.refreshBtn.addClass('btn-wide');
	this.refreshBtn.text('换一组');
	this.refreshBtn.owner=this;
	var self=this;
	this.refreshBtn.bind('click', function() {
		self.refresh();
	 });
	this.btnArea.append(this.refreshBtn);
	//FIXME 2014 1109 确定按钮感觉没有存在的必要，暂时不管他
	this.parent.append(this.btnArea);
};
MatchInfoMgr.prototype.getRefreshBtn=function(){
	return this.refreshBtn;
};
/**
 * 刷新
 */
MatchInfoMgr.prototype.refresh = function() {
	this.clear();
	var self = this;
	$.ajax({
	    type: "POST",
	    url: "/zhaoxi/match.do?action=getMatchInfo",
	    contentType: "application/json; charset=utf-8",
	    dataType: "json",
	    success: function(data) {
	    	self.userInfo = data.user;
			self.infoId = data.id;
			self._canMatch=data.canMatch;
			var sameUsers = data.same;
			if (sameUsers) {
				for (var i = 0; i < sameUsers.length; i++) {
					self._addSame(sameUsers[i]);
				}
			}
			var opsiteUsers = data.opposite;
			if (opsiteUsers) {
				for (var i = 0; i < opsiteUsers.length; i++) {
					self._addOpsite(opsiteUsers[i]);
				}
			}
	    },
	    error: function (xhr, textStatus, errorThrown) {
	    	alert('出现错误' + textStatus);
	    }
	});
};
MatchInfoMgr.prototype._addSame = function(user) {
	this._addUser(user, true);
};
MatchInfoMgr.prototype._addOpsite = function(user) {
	this._addUser(user, false);
};
/**
 *
 */
MatchInfoMgr.prototype._addUser = function(user, isSame) {
	var userInfo = new MatchUser(user, this, isSame);
	userInfo.init();
};
/**
 * 获取当前登录id
 */
MatchInfoMgr.prototype.getUserId = function() {
	return this.userId;
};
/**
 * 设置userid
 *
 * @param userId
 */
MatchInfoMgr.prototype.setUserId = function(userId) {
	this.userId = userId;
};
/**
 * 获取当前连线组的id
 */
MatchInfoMgr.prototype.getInfoId = function() {
	return this.infoId;
};
/**
 * 当前登录者的信息
 */
MatchInfoMgr.prototype.getUserObj = function() {
	return this.userInfo;
};
/**
 * 获取异性列表
 *
 * @returns 返回异性列表的数组
 */
MatchInfoMgr.prototype.getOppositeSex = function() {
return this.opsiteUsers;
};
/**
 * 获取同性
 *
 * @returns
 */
MatchInfoMgr.prototype.getSameSex = function() {
	return this.sameUsers;
};
/**
 *
 * @param id
 */
MatchInfoMgr.prototype.getItem = function(id) {
	return this.users[id];
};
/**
 * 连线动作
 *
 * @param id1
 * @param id2
 */
MatchInfoMgr.prototype.match = function(id1, id2) {
	var self = this;
	$.ajax({
	    type: "POST",
	    url: "/zhaoxi/match.do?action=MatchUser",
	    data: { user: id1, other: id2},
	    success: function(data) {
	    	if(data.suc){
				alert('连线成功！');
		    	self.refresh();
	    	}else{
	    		alert('ops,连线失败了，换个人再试一次吧。'+data.msg);
	    	}
	    },
	    error: function (xhr, textStatus, errorThrown) {
	    	alert('出现错误' + textStatus);
	    }
	});
};
/**
 *清除方法
 */
MatchInfoMgr.prototype.clear=function(){
	this.sameUl.empty();
	this.opsiteUl.empty();
	this.sameUsers={};
	this.opsiteUsers={};
	this.users={};
};
/**
 *是否能够连接
 */
MatchInfoMgr.prototype.canMatch=function(){
	return this._canMatch;
}
/**
 *
 */
function MatchUser(userObj, mgr, isSame) {
	this.userObj = userObj;
	this.mgr = mgr;
	this.isSame = isSame;
}
/**
 *

 *

 *

 * 喜欢做xxx
 *

 *

 * 偶像xxx
 *

 *

 * 其他xxx
 *

 *

 */
MatchUser.prototype.init = function() {
	this.liDom = $('
');
	var self=this;
	//拖动执行函数
	$(this.liDom).draggable({
		stop:function(event,ui){
			if(!self.mgr.canMatch()){
				return false;
			}
			var position=ui.offset;
			var opsiteSex=self.isSame?self.mgr.getOppositeSex():self.mgr.getSameSex();
			if (!opsiteSex) {
				return false;
			};
			$.each(opsiteSex,function(userObjId,value){
				var tagetPosition=value.getPosition();
				//是否重合的算法 逻辑是 二者的定位误差不超过20像素
				if(Math.abs(position.left-tagetPosition.left)<=20&&Math.abs(position.top-tagetPosition.top)<=20){
					if(confirm('确认连线'+self.userObj.name+'和'+value.userObj.name+'吗？')){
						self.mgr.match(self.userObj.id,userObjId);
					}
				};
			});
		}
	});
	//拖动之后回到起始位置
	$(this.liDom).draggable({ revert: true });

	this.imgDiv = $('
');
	this.imgDiv.addClass('photo');
	this.img = $('');
	this.img.attr('src', this.userObj.img);
	this.imgDiv.append(this.img);
	this.liDom.append(this.imgDiv);

	this.tagsDiv = $('
');
	var tags = this.userObj.tags;
	var tag;
	for (var i = 0; i < tags.length; i++) {
		tag = $('
');
		tag.text(tags[i]);
		this.tagsDiv.append(tag);
	}
	this.liDom.append(this.tagsDiv);
	if (!this.isSame) {
		this.flowerDiv = $('
');
		this.flower = $('');
		this.flower.addClass('send-flower');
		this.flower.attr('title','送花');
		this.flower.bind('click',function(){
			$.ajax({
				    type: "POST",
				    url: "../match.do?action=flower",
				    data: { target: self.userObj.id,},
				    success: function(data) {
				    	alert('花已经送出去了，祝你好运');
				    },
				    error: function (xhr, textStatus, errorThrown) {
				    	alert('出现错误' + textStatus);
				    }
				});
		})
		this.flowerDiv.append(this.flower);
		this.liDom.append(this.flowerDiv);
		this.mgr.opsiteUl.append(this.liDom);
		this.mgr.opsiteUsers[this.userObj.id] = this;
	} else {
		this.mgr.sameUl.append(this.liDom);
		this.mgr.sameUsers[this.userObj.id] = this;
	}
	this.mgr.users[this.userObj.id] = this;
};
/**
 *
 */
MatchUser.prototype.canMatch = function(id) {

};
/**
 * 获取用户展示的当前位置
 */
MatchUser.prototype.getPosition=function(){
	return this.liDom.offset();
};
<commit_msg>显示姓名，年龄和tag提示信息<commit_after>/**
 *

喜欢做xxx

偶像xxx

其他xxx

喜欢做xxx

偶像xxx

其他xxx

 * */
/**
 * 配对信息管理对象
 */
function MatchInfoMgr(window, parent) {
	this.wnd = window;
	this.parent = parent;
	this._init();
}
MatchInfoMgr.prototype._init = function() {
	this.sameUser={};
	this.opsiteUser={};
	this.users={};
	this.opsiteUl = $('
');
	this.opsiteUl.addClass('list');
	this.opsiteUl.addClass('clearfix');

	this.sameUl = $('
');
	this.sameUl.addClass('list');
	this.sameUl.addClass('clearfix');

	this.parent.append(this.opsiteUl);
	this.parent.append(this.sameUl);
	/**
	 *

            <button class="btn btn-default btn-wide" id="refresh-btn">换一组</button>
            <button type="submit" class="btn btn-primary btn-wide">确定</button>

	 */
	this.btnArea=$('
');
	this.btnArea.addClass('submit-area');
	//换一组 按钮
	this.refreshBtn=$('<button>');
	this.refreshBtn.addClass('btn');
	this.refreshBtn.addClass('btn-default');
	this.refreshBtn.addClass('btn-wide');
	this.refreshBtn.text('换一组');
	this.refreshBtn.owner=this;
	var self=this;
	this.refreshBtn.bind('click', function() {
		self.refresh();
	 });
	this.btnArea.append(this.refreshBtn);
	//FIXME 2014 1109 确定按钮感觉没有存在的必要，暂时不管他
	this.parent.append(this.btnArea);
};
MatchInfoMgr.prototype.getRefreshBtn=function(){
	return this.refreshBtn;
};
/**
 * 刷新
 */
MatchInfoMgr.prototype.refresh = function() {
	this.clear();
	var self = this;
	$.ajax({
	    type: "POST",
	    url: "/zhaoxi/match.do?action=getMatchInfo",
	    contentType: "application/json; charset=utf-8",
	    dataType: "json",
	    success: function(data) {
	    	self.userInfo = data.user;
			self.infoId = data.id;
			self._canMatch=data.canMatch;
			var sameUsers = data.same;
			if (sameUsers) {
				for (var i = 0; i < sameUsers.length; i++) {
					self._addSame(sameUsers[i]);
				}
			}
			var opsiteUsers = data.opposite;
			if (opsiteUsers) {
				for (var i = 0; i < opsiteUsers.length; i++) {
					self._addOpsite(opsiteUsers[i]);
				}
			}
	    },
	    error: function (xhr, textStatus, errorThrown) {
	    	alert('出现错误' + textStatus);
	    }
	});
};
MatchInfoMgr.prototype._addSame = function(user) {
	this._addUser(user, true);
};
MatchInfoMgr.prototype._addOpsite = function(user) {
	this._addUser(user, false);
};
/**
 *
 */
MatchInfoMgr.prototype._addUser = function(user, isSame) {
	var userInfo = new MatchUser(user, this, isSame);
	userInfo.init();
};
/**
 * 获取当前登录id
 */
MatchInfoMgr.prototype.getUserId = function() {
	return this.userId;
};
/**
 * 设置userid
 *
 * @param userId
 */
MatchInfoMgr.prototype.setUserId = function(userId) {
	this.userId = userId;
};
/**
 * 获取当前连线组的id
 */
MatchInfoMgr.prototype.getInfoId = function() {
	return this.infoId;
};
/**
 * 当前登录者的信息
 */
MatchInfoMgr.prototype.getUserObj = function() {
	return this.userInfo;
};
/**
 * 获取异性列表
 *
 * @returns 返回异性列表的数组
 */
MatchInfoMgr.prototype.getOppositeSex = function() {
return this.opsiteUsers;
};
/**
 * 获取同性
 *
 * @returns
 */
MatchInfoMgr.prototype.getSameSex = function() {
	return this.sameUsers;
};
/**
 *
 * @param id
 */
MatchInfoMgr.prototype.getItem = function(id) {
	return this.users[id];
};
/**
 * 连线动作
 *
 * @param id1
 * @param id2
 */
MatchInfoMgr.prototype.match = function(id1, id2) {
	var self = this;
	$.ajax({
	    type: "POST",
	    url: "/zhaoxi/match.do?action=MatchUser",
	    data: { user: id1, other: id2},
	    success: function(data) {
	    	if(data.suc){
				alert('连线成功！');
		    	self.refresh();
	    	}else{
	    		alert('ops,连线失败了，换个人再试一次吧。'+data.msg);
	    	}
	    },
	    error: function (xhr, textStatus, errorThrown) {
	    	alert('出现错误' + textStatus);
	    }
	});
};
/**
 *清除方法
 */
MatchInfoMgr.prototype.clear=function(){
	this.sameUl.empty();
	this.opsiteUl.empty();
	this.sameUsers={};
	this.opsiteUsers={};
	this.users={};
};
/**
 *是否能够连接
 */
MatchInfoMgr.prototype.canMatch=function(){
	return this._canMatch;
}
/**
 *
 */
function MatchUser(userObj, mgr, isSame) {
	this.userObj = userObj;
	this.mgr = mgr;
	this.isSame = isSame;
}
MatchUser.LINE_SIDE=40;
/**
 *

 *

 *

 * 喜欢做xxx
 *

 *

 * 偶像xxx
 *

 *

 * 其他xxx
 *

 *

 */
MatchUser.prototype.init = function() {
	this.liDom = $('
');
	var self=this;
	//拖动执行函数
	$(this.liDom).draggable({
		stop:function(event,ui){
			if(!self.mgr.canMatch()){
				return false;
			}
			var position=ui.offset;
			var opsiteSex=self.isSame?self.mgr.getOppositeSex():self.mgr.getSameSex();
			if (!opsiteSex) {
				return false;
			};
			$.each(opsiteSex,function(userObjId,value){
				var tagetPosition=value.getPosition();
				//是否重合的算法 逻辑是 二者的定位误差不超过40像素
				if(Math.abs(position.left-tagetPosition.left)<=MatchUser.LINE_SIDE&&Math.abs(position.top-tagetPosition.top)<=MatchUser.LINE_SIDE){
					if(confirm('确认连线'+self.userObj.name+'和'+value.userObj.name+'吗？')){
						self.mgr.match(self.userObj.id,userObjId);
					}
				};
			});
		}
	});
	//拖动之后回到起始位置
	$(this.liDom).draggable({ revert: true });

	this.imgDiv = $('
');
	this.imgDiv.addClass('photo');
	this.img = $('');
	this.img.attr('src', this.userObj.img);
	this.imgDiv.append(this.img);
	this.liDom.append(this.imgDiv);

	this.tagsDiv = $('
');
	//用户名
	var userCapTag = $('
');
	var userCaption=this.userObj.name;
	var userAgeRange='未知年龄段';
	switch(this.userObj.age){
		case(1):{
			userAgeRange='18-20';
			break;
		}
		case(2):{
			userAgeRange='23-26';
			break;
		}
		case(3):{
			userAgeRange='20-23';
			break;
		}
		case(4):{
			userAgeRange='26-30';
			break;
		}
		case(5):{
			userAgeRange='30';
			break;
		}
	}

	userCapTag.text(userCaption+' '+userAgeRange);
	this.tagsDiv.append(userCapTag);

	var tags = this.userObj.tags;
	var tag;
	for (var i = 0; i < tags.length; i++) {
		tag = $('
');
		tag.html(tags[i].tagsug+":&nbsp&nbsp&nbsp&nbsp"+tags[i].tagInfo);
		this.tagsDiv.append(tag);
	}
	this.liDom.append(this.tagsDiv);
	if (!this.isSame) {
		this.flowerDiv = $('
');
		this.flower = $('');
		this.flower.addClass('send-flower');
		this.flower.attr('title','送花');
		this.flower.bind('click',function(){
			$.ajax({
				    type: "POST",
				    url: "../match.do?action=flower",
				    data: { target: self.userObj.id,},
				    success: function(data) {
				    	alert('花已经送出去了，祝你好运');
				    },
				    error: function (xhr, textStatus, errorThrown) {
				    	alert('出现错误' + textStatus);
				    }
				});
		})
		this.flowerDiv.append(this.flower);
		this.liDom.append(this.flowerDiv);
		this.mgr.opsiteUl.append(this.liDom);
		this.mgr.opsiteUsers[this.userObj.id] = this;
	} else {
		this.mgr.sameUl.append(this.liDom);
		this.mgr.sameUsers[this.userObj.id] = this;
	}
	this.mgr.users[this.userObj.id] = this;
};
/**
 *
 */
MatchUser.prototype.canMatch = function(id) {

};
/**
 * 获取用户展示的当前位置
 */
MatchUser.prototype.getPosition=function(){
	return this.liDom.offset();
};
<|endoftext|>


<commit_before>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;

    //probably extraneous
    Handlebars.registerHelper("formatTime", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10)
        return formatted.join(":");
    });

    //converts 24 hour time to 12 hour
    Handlebars.registerHelper("formatTimeAMPM", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10)
        if (formatted[0] < 12) {
            formatted[1] += "AM";
        }
        else {
            formatted[1] += "PM";
        }
        return formatted.join(":");
    });

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        if (state === null || state === "course_list") {
            // Figure out what to do from the url
            CourseList.show_list();
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.instructor);
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule();
        }
    });

    CourseList.show_list();

});
<commit_msg>Dispatch based on url when the page loads, or the user backs onto the initial state<commit_after>// mobile javascript
var data;

$(document).ready(function() {

    var course_data = null;
    var book_data = null;

    //probably extraneous
    Handlebars.registerHelper("formatTime", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10)
        return formatted.join(":");
    });

    //converts 24 hour time to 12 hour
    Handlebars.registerHelper("formatTimeAMPM", function(time) {
        formatted = time.toString().split(":");
        formatted[0] = parseInt(formatted[0], 10)
        if (formatted[0] < 12) {
            formatted[1] += "AM";
        }
        else {
            formatted[1] += "PM";
        }
        return formatted.join(":");
    });

    History.Adapter.bind(window,'statechange',function(){
        var history_state = History.getState();
        var data = history_state.data;
        var state = data.state;

        if (state === null || state === "course_list") {
            // Figure out what to do from the url
            show_page_from_url();
        }
        else if (state === "instructor") {
            Instructor.show_instructor(data.instructor);
        }
        else if (state === "visual") {
            VisualSchedule.show_visual_schedule();
        }
    });

    function show_page_from_url() {
        var path = window.location.pathname;

        if (path === "/my/") {
            CourseList.show_list();
        }
        else if (path === "/my/visual") {
            VisualSchedule.show_visual_schedule();
        }
        else if (path.match(/^\/my\/instructor\/[A-Z0-9]+/)) {
            var matches = path.match(/^\/my\/instructor\/([A-Z0-9]+)/);
            Instructor.show_instructor(matches[1]);
        }
        else {
            // Just fall back to the course list?
            CourseList.show_list();
        }
    }

    show_page_from_url();

});
<|endoftext|>


<commit_before>// @flow

import Animated, { Easing } from 'react-native-reanimated';
import { State as GestureState } from 'react-native-gesture-handler';
import { Platform } from 'react-native';

/* eslint-disable import/no-named-as-default-member */
const {
  Clock,
  Value,
  block,
  cond,
  not,
  and,
  greaterThan,
  lessThan,
  eq,
  sub,
  set,
  max,
  startClock,
  stopClock,
  clockRunning,
  timing,
} = Animated;
/* eslint-enable import/no-named-as-default-member */

function clamp(value: Value, minValue: Value, maxValue: Value): Value {
  return cond(
    greaterThan(value, maxValue),
    maxValue,
    cond(greaterThan(minValue, value), minValue, value),
  );
}

function delta(value: Value) {
  const prevValue = new Value(0);
  const deltaValue = new Value(0);
  return [
    set(deltaValue, cond(eq(prevValue, 0), 0, sub(value, prevValue))),
    set(prevValue, value),
    deltaValue,
  ];
}

function gestureJustStarted(state: Value) {
  const prevValue = new Value(-1);
  return cond(eq(prevValue, state), 0, [
    set(prevValue, state),
    eq(state, GestureState.ACTIVE),
  ]);
}

function gestureJustEnded(state: Value) {
  const prevValue = new Value(-1);
  return cond(eq(prevValue, state), 0, [
    set(prevValue, state),
    eq(state, GestureState.END),
  ]);
}

const defaultTimingConfig = {
  duration: 250,
  easing: Easing.out(Easing.ease),
};

type TimingConfig = $Shape<typeof defaultTimingConfig>;
function runTiming(
  clock: Clock,
  initialValue: Value | number,
  finalValue: Value | number,
  startStopClock: boolean = true,
  config: TimingConfig = defaultTimingConfig,
): Value {
  const state = {
    finished: new Value(0),
    position: new Value(0),
    frameTime: new Value(0),
    time: new Value(0),
  };
  const timingConfig = {
    ...defaultTimingConfig,
    ...config,
    toValue: new Value(0),
  };
  return [
    cond(not(clockRunning(clock)), [
      set(state.finished, 0),
      set(state.frameTime, 0),
      set(state.time, 0),
      set(state.position, initialValue),
      set(timingConfig.toValue, finalValue),
      startStopClock && startClock(clock),
    ]),
    timing(clock, state, timingConfig),
    cond(state.finished, startStopClock && stopClock(clock)),
    state.position,
  ];
}

// You provide a node that performs a "ratchet",
// and this function will call it as keyboard height increases
function ratchetAlongWithKeyboardHeight(
  keyboardHeight: Animated.Node,
  ratchetFunction: Animated.Node,
) {
  const prevKeyboardHeightValue = new Value(-1);
  const whenToUpdate = Platform.select({
    // In certain situations, iOS will send multiple keyboardShows in rapid
    // succession with increasing height values. Only the final value has any
    // semblance of reality. I've encountered this when using the native
    // password management integration
    ios: greaterThan(keyboardHeight, max(prevKeyboardHeightValue, 0)),
    // Android's keyboard can resize due to user interaction sometimes. In these
    // cases it can get quite big, in which case we don't want to update
    defaut: and(eq(prevKeyboardHeightValue, 0), greaterThan(keyboardHeight, 0)),
  });
  return block([
    cond(
      lessThan(prevKeyboardHeightValue, 0),
      set(prevKeyboardHeightValue, keyboardHeight),
    ),
    cond(whenToUpdate, ratchetFunction),
    set(prevKeyboardHeightValue, keyboardHeight),
  ]);
}

export {
  clamp,
  delta,
  gestureJustStarted,
  gestureJustEnded,
  runTiming,
  ratchetAlongWithKeyboardHeight,
};
<commit_msg>[native] Make sure ratchetAlongWithKeyboardHeight resets when keyboard hides<commit_after>// @flow

import Animated, { Easing } from 'react-native-reanimated';
import { State as GestureState } from 'react-native-gesture-handler';
import { Platform } from 'react-native';

/* eslint-disable import/no-named-as-default-member */
const {
  Clock,
  Value,
  block,
  cond,
  not,
  and,
  or,
  greaterThan,
  lessThan,
  eq,
  sub,
  set,
  max,
  startClock,
  stopClock,
  clockRunning,
  timing,
} = Animated;
/* eslint-enable import/no-named-as-default-member */

function clamp(value: Value, minValue: Value, maxValue: Value): Value {
  return cond(
    greaterThan(value, maxValue),
    maxValue,
    cond(greaterThan(minValue, value), minValue, value),
  );
}

function delta(value: Value) {
  const prevValue = new Value(0);
  const deltaValue = new Value(0);
  return [
    set(deltaValue, cond(eq(prevValue, 0), 0, sub(value, prevValue))),
    set(prevValue, value),
    deltaValue,
  ];
}

function gestureJustStarted(state: Value) {
  const prevValue = new Value(-1);
  return cond(eq(prevValue, state), 0, [
    set(prevValue, state),
    eq(state, GestureState.ACTIVE),
  ]);
}

function gestureJustEnded(state: Value) {
  const prevValue = new Value(-1);
  return cond(eq(prevValue, state), 0, [
    set(prevValue, state),
    eq(state, GestureState.END),
  ]);
}

const defaultTimingConfig = {
  duration: 250,
  easing: Easing.out(Easing.ease),
};

type TimingConfig = $Shape<typeof defaultTimingConfig>;
function runTiming(
  clock: Clock,
  initialValue: Value | number,
  finalValue: Value | number,
  startStopClock: boolean = true,
  config: TimingConfig = defaultTimingConfig,
): Value {
  const state = {
    finished: new Value(0),
    position: new Value(0),
    frameTime: new Value(0),
    time: new Value(0),
  };
  const timingConfig = {
    ...defaultTimingConfig,
    ...config,
    toValue: new Value(0),
  };
  return [
    cond(not(clockRunning(clock)), [
      set(state.finished, 0),
      set(state.frameTime, 0),
      set(state.time, 0),
      set(state.position, initialValue),
      set(timingConfig.toValue, finalValue),
      startStopClock && startClock(clock),
    ]),
    timing(clock, state, timingConfig),
    cond(state.finished, startStopClock && stopClock(clock)),
    state.position,
  ];
}

// You provide a node that performs a "ratchet",
// and this function will call it as keyboard height increases
function ratchetAlongWithKeyboardHeight(
  keyboardHeight: Animated.Node,
  ratchetFunction: Animated.Node,
) {
  const prevKeyboardHeightValue = new Value(-1);
  const whenToUpdate = Platform.select({
    // In certain situations, iOS will send multiple keyboardShows in rapid
    // succession with increasing height values. Only the final value has any
    // semblance of reality. I've encountered this when using the native
    // password management integration
    ios: greaterThan(keyboardHeight, max(prevKeyboardHeightValue, 0)),
    // Android's keyboard can resize due to user interaction sometimes. In these
    // cases it can get quite big, in which case we don't want to update
    defaut: and(eq(prevKeyboardHeightValue, 0), greaterThan(keyboardHeight, 0)),
  });
  const whenToReset = and(
    eq(keyboardHeight, 0),
    greaterThan(prevKeyboardHeightValue, 0),
  );
  return block([
    cond(
      lessThan(prevKeyboardHeightValue, 0),
      set(prevKeyboardHeightValue, keyboardHeight),
    ),
    cond(or(whenToUpdate, whenToReset), ratchetFunction),
    set(prevKeyboardHeightValue, keyboardHeight),
  ]);
}

export {
  clamp,
  delta,
  gestureJustStarted,
  gestureJustEnded,
  runTiming,
  ratchetAlongWithKeyboardHeight,
};
<|endoftext|>


<commit_before>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* globals mozL10n, RenderingStates, Promise, scrollIntoView,
           watchScroll, getVisibleElements */

'use strict';

var THUMBNAIL_SCROLL_MARGIN = -19;

/**
 * @constructor
 * @param container
 * @param id
 * @param defaultViewport
 * @param linkService
 * @param renderingQueue
 *
 * @implements {IRenderableView}
 */
var ThumbnailView = function thumbnailView(container, id, defaultViewport,
                                           linkService, renderingQueue) {
  var anchor = document.createElement('a');
  anchor.href = linkService.getAnchorUrl('#page=' + id);
  anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
  anchor.onclick = function stopNavigation() {
    linkService.page = id;
    return false;
  };

  this.pdfPage = undefined;
  this.viewport = defaultViewport;
  this.pdfPageRotate = defaultViewport.rotation;

  this.rotation = 0;
  this.pageWidth = this.viewport.width;
  this.pageHeight = this.viewport.height;
  this.pageRatio = this.pageWidth / this.pageHeight;
  this.id = id;
  this.renderingId = 'thumbnail' + id;

  this.canvasWidth = 98;
  this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
  this.scale = (this.canvasWidth / this.pageWidth);

  var div = this.el = document.createElement('div');
  div.id = 'thumbnailContainer' + id;
  div.className = 'thumbnail';

  if (id === 1) {
    // Highlight the thumbnail of the first page when no page number is
    // specified (or exists in cache) when the document is loaded.
    div.classList.add('selected');
  }

  var ring = document.createElement('div');
  ring.className = 'thumbnailSelectionRing';
  ring.style.width = this.canvasWidth + 'px';
  ring.style.height = this.canvasHeight + 'px';

  div.appendChild(ring);
  anchor.appendChild(div);
  container.appendChild(anchor);

  this.hasImage = false;
  this.renderingState = RenderingStates.INITIAL;
  this.renderingQueue = renderingQueue;

  this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) {
    this.pdfPage = pdfPage;
    this.pdfPageRotate = pdfPage.rotate;
    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
    this.viewport = pdfPage.getViewport(1, totalRotation);
    this.update();
  };

  this.update = function thumbnailViewUpdate(rotation) {
    if (rotation !== undefined) {
      this.rotation = rotation;
    }
    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
    this.viewport = this.viewport.clone({
      scale: 1,
      rotation: totalRotation
    });
    this.pageWidth = this.viewport.width;
    this.pageHeight = this.viewport.height;
    this.pageRatio = this.pageWidth / this.pageHeight;

    this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
    this.scale = (this.canvasWidth / this.pageWidth);

    div.removeAttribute('data-loaded');
    ring.textContent = '';
    ring.style.width = this.canvasWidth + 'px';
    ring.style.height = this.canvasHeight + 'px';

    this.hasImage = false;
    this.renderingState = RenderingStates.INITIAL;
    this.resume = null;
  };

  this.getPageDrawContext = function thumbnailViewGetPageDrawContext() {
    var canvas = document.createElement('canvas');
    canvas.id = 'thumbnail' + id;

    canvas.width = this.canvasWidth;
    canvas.height = this.canvasHeight;
    canvas.className = 'thumbnailImage';
    canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
      {page: id}, 'Thumbnail of Page {{page}}'));

    div.setAttribute('data-loaded', true);

    ring.appendChild(canvas);

    var ctx = canvas.getContext('2d');
    ctx.save();
    ctx.fillStyle = 'rgb(255, 255, 255)';
    ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
    ctx.restore();
    return ctx;
  };

  this.drawingRequired = function thumbnailViewDrawingRequired() {
    return !this.hasImage;
  };

  this.draw = function thumbnailViewDraw() {
    if (this.renderingState !== RenderingStates.INITIAL) {
      console.error('Must be in new state before drawing');
    }

    this.renderingState = RenderingStates.RUNNING;
    if (this.hasImage) {
      return Promise.resolve(undefined);
    }

    var resolveRenderPromise, rejectRenderPromise;
    var promise = new Promise(function (resolve, reject) {
      resolveRenderPromise = resolve;
      rejectRenderPromise = reject;
    });

    var self = this;
    var ctx = this.getPageDrawContext();
    var drawViewport = this.viewport.clone({ scale: this.scale });
    var renderContext = {
      canvasContext: ctx,
      viewport: drawViewport,
      continueCallback: function(cont) {
        if (!self.renderingQueue.isHighestPriority(self)) {
          self.renderingState = RenderingStates.PAUSED;
          self.resume = function() {
            self.renderingState = RenderingStates.RUNNING;
            cont();
          };
          return;
        }
        cont();
      }
    };
    this.pdfPage.render(renderContext).promise.then(
      function pdfPageRenderCallback() {
        self.renderingState = RenderingStates.FINISHED;
        resolveRenderPromise(undefined);
      },
      function pdfPageRenderError(error) {
        self.renderingState = RenderingStates.FINISHED;
        rejectRenderPromise(error);
      }
    );
    this.hasImage = true;
    return promise;
  };

  function getTempCanvas(width, height) {
    var tempCanvas = ThumbnailView.tempImageCache;
    if (!tempCanvas) {
      tempCanvas = document.createElement('canvas');
      ThumbnailView.tempImageCache = tempCanvas;
    }
    tempCanvas.width = width;
    tempCanvas.height = height;
    return tempCanvas;
  }

  this.setImage = function thumbnailViewSetImage(pageView) {
    var img = pageView.canvas;
    if (this.hasImage || !img) {
      return;
    }
    if (!this.pdfPage) {
      this.setPdfPage(pageView.pdfPage);
    }
    this.renderingState = RenderingStates.FINISHED;
    var ctx = this.getPageDrawContext();

    var reducedImage = img;
    var reducedWidth = img.width;
    var reducedHeight = img.height;

    // drawImage does an awful job of rescaling the image, doing it gradually
    var MAX_SCALE_FACTOR = 2.0;
    if (Math.max(img.width / ctx.canvas.width,
                 img.height / ctx.canvas.height) > MAX_SCALE_FACTOR) {
      reducedWidth >>= 1;
      reducedHeight >>= 1;
      reducedImage = getTempCanvas(reducedWidth, reducedHeight);
      var reducedImageCtx = reducedImage.getContext('2d');
      reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
                                0, 0, reducedWidth, reducedHeight);
      while (Math.max(reducedWidth / ctx.canvas.width,
                      reducedHeight / ctx.canvas.height) > MAX_SCALE_FACTOR) {
        reducedImageCtx.drawImage(reducedImage,
                                  0, 0, reducedWidth, reducedHeight,
                                  0, 0, reducedWidth >> 1, reducedHeight >> 1);
        reducedWidth >>= 1;
        reducedHeight >>= 1;
      }
    }

    ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
                  0, 0, ctx.canvas.width, ctx.canvas.height);

    this.hasImage = true;
  };
};

ThumbnailView.tempImageCache = null;

/**
 * @typedef {Object} PDFThumbnailViewerOptions
 * @property {HTMLDivElement} container - The container for the thumbs elements.
 * @property {IPDFLinkService} linkService - The navigation/linking service.
 * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
 */

/**
 * Simple viewer control to display thumbs for pages.
 * @class
 */
var PDFThumbnailViewer = (function pdfThumbnailViewer() {
  /**
   * @constructs
   * @param {PDFThumbnailViewerOptions} options
   */
  function PDFThumbnailViewer(options) {
    this.container = options.container;
    this.renderingQueue = options.renderingQueue;
    this.linkService = options.linkService;

    this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));
    this._resetView();
  }

  PDFThumbnailViewer.prototype = {
    _scrollUpdated: function PDFThumbnailViewer_scrollUpdated() {
      this.renderingQueue.renderHighestPriority();
    },

    getThumbnail: function PDFThumbnailViewer_getThumbnail(index) {
      return this.thumbnails[index];
    },

    _getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() {
      return getVisibleElements(this.container, this.thumbnails);
    },

    scrollThumbnailIntoView: function (page) {
      var selected = document.querySelector('.thumbnail.selected');
      if (selected) {
        selected.classList.remove('selected');
      }
      var thumbnail = document.getElementById('thumbnailContainer' + page);
      thumbnail.classList.add('selected');
      var visibleThumbs = this._getVisibleThumbs();
      var numVisibleThumbs = visibleThumbs.views.length;

      // If the thumbnail isn't currently visible, scroll it into view.
      if (numVisibleThumbs > 0) {
        var first = visibleThumbs.first.id;
        // Account for only one thumbnail being visible.
        var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);
        if (page <= first || page >= last) {
          scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
        }
      }
    },

    get pagesRotation() {
      return this._pagesRotation;
    },

    set pagesRotation(rotation) {
      this._pagesRotation = rotation;
      for (var i = 0, l = this.thumbnails.length; i < l; i++) {
        var thumb = this.thumbnails[i];
        thumb.update(rotation);
      }
    },

    cleanup: function PDFThumbnailViewer_cleanup() {
      ThumbnailView.tempImageCache = null;
    },

    _resetView: function () {
      this.thumbnails = [];
      this._pagesRotation = 0;
      this._pagesRequests = [];
    },

    setDocument: function (pdfDocument) {
      if (this.pdfDocument) {
        // cleanup of the elements and views
        var thumbsView = this.container;
        while (thumbsView.hasChildNodes()) {
          thumbsView.removeChild(thumbsView.lastChild);
        }
        this._resetView();
      }

      this.pdfDocument = pdfDocument;
      if (!pdfDocument) {
        return Promise.resolve();
      }

      return pdfDocument.getPage(1).then(function (firstPage) {
        var pagesCount = pdfDocument.numPages;
        var viewport = firstPage.getViewport(1.0);
        for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
          var thumbnail = new ThumbnailView(this.container, pageNum,
                                            viewport.clone(), this.linkService,
                                            this.renderingQueue);
          this.thumbnails.push(thumbnail);
        }
      }.bind(this));
    },

    /**
     * @param {PDFPageView} pageView
     * @returns {PDFPage}
     * @private
     */
    _ensurePdfPageLoaded: function (thumbView) {
      if (thumbView.pdfPage) {
        return Promise.resolve(thumbView.pdfPage);
      }
      var pageNumber = thumbView.id;
      if (this._pagesRequests[pageNumber]) {
        return this._pagesRequests[pageNumber];
      }
      var promise = this.pdfDocument.getPage(pageNumber).then(
        function (pdfPage) {
          thumbView.setPdfPage(pdfPage);
          this._pagesRequests[pageNumber] = null;
          return pdfPage;
        }.bind(this));
      this._pagesRequests[pageNumber] = promise;
      return promise;
    },

    ensureThumbnailVisible:
        function PDFThumbnailViewer_ensureThumbnailVisible(page) {
      // Ensure that the thumbnail of the current page is visible
      // when switching from another view.
      scrollIntoView(document.getElementById('thumbnailContainer' + page));
    },

    forceRendering: function () {
      var visibleThumbs = this._getVisibleThumbs();
      var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,
                                                             this.thumbnails,
                                                             this.scroll.down);
      if (thumbView) {
        this._ensurePdfPageLoaded(thumbView).then(function () {
          this.renderingQueue.renderView(thumbView);
        }.bind(this));
        return true;
      }
      return false;
    }
  };

  return PDFThumbnailViewer;
})();
<commit_msg>Fill temporary canvases with a white background too<commit_after>/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* globals mozL10n, RenderingStates, Promise, scrollIntoView,
           watchScroll, getVisibleElements */

'use strict';

var THUMBNAIL_SCROLL_MARGIN = -19;

/**
 * @constructor
 * @param container
 * @param id
 * @param defaultViewport
 * @param linkService
 * @param renderingQueue
 *
 * @implements {IRenderableView}
 */
var ThumbnailView = function thumbnailView(container, id, defaultViewport,
                                           linkService, renderingQueue) {
  var anchor = document.createElement('a');
  anchor.href = linkService.getAnchorUrl('#page=' + id);
  anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}');
  anchor.onclick = function stopNavigation() {
    linkService.page = id;
    return false;
  };

  this.pdfPage = undefined;
  this.viewport = defaultViewport;
  this.pdfPageRotate = defaultViewport.rotation;

  this.rotation = 0;
  this.pageWidth = this.viewport.width;
  this.pageHeight = this.viewport.height;
  this.pageRatio = this.pageWidth / this.pageHeight;
  this.id = id;
  this.renderingId = 'thumbnail' + id;

  this.canvasWidth = 98;
  this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
  this.scale = (this.canvasWidth / this.pageWidth);

  var div = this.el = document.createElement('div');
  div.id = 'thumbnailContainer' + id;
  div.className = 'thumbnail';

  if (id === 1) {
    // Highlight the thumbnail of the first page when no page number is
    // specified (or exists in cache) when the document is loaded.
    div.classList.add('selected');
  }

  var ring = document.createElement('div');
  ring.className = 'thumbnailSelectionRing';
  ring.style.width = this.canvasWidth + 'px';
  ring.style.height = this.canvasHeight + 'px';

  div.appendChild(ring);
  anchor.appendChild(div);
  container.appendChild(anchor);

  this.hasImage = false;
  this.renderingState = RenderingStates.INITIAL;
  this.renderingQueue = renderingQueue;

  this.setPdfPage = function thumbnailViewSetPdfPage(pdfPage) {
    this.pdfPage = pdfPage;
    this.pdfPageRotate = pdfPage.rotate;
    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
    this.viewport = pdfPage.getViewport(1, totalRotation);
    this.update();
  };

  this.update = function thumbnailViewUpdate(rotation) {
    if (rotation !== undefined) {
      this.rotation = rotation;
    }
    var totalRotation = (this.rotation + this.pdfPageRotate) % 360;
    this.viewport = this.viewport.clone({
      scale: 1,
      rotation: totalRotation
    });
    this.pageWidth = this.viewport.width;
    this.pageHeight = this.viewport.height;
    this.pageRatio = this.pageWidth / this.pageHeight;

    this.canvasHeight = this.canvasWidth / this.pageWidth * this.pageHeight;
    this.scale = (this.canvasWidth / this.pageWidth);

    div.removeAttribute('data-loaded');
    ring.textContent = '';
    ring.style.width = this.canvasWidth + 'px';
    ring.style.height = this.canvasHeight + 'px';

    this.hasImage = false;
    this.renderingState = RenderingStates.INITIAL;
    this.resume = null;
  };

  this.getPageDrawContext = function thumbnailViewGetPageDrawContext() {
    var canvas = document.createElement('canvas');
    canvas.id = 'thumbnail' + id;

    canvas.width = this.canvasWidth;
    canvas.height = this.canvasHeight;
    canvas.className = 'thumbnailImage';
    canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas',
      {page: id}, 'Thumbnail of Page {{page}}'));

    div.setAttribute('data-loaded', true);

    ring.appendChild(canvas);

    var ctx = canvas.getContext('2d');
    ctx.save();
    ctx.fillStyle = 'rgb(255, 255, 255)';
    ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
    ctx.restore();
    return ctx;
  };

  this.drawingRequired = function thumbnailViewDrawingRequired() {
    return !this.hasImage;
  };

  this.draw = function thumbnailViewDraw() {
    if (this.renderingState !== RenderingStates.INITIAL) {
      console.error('Must be in new state before drawing');
    }

    this.renderingState = RenderingStates.RUNNING;
    if (this.hasImage) {
      return Promise.resolve(undefined);
    }

    var resolveRenderPromise, rejectRenderPromise;
    var promise = new Promise(function (resolve, reject) {
      resolveRenderPromise = resolve;
      rejectRenderPromise = reject;
    });

    var self = this;
    var ctx = this.getPageDrawContext();
    var drawViewport = this.viewport.clone({ scale: this.scale });
    var renderContext = {
      canvasContext: ctx,
      viewport: drawViewport,
      continueCallback: function(cont) {
        if (!self.renderingQueue.isHighestPriority(self)) {
          self.renderingState = RenderingStates.PAUSED;
          self.resume = function() {
            self.renderingState = RenderingStates.RUNNING;
            cont();
          };
          return;
        }
        cont();
      }
    };
    this.pdfPage.render(renderContext).promise.then(
      function pdfPageRenderCallback() {
        self.renderingState = RenderingStates.FINISHED;
        resolveRenderPromise(undefined);
      },
      function pdfPageRenderError(error) {
        self.renderingState = RenderingStates.FINISHED;
        rejectRenderPromise(error);
      }
    );
    this.hasImage = true;
    return promise;
  };

  function getTempCanvas(width, height) {
    var tempCanvas = ThumbnailView.tempImageCache;
    if (!tempCanvas) {
      tempCanvas = document.createElement('canvas');
      ThumbnailView.tempImageCache = tempCanvas;
    }
    tempCanvas.width = width;
    tempCanvas.height = height;

    // Since this is a temporary canvas, we need to fill
    // the canvas with a white background ourselves.
    // |getPageDrawContext| uses CSS rules for this.
    var ctx = tempCanvas.getContext('2d');
    ctx.save();
    ctx.fillStyle = 'rgb(255, 255, 255)';
    ctx.fillRect(0, 0, width, height);
    ctx.restore();
    return tempCanvas;
  }

  this.setImage = function thumbnailViewSetImage(pageView) {
    var img = pageView.canvas;
    if (this.hasImage || !img) {
      return;
    }
    if (!this.pdfPage) {
      this.setPdfPage(pageView.pdfPage);
    }
    this.renderingState = RenderingStates.FINISHED;
    var ctx = this.getPageDrawContext();

    var reducedImage = img;
    var reducedWidth = img.width;
    var reducedHeight = img.height;

    // drawImage does an awful job of rescaling the image, doing it gradually
    var MAX_SCALE_FACTOR = 2.0;
    if (Math.max(img.width / ctx.canvas.width,
                 img.height / ctx.canvas.height) > MAX_SCALE_FACTOR) {
      reducedWidth >>= 1;
      reducedHeight >>= 1;
      reducedImage = getTempCanvas(reducedWidth, reducedHeight);
      var reducedImageCtx = reducedImage.getContext('2d');
      reducedImageCtx.drawImage(img, 0, 0, img.width, img.height,
                                0, 0, reducedWidth, reducedHeight);
      while (Math.max(reducedWidth / ctx.canvas.width,
                      reducedHeight / ctx.canvas.height) > MAX_SCALE_FACTOR) {
        reducedImageCtx.drawImage(reducedImage,
                                  0, 0, reducedWidth, reducedHeight,
                                  0, 0, reducedWidth >> 1, reducedHeight >> 1);
        reducedWidth >>= 1;
        reducedHeight >>= 1;
      }
    }

    ctx.drawImage(reducedImage, 0, 0, reducedWidth, reducedHeight,
                  0, 0, ctx.canvas.width, ctx.canvas.height);

    this.hasImage = true;
  };
};

ThumbnailView.tempImageCache = null;

/**
 * @typedef {Object} PDFThumbnailViewerOptions
 * @property {HTMLDivElement} container - The container for the thumbs elements.
 * @property {IPDFLinkService} linkService - The navigation/linking service.
 * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
 */

/**
 * Simple viewer control to display thumbs for pages.
 * @class
 */
var PDFThumbnailViewer = (function pdfThumbnailViewer() {
  /**
   * @constructs
   * @param {PDFThumbnailViewerOptions} options
   */
  function PDFThumbnailViewer(options) {
    this.container = options.container;
    this.renderingQueue = options.renderingQueue;
    this.linkService = options.linkService;

    this.scroll = watchScroll(this.container, this._scrollUpdated.bind(this));
    this._resetView();
  }

  PDFThumbnailViewer.prototype = {
    _scrollUpdated: function PDFThumbnailViewer_scrollUpdated() {
      this.renderingQueue.renderHighestPriority();
    },

    getThumbnail: function PDFThumbnailViewer_getThumbnail(index) {
      return this.thumbnails[index];
    },

    _getVisibleThumbs: function PDFThumbnailViewer_getVisibleThumbs() {
      return getVisibleElements(this.container, this.thumbnails);
    },

    scrollThumbnailIntoView: function (page) {
      var selected = document.querySelector('.thumbnail.selected');
      if (selected) {
        selected.classList.remove('selected');
      }
      var thumbnail = document.getElementById('thumbnailContainer' + page);
      thumbnail.classList.add('selected');
      var visibleThumbs = this._getVisibleThumbs();
      var numVisibleThumbs = visibleThumbs.views.length;

      // If the thumbnail isn't currently visible, scroll it into view.
      if (numVisibleThumbs > 0) {
        var first = visibleThumbs.first.id;
        // Account for only one thumbnail being visible.
        var last = (numVisibleThumbs > 1 ? visibleThumbs.last.id : first);
        if (page <= first || page >= last) {
          scrollIntoView(thumbnail, { top: THUMBNAIL_SCROLL_MARGIN });
        }
      }
    },

    get pagesRotation() {
      return this._pagesRotation;
    },

    set pagesRotation(rotation) {
      this._pagesRotation = rotation;
      for (var i = 0, l = this.thumbnails.length; i < l; i++) {
        var thumb = this.thumbnails[i];
        thumb.update(rotation);
      }
    },

    cleanup: function PDFThumbnailViewer_cleanup() {
      ThumbnailView.tempImageCache = null;
    },

    _resetView: function () {
      this.thumbnails = [];
      this._pagesRotation = 0;
      this._pagesRequests = [];
    },

    setDocument: function (pdfDocument) {
      if (this.pdfDocument) {
        // cleanup of the elements and views
        var thumbsView = this.container;
        while (thumbsView.hasChildNodes()) {
          thumbsView.removeChild(thumbsView.lastChild);
        }
        this._resetView();
      }

      this.pdfDocument = pdfDocument;
      if (!pdfDocument) {
        return Promise.resolve();
      }

      return pdfDocument.getPage(1).then(function (firstPage) {
        var pagesCount = pdfDocument.numPages;
        var viewport = firstPage.getViewport(1.0);
        for (var pageNum = 1; pageNum <= pagesCount; ++pageNum) {
          var thumbnail = new ThumbnailView(this.container, pageNum,
                                            viewport.clone(), this.linkService,
                                            this.renderingQueue);
          this.thumbnails.push(thumbnail);
        }
      }.bind(this));
    },

    /**
     * @param {PDFPageView} pageView
     * @returns {PDFPage}
     * @private
     */
    _ensurePdfPageLoaded: function (thumbView) {
      if (thumbView.pdfPage) {
        return Promise.resolve(thumbView.pdfPage);
      }
      var pageNumber = thumbView.id;
      if (this._pagesRequests[pageNumber]) {
        return this._pagesRequests[pageNumber];
      }
      var promise = this.pdfDocument.getPage(pageNumber).then(
        function (pdfPage) {
          thumbView.setPdfPage(pdfPage);
          this._pagesRequests[pageNumber] = null;
          return pdfPage;
        }.bind(this));
      this._pagesRequests[pageNumber] = promise;
      return promise;
    },

    ensureThumbnailVisible:
        function PDFThumbnailViewer_ensureThumbnailVisible(page) {
      // Ensure that the thumbnail of the current page is visible
      // when switching from another view.
      scrollIntoView(document.getElementById('thumbnailContainer' + page));
    },

    forceRendering: function () {
      var visibleThumbs = this._getVisibleThumbs();
      var thumbView = this.renderingQueue.getHighestPriority(visibleThumbs,
                                                             this.thumbnails,
                                                             this.scroll.down);
      if (thumbView) {
        this._ensurePdfPageLoaded(thumbView).then(function () {
          this.renderingQueue.renderView(thumbView);
        }.bind(this));
        return true;
      }
      return false;
    }
  };

  return PDFThumbnailViewer;
})();
<|endoftext|>


<commit_before>module("Geometry", {
    setup : function() {
        stop();
        var that = this;
        this.cb = function(e) {
            ok(true, "Scene loaded");
            that.doc = document.getElementById("xml3dframe").contentDocument;
            start();
        };
        loadDocument("scenes/points.xhtml"+window.location.search, this.cb);
    },
    teardown : function() {
        var v = document.getElementById("xml3dframe");
        v.removeEventListener("load", this.cb, true);
    }
});

test("Color Points", 14, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 300, 170)[0] == 0)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 170), [255,255,255,255], EPSILON,
            "Lower Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 233), [102,102,102,255], EPSILON,
            "Upper Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 267, 202), [153,153,153,255], EPSILON,
            "Left Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 331, 202), [204,204,204,255], EPSILON,
            "Right Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 200), [0,0,0,0], EPSILON,
            "Center points is transparent" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 283, 166), [0,0,0,0], EPSILON,
            "Dimensions of medium distance points are small enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 284, 166), [255,255,255,255], EPSILON,
            "Dimensions of medium distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 283, 166), [0,0,0,0], EPSILON,
            "Dimensions of medium distance points are small enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 280, 37), [255,255,255,255], EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 279, 37), [0,0,0,0], EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 288, 273), [255,255,255,255], EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 287, 273), [0,0,0,0], EPSILON,
            "Dimensions of near distance points are big enough" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});

test("Texture Points", 7, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 172, 168)[0] != 255)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 172, 168), [255,0,0,255], EPSILON,
            "Lower Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 172, 232), [0,255,255,255], EPSILON,
            "Upper Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 138, 200), [0,255,0,255], EPSILON,
            "Left Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 198, 200), [0,0,255,255], EPSILON,
            "Right Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 158, 155), [0,0,0,0], EPSILON,
            "Corner Point is transparent due to round texture image" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});
test("Texture Color Points", 6, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 428, 167)[0] != 255)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 428, 167), [255,0,0,255], EPSILON,
            "Lower Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 428, 231), [0,102,102,255], EPSILON,
            "Upper Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 396, 200), [0,153,0,255], EPSILON,
            "Left Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 460, 200), [0,0,204,255], EPSILON,
            "Right Point has correct texture and color" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();
});

module("Geometry", {
    setup : function() {
        stop();
        var that = this;
        this.cb = function(e) {
            ok(true, "Scene loaded");
            that.doc = document.getElementById("xml3dframe").contentDocument;
            start();
        };
        loadDocument("scenes/lines.xhtml"+window.location.search, this.cb);
    },
    teardown : function() {
        var v = document.getElementById("xml3dframe");
        v.removeEventListener("load", this.cb, true);
    }
});

test("Color Lines", 8, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 300, 211)[0] == 0)
            return;

        ok( XML3DUnit.getPixelValue(glTest, 300, 211)[0] > 0 , EPSILON,
            "Center Vertical Line exists");
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 233), [0,0,0,0], EPSILON,
            "Center Vertical Line has right length" );
        ok( XML3DUnit.getPixelValue(glTest, 316, 200)[0] > 0 , EPSILON,
            "Center Horizontal Line exists");
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 333, 200), [0,0,0,0], EPSILON,
            "Center Horizontal Line has right length" );

        ok(XML3DUnit.getPixelValue(glTest, 217, 200)[3] != 0 &&
           XML3DUnit.getPixelValue(glTest, 203, 215)[3] != 0 &&
           XML3DUnit.getPixelValue(glTest, 186, 200)[3] != 0,
            "Indexed Line correct");

        ok(XML3DUnit.getPixelValue(glTest, 410, 199)[3] != 0 &&
            XML3DUnit.getPixelValue(glTest, 412, 216)[3] != 0 &&
            XML3DUnit.getPixelValue(glTest, 379, 215)[3] != 0,
            "Linestrips correct");
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});<commit_msg>Use pixel epsilon in geometry tests and fix Lines test to also check neighboring pixels<commit_after>module("Geometry", {
    setup : function() {
        stop();
        var that = this;
        this.cb = function(e) {
            ok(true, "Scene loaded");
            that.doc = document.getElementById("xml3dframe").contentDocument;
            start();
        };
        loadDocument("scenes/points.xhtml"+window.location.search, this.cb);
    },
    teardown : function() {
        var v = document.getElementById("xml3dframe");
        v.removeEventListener("load", this.cb, true);
    }
});

test("Color Points", 14, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 300, 170)[0] == 0)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 170), [255,255,255,255], PIXEL_EPSILON,
            "Lower Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 233), [102,102,102,255], PIXEL_EPSILON,
            "Upper Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 267, 202), [153,153,153,255], PIXEL_EPSILON,
            "Left Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 331, 202), [204,204,204,255], PIXEL_EPSILON,
            "Right Point has correct color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 200), [0,0,0,0], PIXEL_EPSILON,
            "Center points is transparent" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 283, 166), [0,0,0,0], PIXEL_EPSILON,
            "Dimensions of medium distance points are small enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 284, 166), [255,255,255,255], PIXEL_EPSILON,
            "Dimensions of medium distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 283, 166), [0,0,0,0], PIXEL_EPSILON,
            "Dimensions of medium distance points are small enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 280, 37), [255,255,255,255], PIXEL_EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 279, 37), [0,0,0,0], PIXEL_EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 288, 273), [255,255,255,255], PIXEL_EPSILON,
            "Dimensions of near distance points are big enough" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 287, 273), [0,0,0,0], PIXEL_EPSILON,
            "Dimensions of near distance points are big enough" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});

test("Texture Points", 7, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 172, 168)[0] != 255)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 172, 168), [255,0,0,255], PIXEL_EPSILON,
            "Lower Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 172, 232), [0,255,255,255], PIXEL_EPSILON,
            "Upper Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 138, 200), [0,255,0,255], PIXEL_EPSILON,
            "Left Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 198, 200), [0,0,255,255], PIXEL_EPSILON,
            "Right Point has correct texture" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 158, 155), [0,0,0,0], PIXEL_EPSILON,
            "Corner Point is transparent due to round texture image" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});
test("Texture Color Points", 6, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var testStep = 0;
    function onFrameDrawn(){
        if( XML3DUnit.getPixelValue(glTest, 428, 167)[0] != 255)
            return;

        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 428, 167), [255,0,0,255], PIXEL_EPSILON,
            "Lower Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 428, 231), [0,102,102,255], PIXEL_EPSILON,
            "Upper Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 396, 200), [0,153,0,255], PIXEL_EPSILON,
            "Left Point has correct texture and color" );
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 460, 200), [0,0,204,255], PIXEL_EPSILON,
            "Right Point has correct texture and color" );
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();
});

module("Geometry", {
    setup : function() {
        stop();
        var that = this;
        this.cb = function(e) {
            ok(true, "Scene loaded");
            that.doc = document.getElementById("xml3dframe").contentDocument;
            start();
        };
        loadDocument("scenes/lines.xhtml"+window.location.search, this.cb);
    },
    teardown : function() {
        var v = document.getElementById("xml3dframe");
        v.removeEventListener("load", this.cb, true);
    }
});

test("Color Lines", 8, function() {
    var xTest = this.doc.getElementById("myXml3d"),
        glTest = getContextForXml3DElement(xTest), hTest = getHandler(xTest);
    var self = this;

    var rangedTest = function(x, y) {
        var sum = [0,0,0,0];
        var samp = XML3DUnit.getPixelValue(glTest, x, y);
        sum[0] += samp[0]; sum[1] += samp[1]; sum[2] += samp[2]; sum[3] += samp[3];
        var samp = XML3DUnit.getPixelValue(glTest, x+1, y);
        sum[0] += samp[0]; sum[1] += samp[1]; sum[2] += samp[2]; sum[3] += samp[3];
        var samp = XML3DUnit.getPixelValue(glTest, x-1, y);
        sum[0] += samp[0]; sum[1] += samp[1]; sum[2] += samp[2]; sum[3] += samp[3];
        var samp = XML3DUnit.getPixelValue(glTest, x, y+1);
        sum[0] += samp[0]; sum[1] += samp[1]; sum[2] += samp[2]; sum[3] += samp[3];
        var samp = XML3DUnit.getPixelValue(glTest, x, y-1);
        sum[0] += samp[0]; sum[1] += samp[1]; sum[2] += samp[2]; sum[3] += samp[3];
       return sum;
    }

    var testStep = 0;
    function onFrameDrawn(){
        if( rangedTest(300, 211)[0] == 0)
            return;

        ok( rangedTest(300, 211)[0] > 0 , PIXEL_EPSILON, "Center Vertical Line exists");
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 300, 233), [0,0,0,0], PIXEL_EPSILON,
            "Center Vertical Line has right length" );
        ok( rangedTest(316, 200)[0] > 0 , PIXEL_EPSILON, "Center Horizontal Line exists");
        QUnit.closeArray(XML3DUnit.getPixelValue(glTest, 333, 200), [0,0,0,0], PIXEL_EPSILON,
            "Center Horizontal Line has right length" );

        ok(rangedTest(217, 200)[3] != 0 &&
           rangedTest(203, 215)[3] != 0 &&
           rangedTest(186, 200)[3] != 0,
            "Indexed Line correct");

        ok(rangedTest(410, 199)[3] != 0 &&
            rangedTest(412, 216)[3] != 0 &&
            rangedTest(379, 215)[3] != 0,
            "Linestrips correct");
        start();
    }

    stop();
    xTest.addEventListener("framedrawn", onFrameDrawn);
    hTest.draw();

});<|endoftext|>