<commit_before>import $ from 'jquery';
import { VIEWS } from './constants';
import { getMinDay } from './utilities';

export default {
  click(e) {
    const $target = $(e.target);
    const { options, viewDate, format } = this;

    e.stopPropagation();
    e.preventDefault();

    if ($target.hasClass('disabled')) {
      return;
    }

    const view = $target.data('view');
    let viewYear = viewDate.getFullYear();
    let viewMonth = viewDate.getMonth();
    let viewDay = viewDate.getDate();

    switch (view) {
      case 'years prev':
      case 'years next': {
        viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10;
        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderYears();
        break;
      }

      case 'year prev':
      case 'year next':
        viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1;
        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderMonths();
        break;

      case 'year current':
        if (format.hasYear) {
          this.showView(VIEWS.YEARS);
        }

        break;

      case 'year picked':
        if (format.hasMonth) {
          this.showView(VIEWS.MONTHS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('year');
        break;

      case 'year':
        viewYear = parseInt($target.text(), 10);
        this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));

        if (format.hasMonth) {
          this.viewDate = new Date(this.date);
          this.showView(VIEWS.MONTHS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('year');
        break;

      case 'month prev':
      case 'month next':
        viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1;

        if (viewMonth < 0) {
          viewYear -= 1;
          viewMonth += 12;
        } else if (viewMonth > 11) {
          viewYear += 1;
          viewMonth -= 12;
        }

        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderDays();
        break;

      case 'month current':
        if (format.hasMonth) {
          this.showView(VIEWS.MONTHS);
        }

        break;

      case 'month picked':
        if (format.hasDay) {
          this.showView(VIEWS.DAYS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('month');
        break;

      case 'month':
        viewMonth = $.inArray($target.text(), options.monthsShort);
        this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));

        if (format.hasDay) {
          this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
          this.showView(VIEWS.DAYS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('month');
        break;

      case 'day prev':
      case 'day next':
      case 'day':
        if (view === 'day prev') {
          viewMonth -= 1;
        } else if (view === 'day next') {
          viewMonth += 1;
        }

        viewDay = parseInt($target.text(), 10);
        this.date = new Date(viewYear, viewMonth, viewDay);
        this.viewDate = new Date(viewYear, viewMonth, viewDay);
        this.renderDays();

        if (view === 'day') {
          this.hideView();
        }

        this.pick('day');
        break;

      case 'day picked':
        this.hideView();
        this.pick('day');
        break;

      default:
    }
  },

  globalClick({ target }) {
    const { element, $trigger } = this;
    const trigger = $trigger[0];
    let hidden = true;

    while (target !== document) {
      if (target === trigger || target === element) {
        hidden = false;
        break;
      }

      target = target.parentNode;
    }

    if (hidden) {
      this.hide();
    }
  },

  keyup() {
    this.update();
  },

  globalKeyup({ target, key, keyCode }) {
    if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) {
      this.hide();
    }
  },
};
<commit_msg>fix: render years and months<commit_after>import $ from 'jquery';
import { VIEWS } from './constants';
import { getMinDay } from './utilities';

export default {
  click(e) {
    const $target = $(e.target);
    const { options, viewDate, format } = this;

    e.stopPropagation();
    e.preventDefault();

    if ($target.hasClass('disabled')) {
      return;
    }

    const view = $target.data('view');
    let viewYear = viewDate.getFullYear();
    let viewMonth = viewDate.getMonth();
    let viewDay = viewDate.getDate();

    switch (view) {
      case 'years prev':
      case 'years next': {
        viewYear = view === 'years prev' ? viewYear - 10 : viewYear + 10;
        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderYears();
        break;
      }

      case 'year prev':
      case 'year next':
        viewYear = view === 'year prev' ? viewYear - 1 : viewYear + 1;
        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderMonths();
        break;

      case 'year current':
        if (format.hasYear) {
          this.showView(VIEWS.YEARS);
        }

        break;

      case 'year picked':
        if (format.hasMonth) {
          this.showView(VIEWS.MONTHS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('year');
        break;

      case 'year':
        viewYear = parseInt($target.text(), 10);
        this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));

        if (format.hasMonth) {
          this.viewDate = new Date(this.date);
          this.showView(VIEWS.MONTHS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.renderYears();
          this.hideView();
        }

        this.pick('year');
        break;

      case 'month prev':
      case 'month next':
        viewMonth = view === 'month prev' ? viewMonth - 1 : viewMonth + 1;

        if (viewMonth < 0) {
          viewYear -= 1;
          viewMonth += 12;
        } else if (viewMonth > 11) {
          viewYear += 1;
          viewMonth -= 12;
        }

        this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
        this.renderDays();
        break;

      case 'month current':
        if (format.hasMonth) {
          this.showView(VIEWS.MONTHS);
        }

        break;

      case 'month picked':
        if (format.hasDay) {
          this.showView(VIEWS.DAYS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.hideView();
        }

        this.pick('month');
        break;

      case 'month':
        viewMonth = $.inArray($target.text(), options.monthsShort);
        this.date = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));

        if (format.hasDay) {
          this.viewDate = new Date(viewYear, viewMonth, getMinDay(viewYear, viewMonth, viewDay));
          this.showView(VIEWS.DAYS);
        } else {
          $target.addClass(options.pickedClass)
            .siblings()
            .removeClass(options.pickedClass);
          this.renderMonths();
          this.hideView();
        }

        this.pick('month');
        break;

      case 'day prev':
      case 'day next':
      case 'day':
        if (view === 'day prev') {
          viewMonth -= 1;
        } else if (view === 'day next') {
          viewMonth += 1;
        }

        viewDay = parseInt($target.text(), 10);
        this.date = new Date(viewYear, viewMonth, viewDay);
        this.viewDate = new Date(viewYear, viewMonth, viewDay);
        this.renderDays();

        if (view === 'day') {
          this.hideView();
        }

        this.pick('day');
        break;

      case 'day picked':
        this.hideView();
        this.pick('day');
        break;

      default:
    }
  },

  globalClick({ target }) {
    const { element, $trigger } = this;
    const trigger = $trigger[0];
    let hidden = true;

    while (target !== document) {
      if (target === trigger || target === element) {
        hidden = false;
        break;
      }

      target = target.parentNode;
    }

    if (hidden) {
      this.hide();
    }
  },

  keyup() {
    this.update();
  },

  globalKeyup({ target, key, keyCode }) {
    if (this.isInput && target !== this.element && this.shown && (key === 'Tab' || keyCode === 9)) {
      this.hide();
    }
  },
};
<|endoftext|>


<commit_before>/**
 * @file SQ.LazyLoad 延迟加载插件
 * @version 1.0.0
 */

/**
 * @changelog
 * 1.0.0  * 重写插件，调用方式改为 $. 链式调用。
 * 0.8.1  * 新增 ANIMATE 设置。
 * 0.8.0  * 重写 lazylaod 插件，提高整体性能。
 * 0.7.0  * 调整滑动阀值 scrollDelay，由 200 调整至 150；
 *        * 调整可视区的计算方式，由 offset 改为 getBoundingClientRect；
 *        * 针对 UC 浏览器极速版进行优化，可以在滑动过程中进行加载。
 * 0.6.5  * 修复 jshint 问题。
 * 0.6.4  * 修复图片加载失败时会导致 error 时间一直被触发的 bug；
 *          修复与 loadmore 插件配合使用时，无法替换加载错误的图片。
 * 0.6.3  + 新增首屏图片自动加载功能；
 *        + 新增占位图、占位背景设置。
 * 0.6.0  + 首屏图片自动加载。
 * 0.5.1  * 完成图片模式的延迟加载功能。
 * 0.0.1  + 新建。
 */
/*global
 $: false,
 SQ: false,
 console: false,
 jQuery: false
 */
;(function ($) {
    "use strict";
    /**
     * @name LazyLoad
     * @classdesc 内容延迟加载
     * @constructor
     * @param {object} config 插件配置（下面的参数为配置项，配置会写入属性）
     * @param {string} config.MODE                  延迟加载模式，默认为：image（图片模式）
     * @param {string} config.IMG_PLACEHOLDER       占位图片
     * @param {number} config.NUM_THRESHOLD         灵敏度，数值越大越灵敏，延迟性越小，默认为 200
     * @param {string} config.ANIMATE               动画类，例如 .fadeIn
     * @example $(".J_lazyload").lazyload({
    ANIMATE: ".fadeIn"
});
     */

    var scope = "sq-lazyload";      // data-* 后缀
    var defaults = {
        "MODE": "image",
        "NUM_THRESHOLD": 350
    };

    function Lazyload ( element, options ) {
        this.element = element;
        this.settings = $.extend( {}, defaults, options );
        this._defaults = defaults;
        this.init();
    }

    Lazyload.prototype = {
        construtor: "Lazyload",
        scrollTimer: 0,     // 滑动计时器
        scrollDelay: 150,   // 滑动阀值
        init: function () {
            var me = this;
            me.$element = $(me.element);
            me.elementClassName = me.settings.selector.slice(1);   // ".style-name" => "style-name"

            me._bindLazyEvent();
            me._trigger();
            me._loadImg();
        },
        /**
         * 刷新延迟加载元素，可以在外部调用。
         */
        /*refresh: function () {
            var me = this;
            me.$element = $(me.element);
            me._bindLazyEvent();
            me._loadImg();
        },*/
        /**
         * 验证参数是否合法
         * @returns {boolean}
         * @private
         */
        /*_verify: function () {
            return true;
        },
        _init: function () {
            var me = this;
            me._bindLazyEvent();
            me._trigger();
            me._loadImg();
        },*/
        _bindLazyEvent: function () {
            var me = this;
            // 为延迟加载元素绑定一次性执行事件
            me.$element.one("appear", function () {
                var img = this;
                var $img = $(img);
                var src = $img.attr("data-img");
                // 添加动画
                if (me.settings.ANIMATE) {
                    var animateClassName = me.settings.ANIMATE.indexOf(".") === 0 ? me.settings.ANIMATE.slice(1) : me.settings.ANIMATE;
                    $img.addClass("animated " + animateClassName);
                }
                // 替换 src 操作
                if (src) {
                    $img.attr("src", src).removeAttr("data-img").removeClass(me.elementClassName);
                    $img.on("error", function () {
                        if (me.settings.IMG_PLACEHOLDER) {
                            $(this).attr("src", me.settings.IMG_PLACEHOLDER).off("error");
                        }
                    });
                }
            });
        },
        _trigger: function () {
            var me = this;
            $(window).on("scroll", function () {
                // 添加 scroll 事件相应伐值，优化其性能
                if (!me.scrollTimer) {
                    me.scrollTimer = setTimeout(function () {
                        if (me.settings.MODE === "image") {
                            me._loadImg();
                        }
                        me.scrollTimer = 0;
                    }, me.scrollDelay);
                }
            });
        },
        /**
         * 判断是否在显示区域
         */
        _isInDisplayArea: function (item) {
            var me = this;
            if (item.getBoundingClientRect()) {
                var pos = item.getBoundingClientRect();
                return pos.top > 0 - me.settings.NUM_THRESHOLD && pos.top - me.settings.NUM_THRESHOLD < window.innerHeight;
            } else {
                var $item = $(item);
                var winH = window.innerHeight;
                var winOffsetTop = window.pageYOffset; // window Y 轴偏移量
                var itemOffsetTop = $item.offset().top;
                // itemOffsetTop >= winOffsetTop 只加载可视区域下方的内容
                // winOffsetTop + winH + me.settings.NUM_THRESHOLD 加载可视区域下方一屏内的内容
                return itemOffsetTop >= winOffsetTop && itemOffsetTop <= winOffsetTop + winH + me.settings.NUM_THRESHOLD;
            }
        },
        _loadImg: function () {
            var me = this;
            me.$element.each(function (index, item) {
                var $img = $(item);
                if (me.settings.IMG_PLACEHOLDER && $img.hasClass(me.elementClassName)) {
                    $img.attr("src", me.settings.IMG_PLACEHOLDER);
                    $img.on("error", function () {
                        $(this).attr("src", me.settings.IMG_PLACEHOLDER).off("error");
                    });
                }
                if (me._isInDisplayArea(item)) {
                    $img.trigger("appear");
                }
            });
        }
    };

    $.fn.lazyload = function ( options ) {
        var isZepto = typeof Zepto !== "undefined" ? true : false;
        var isJQuery = typeof jQuery !== "undefined" ? true : false;
        var plugin;

        options = options || {};
        options.selector = this.selector;

        this.each(function() {
            if (isJQuery) {
                if ( !$.data( this, scope ) ) {
                    $.data( this, scope, new Lazyload( this, options ) );
                }
            } else if (isZepto) {
                if (!$(this).data(scope)) {
                    plugin = new Lazyload( this, options );
                    $(this).data(scope, "initialized");
                }
            }
        });
        // chain jQuery functions
        return this;
    };

})($);<commit_msg>增加验证提示，调整了 init 函数<commit_after>/**
 * @file SQ.LazyLoad 延迟加载插件
 * @version 1.0.1
 */

/**
 * @changelog
 * 1.0.1  * 增加验证提示，调整了 init 函数。
 * 1.0.0  * 重写插件，调用方式改为 $. 链式调用。
 * 0.8.1  * 新增 ANIMATE 设置。
 * 0.8.0  * 重写 lazylaod 插件，提高整体性能。
 * 0.7.0  * 调整滑动阀值 scrollDelay，由 200 调整至 150；
 *        * 调整可视区的计算方式，由 offset 改为 getBoundingClientRect；
 *        * 针对 UC 浏览器极速版进行优化，可以在滑动过程中进行加载。
 * 0.6.5  * 修复 jshint 问题。
 * 0.6.4  * 修复图片加载失败时会导致 error 时间一直被触发的 bug；
 *          修复与 loadmore 插件配合使用时，无法替换加载错误的图片。
 * 0.6.3  + 新增首屏图片自动加载功能；
 *        + 新增占位图、占位背景设置。
 * 0.6.0  + 首屏图片自动加载。
 * 0.5.1  * 完成图片模式的延迟加载功能。
 * 0.0.1  + 新建。
 */
/*global
 $: false,
 SQ: false,
 console: false,
 jQuery: false
 */
;(function ($) {
    "use strict";
    /**
     * @name LazyLoad
     * @classdesc 内容延迟加载
     * @constructor
     * @param {object} config 插件配置（下面的参数为配置项，配置会写入属性）
     * @param {string} config.MODE                  延迟加载模式，默认为：image（图片模式）
     * @param {string} config.IMG_PLACEHOLDER       占位图片
     * @param {number} config.NUM_THRESHOLD         灵敏度，数值越大越灵敏，延迟性越小，默认为 200
     * @param {string} config.ANIMATE               动画类，例如 .fadeIn
     * @example $(".J_lazyload").lazyload({
    ANIMATE: ".fadeIn"
});
     */

    var scope = "sq-lazyload";      // data-* 后缀
    var defaults = {
        "MODE": "image",
        "NUM_THRESHOLD": 350
    };

    function Lazyload ( element, options ) {
        this.element = element;
        this.settings = $.extend( {}, defaults, options );
        this._defaults = defaults;
        this.init();
    }

    Lazyload.prototype = {
        construtor: "Lazyload",
        scrollTimer: 0,     // 滑动计时器
        scrollDelay: 150,   // 滑动阀值
        init: function () {
            var me = this;
            me.$element = $(me.element);
            me.elementClassName = me.settings.selector.slice(1);   // ".style-name" => "style-name"

            if (me._verify()) {
                me._bindLazyEvent();
                me._trigger();
                me._loadImg();
            }
        },
        /**
         * 验证参数是否合法
         * @returns {boolean}
         * @private
         */
        _verify: function () {
            /*if (!this.$element.length) {
                console.warn("SQ.lazyload: "+ this.settings.selector +"下未找到");
                return false;
            }*/
            return true;
        },
        _bindLazyEvent: function () {
            var me = this;
            // 为延迟加载元素绑定一次性执行事件
            me.$element.one("appear", function () {
                var img = this;
                var $img = $(img);
                var src = $img.attr("data-img");
                // 替换 src 操作
                if (src) {
                    $img.addClass("unvisible").attr("src", src).removeAttr("data-img").removeClass(me.elementClassName);
                    $img.on("load", function () {
                        // 添加动画
                        if (me.settings.ANIMATE) {
                            var animateClassName = me.settings.ANIMATE.indexOf(".") === 0 ? me.settings.ANIMATE.slice(1) : me.settings.ANIMATE;
                            $img.addClass("animated " + animateClassName).removeClass("unvisible");
                        }
                    });
                    $img.on("error", function () {
                        if (me.settings.IMG_PLACEHOLDER) {
                            $(this).attr("src", me.settings.IMG_PLACEHOLDER).off("error");
                        }
                    });
                }
            });
        },
        _trigger: function () {
            var me = this;
            $(window).on("scroll", function () {
                // 添加 scroll 事件相应伐值，优化其性能
                if (!me.scrollTimer) {
                    me.scrollTimer = setTimeout(function () {
                        if (me.settings.MODE === "image") {
                            me._loadImg();
                        }
                        me.scrollTimer = 0;
                    }, me.scrollDelay);
                }
            });
        },
        /**
         * 判断是否在显示区域
         */
        _isInDisplayArea: function (item) {
            var me = this;
            if (item.getBoundingClientRect()) {
                var pos = item.getBoundingClientRect();
                return pos.top > 0 - me.settings.NUM_THRESHOLD && pos.top - me.settings.NUM_THRESHOLD < window.innerHeight;
            } else {
                var $item = $(item);
                var winH = window.innerHeight;
                var winOffsetTop = window.pageYOffset; // window Y 轴偏移量
                var itemOffsetTop = $item.offset().top;
                // itemOffsetTop >= winOffsetTop 只加载可视区域下方的内容
                // winOffsetTop + winH + me.settings.NUM_THRESHOLD 加载可视区域下方一屏内的内容
                return itemOffsetTop >= winOffsetTop && itemOffsetTop <= winOffsetTop + winH + me.settings.NUM_THRESHOLD;
            }
        },
        _loadImg: function () {
            var me = this;
            me.$element.each(function (index, item) {
                var $img = $(item);
                // 设置占位图
                if (me.settings.IMG_PLACEHOLDER && $img.hasClass(me.elementClassName)) {
                    $img.attr("src", me.settings.IMG_PLACEHOLDER);
                    $img.on("error", function () {
                        $(this).attr("src", me.settings.IMG_PLACEHOLDER).off("error");
                    });
                }
                if (me._isInDisplayArea(item)) {
                    $img.trigger("appear");
                }
            });
        }
    };

    $.fn.lazyload = function ( options ) {
        var isZepto = typeof Zepto !== "undefined" ? true : false;
        var isJQuery = typeof jQuery !== "undefined" ? true : false;
        var plugin;

        options = options || {};
        options.selector = this.selector;

        if (!this.length) {
            console.warn("SQ.lazyload: 未找到"+ this.selector +"元素");
        }

        this.each(function() {
            if (isJQuery) {
                if ( !$.data( this, scope ) ) {
                    $.data( this, scope, new Lazyload( this, options ) );
                }
            } else if (isZepto) {
                if (!$(this).data(scope)) {
                    plugin = new Lazyload( this, options );
                    $(this).data(scope, "initialized");
                }
            }
        });
        // chain jQuery functions
        return this;
    };

})($);<|endoftext|>


<commit_before>/*!
 * Fork by Zach Fitzgerald and other contributors of Ionic Material
 *
 * Waves v0.5.4
 * http://fian.my.id/Waves
 *
 * Copyright 2014 Alfiana E. Sibuea and other contributors
 *
 * Released under the MIT license
 * https://github.com/fians/Waves/blob/master/LICENSE
 *
 */

var ionic = ionic || {};
ionic.material = ionic.material || {};

ionic.material.ink = (function() {
    'use strict';

    var Ink = Ink || {};

    // all DOM nodes
    var $$;

    // phantomJS throws an error when you try to use document.querySelectorAll.bind
    if(document && document.querySelectorAll && document.querySelectorAll.bind){
        try{
            // all DOM nodes
            $$ = document.querySelectorAll.bind(document);

        } catch(e){}
    } else if (window && window.angular && window.angular.element) {
        // we can use angular.element instead
        $$ = window.angular.element;
    } else {

            /**
             * mout.js 0.11.0 bind and slice polyfills (substitutes?)
             * TODO: pull out mout.js bind and slice molyfills and inject into material.ink
             */

            /**
             * Create slice of source array or array-like object
             */
            var slicePolyfill = function moutslicePolyfill(arr, start, end){
                var len = arr.length;
                /*jshint eqnull:true */
                if (start == null) {
                    start = 0;
                } else if (start < 0) {
                    start = Math.max(len + start, 0);
                } else {
                    start = Math.min(start, len);
                }

                if (end == null) {

                    end = len;
                } else if (end < 0) {
                    end = Math.max(len + end, 0);
                } else {
                    end = Math.min(end, len);
                }

                var result = [];
                while (start < end) {
                    result.push(arr[start++]);
                }

                return result;
            };

            /**
             * Return a function that will execute in the given context, optionally adding any additional supplied parameters to the beginning of the arguments collection.
             * @param {Function} fn  Function.
             * @param {object} context   Execution context.
             * @param {rest} args    Arguments (0...n arguments).
             * @return {Function} Wrapped Function.
             */
            var bindPolyfill = function moutBind(fn, context, args){
                var argsArr = slicePolyfill(arguments, 2); //curried args
                return function(){
                    return fn.apply(context, argsArr.concat(slicePolyfill(arguments)));
                };
            };

            $$ = bindPolyfill(document.querySelectorAll, document);
            /*jshint ignore:end */
    }

    if (!$$){
        throw new Error('ionic material ink module could not create reference of DOM nodes');
    }

    // Find exact position of element
    function isWindow(obj) {
        return obj !== null && obj === obj.window;
    }

    function getWindow(elem) {
        return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }

    function offset(elem) {
        var docElem, win,
            box = {
                top: 0,
                left: 0
            },
            doc = elem && elem.ownerDocument;

        docElem = doc.documentElement;

        if (typeof elem.getBoundingClientRect !== typeof undefined) {
            box = elem.getBoundingClientRect();
        }
        win = getWindow(doc);
        return {
            top: box.top + win.pageYOffset - docElem.clientTop,
            left: box.left + win.pageXOffset - docElem.clientLeft
        };
    }

    function hexToRgb(hex) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
        } : null;
    }

    function convertStyle(obj) {
        var style = '';

        for (var a in obj) {
            if (obj.hasOwnProperty(a)) {
                style += (a + ':' + obj[a] + ';');
            }
        }

        return style;
    }

    var Effect = {

        // Effect delay
        duration: 500,

        show: function(e) {

            // Disable right click
            if (e.button === 2) {
                return false;
            }

            var el = this;

            // Create ripple
            var ripple = document.createElement('div');
            var customColor = this.dataset.inkColor;
            var customOpacity = this.dataset.inkOpacity;
            var hasCustomRipple = customColor || customOpacity;
            ripple.className = 'ink-ripple';
            el.appendChild(ripple);

            // Get click coordinate and element witdh
            var pos = offset(el);
            var relativeY = (e.pageY - pos.top);
            var relativeX = (e.pageX - pos.left);
            var scale = 'scale(' + ((el.clientWidth / 100) * 2.5) + ')';

            // Support for touch devices
            if ('touches' in e) {
                relativeY = (e.touches[0].pageY - pos.top);
                relativeX = (e.touches[0].pageX - pos.left);
            }

            // Attach data to element
            ripple.setAttribute('data-hold', Date.now());
            ripple.setAttribute('data-scale', scale);
            ripple.setAttribute('data-x', relativeX);
            ripple.setAttribute('data-y', relativeY);

            // Set ripple position
            var rippleStyle = {
                'top': relativeY + 'px',
                'left': relativeX + 'px'
            };

            ripple.className = ripple.className + ' ink-notransition';

            if (hasCustomRipple) {
                var colorRgb;
                if (customColor) {
                    var fromHex = hexToRgb(customColor);
                    colorRgb = fromHex.r + ',' + fromHex.g + ',' + fromHex.b;
                } else {
                    colorRgb = '0,0,0';
                }
                if (!customOpacity) {
                    customOpacity = 0.2;
                }
                var bg = 'rgba(' + colorRgb + ',' + customOpacity + ')';
                rippleStyle['background-color'] = bg;
            }

            ripple.setAttribute('style', convertStyle(rippleStyle));
            ripple.className = ripple.className.replace('ink-notransition', '');

            // Scale the ripple
            rippleStyle['-webkit-transform'] = scale;
            rippleStyle['-moz-transform'] = scale;
            rippleStyle['-ms-transform'] = scale;
            rippleStyle['-o-transform'] = scale;
            rippleStyle.transform = scale;
            rippleStyle.opacity = '1';

            rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['-o-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['transition-duration'] = Effect.duration + 'ms';

            ripple.setAttribute('style', convertStyle(rippleStyle));
        },

        hide: function() {

            var el = this;

            var width = el.clientWidth * 1.4;

            // Get first ripple
            var ripple = null;

            var childrenLength = el.children.length;

            for (var a = 0; a < childrenLength; a++) {
                if (el.children[a].className.indexOf('ink-ripple') !== -1) {
                    ripple = el.children[a];
                    continue;
                }
            }

            if (!ripple) {
                return false;
            }

            var relativeX = ripple.getAttribute('data-x');
            var relativeY = ripple.getAttribute('data-y');
            var scale = ripple.getAttribute('data-scale');

            // Get delay beetween mousedown and mouse leave
            var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
            var delay = 500 - diff;

            if (delay < 0) {
                delay = 0;
            }

            // Fade out ripple after delay
            setTimeout(function() {

                var style = {
                    'top': relativeY + 'px',
                    'left': relativeX + 'px',
                    'opacity': '0',

                    // Duration
                    '-webkit-transition-duration': Effect.duration + 'ms',
                    '-moz-transition-duration': Effect.duration + 'ms',
                    '-o-transition-duration': Effect.duration + 'ms',
                    'transition-duration': Effect.duration + 'ms',
                    '-webkit-transform': scale,
                    '-moz-transform': scale,
                    '-ms-transform': scale,
                    '-o-transform': scale,
                    'transform': scale,
                };

                ripple.setAttribute('style', convertStyle(style));

                setTimeout(function() {
                    try {
                        el.removeChild(ripple);
                    } catch (e) {
                        return false;
                    }
                }, Effect.duration);
            }, delay);
        },

        // Little hack to make <input> can perform ink effect
        wrapInput: function(elements) {

            for (var a = 0; a < elements.length; a++) {

                var el = elements[a];

                if (el.tagName.toLowerCase() === 'input') {

                    var parent = el.parentNode;

                    // If input already have parent just pass through
                    if (parent.tagName.toLowerCase() === 'i' &&
                        parent.className.indexOf('ink') !== -1 &&
                        parent.className.indexOf('tab-item') !== -1 &&
                        parent.className.indexOf('button-fab') !== -1 &&
                        parent.className.indexOf('button-raised') !== -1 &&
                        parent.className.indexOf('button-flat') !== -1 &&
                        parent.className.indexOf('button-clear') !== -1 &&
                        parent.className.indexOf('button') !== -1 &&
                        parent.className.indexOf('item') !== -1) {
                        return false;
                    }

                    // Put element class and style to the specified parent
                    var wrapper = document.createElement('i');
                    wrapper.className = el.className + ' ink-input-wrapper';

                    var elementStyle = el.getAttribute('style');

                    if (!elementStyle) {
                        elementStyle = '';
                    }

                    wrapper.setAttribute('style', elementStyle);

                    el.className = 'ink-button-input';
                    el.removeAttribute('style');

                    // Put element as child
                    parent.replaceChild(wrapper, el);
                    wrapper.appendChild(el);
                }
            }
        }
    };

    Ink.displayEffect = function(options) {
        options = options || {};

        if ('duration' in options) {
            Effect.duration = options.duration;
        }

        //Wrap input inside <i> tag
        var selectors = '.ink,.tab-item,.button-fab,.button-raised,.button-flat,.button-clear,a.item,.popup .button';
        Effect.wrapInput($$(selectors));

        Array.prototype.forEach.call($$(selectors), function(i) {
            if ('ontouchstart' in window) {
                i.addEventListener('touchstart', Effect.show, false);
                i.addEventListener('touchend', Effect.hide, false);
                i.addEventListener('touchcancel', Effect.hide, false);
            } else {
                i.addEventListener('mousedown', Effect.show, false);
                i.addEventListener('mouseup', Effect.hide, false);
                i.addEventListener('mouseleave', Effect.hide, false);
            }
        });
    };

    return Ink;

})();
<commit_msg>renamed ink to Waves in prep for using external module<commit_after>/*!
 * Fork by Zach Fitzgerald and other contributors of Ionic Material
 *
 * Waves v0.5.4
 * http://fian.my.id/Waves
 *
 * Copyright 2014 Alfiana E. Sibuea and other contributors
 *
 * Released under the MIT license
 * https://github.com/fians/Waves/blob/master/LICENSE
 *
 */

var ionic = ionic || {};
ionic.material = ionic.material || {};

ionic.material.ink = (function() {
    'use strict';

    var Waves = Waves || {};

    // all DOM nodes
    var $$;

    // phantomJS throws an error when you try to use document.querySelectorAll.bind
    if(document && document.querySelectorAll && document.querySelectorAll.bind){
        try{
            // all DOM nodes
            $$ = document.querySelectorAll.bind(document);

        } catch(e){}
    } else if (window && window.angular && window.angular.element) {
        // we can use angular.element instead
        $$ = window.angular.element;
    } else {

            /**
             * mout.js 0.11.0 bind and slice polyfills (substitutes?)
             * TODO: pull out mout.js bind and slice molyfills and inject into material.ink
             */

            /**
             * Create slice of source array or array-like object
             */
            var slicePolyfill = function moutslicePolyfill(arr, start, end){
                var len = arr.length;
                /*jshint eqnull:true */
                if (start == null) {
                    start = 0;
                } else if (start < 0) {
                    start = Math.max(len + start, 0);
                } else {
                    start = Math.min(start, len);
                }

                if (end == null) {

                    end = len;
                } else if (end < 0) {
                    end = Math.max(len + end, 0);
                } else {
                    end = Math.min(end, len);
                }

                var result = [];
                while (start < end) {
                    result.push(arr[start++]);
                }

                return result;
            };

            /**
             * Return a function that will execute in the given context, optionally adding any additional supplied parameters to the beginning of the arguments collection.
             * @param {Function} fn  Function.
             * @param {object} context   Execution context.
             * @param {rest} args    Arguments (0...n arguments).
             * @return {Function} Wrapped Function.
             */
            var bindPolyfill = function moutBind(fn, context, args){
                var argsArr = slicePolyfill(arguments, 2); //curried args
                return function(){
                    return fn.apply(context, argsArr.concat(slicePolyfill(arguments)));
                };
            };

            $$ = bindPolyfill(document.querySelectorAll, document);
            /*jshint ignore:end */
    }

    if (!$$){
        throw new Error('ionic material ink module could not create reference of DOM nodes');
    }

    // Find exact position of element
    function isWindow(obj) {
        return obj !== null && obj === obj.window;
    }

    function getWindow(elem) {
        return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }

    function offset(elem) {
        var docElem, win,
            box = {
                top: 0,
                left: 0
            },
            doc = elem && elem.ownerDocument;

        docElem = doc.documentElement;

        if (typeof elem.getBoundingClientRect !== typeof undefined) {
            box = elem.getBoundingClientRect();
        }
        win = getWindow(doc);
        return {
            top: box.top + win.pageYOffset - docElem.clientTop,
            left: box.left + win.pageXOffset - docElem.clientLeft
        };
    }

    function hexToRgb(hex) {
        var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
        return result ? {
            r: parseInt(result[1], 16),
            g: parseInt(result[2], 16),
            b: parseInt(result[3], 16)
        } : null;
    }

    function convertStyle(obj) {
        var style = '';

        for (var a in obj) {
            if (obj.hasOwnProperty(a)) {
                style += (a + ':' + obj[a] + ';');
            }
        }

        return style;
    }

    var Effect = {

        // Effect delay
        duration: 500,

        show: function(e) {

            // Disable right click
            if (e.button === 2) {
                return false;
            }

            var el = this;

            // Create ripple
            var ripple = document.createElement('div');
            var customColor = this.dataset.inkColor;
            var customOpacity = this.dataset.inkOpacity;
            var hasCustomRipple = customColor || customOpacity;
            ripple.className = 'ink-ripple';
            el.appendChild(ripple);

            // Get click coordinate and element witdh
            var pos = offset(el);
            var relativeY = (e.pageY - pos.top);
            var relativeX = (e.pageX - pos.left);
            var scale = 'scale(' + ((el.clientWidth / 100) * 2.5) + ')';

            // Support for touch devices
            if ('touches' in e) {
                relativeY = (e.touches[0].pageY - pos.top);
                relativeX = (e.touches[0].pageX - pos.left);
            }

            // Attach data to element
            ripple.setAttribute('data-hold', Date.now());
            ripple.setAttribute('data-scale', scale);
            ripple.setAttribute('data-x', relativeX);
            ripple.setAttribute('data-y', relativeY);

            // Set ripple position
            var rippleStyle = {
                'top': relativeY + 'px',
                'left': relativeX + 'px'
            };

            ripple.className = ripple.className + ' ink-notransition';

            if (hasCustomRipple) {
                var colorRgb;
                if (customColor) {
                    var fromHex = hexToRgb(customColor);
                    colorRgb = fromHex.r + ',' + fromHex.g + ',' + fromHex.b;
                } else {
                    colorRgb = '0,0,0';
                }
                if (!customOpacity) {
                    customOpacity = 0.2;
                }
                var bg = 'rgba(' + colorRgb + ',' + customOpacity + ')';
                rippleStyle['background-color'] = bg;
            }

            ripple.setAttribute('style', convertStyle(rippleStyle));
            ripple.className = ripple.className.replace('ink-notransition', '');

            // Scale the ripple
            rippleStyle['-webkit-transform'] = scale;
            rippleStyle['-moz-transform'] = scale;
            rippleStyle['-ms-transform'] = scale;
            rippleStyle['-o-transform'] = scale;
            rippleStyle.transform = scale;
            rippleStyle.opacity = '1';

            rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['-o-transition-duration'] = Effect.duration + 'ms';
            rippleStyle['transition-duration'] = Effect.duration + 'ms';

            ripple.setAttribute('style', convertStyle(rippleStyle));
        },

        hide: function() {

            var el = this;

            var width = el.clientWidth * 1.4;

            // Get first ripple
            var ripple = null;

            var childrenLength = el.children.length;

            for (var a = 0; a < childrenLength; a++) {
                if (el.children[a].className.indexOf('ink-ripple') !== -1) {
                    ripple = el.children[a];
                    continue;
                }
            }

            if (!ripple) {
                return false;
            }

            var relativeX = ripple.getAttribute('data-x');
            var relativeY = ripple.getAttribute('data-y');
            var scale = ripple.getAttribute('data-scale');

            // Get delay beetween mousedown and mouse leave
            var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
            var delay = 500 - diff;

            if (delay < 0) {
                delay = 0;
            }

            // Fade out ripple after delay
            setTimeout(function() {

                var style = {
                    'top': relativeY + 'px',
                    'left': relativeX + 'px',
                    'opacity': '0',

                    // Duration
                    '-webkit-transition-duration': Effect.duration + 'ms',
                    '-moz-transition-duration': Effect.duration + 'ms',
                    '-o-transition-duration': Effect.duration + 'ms',
                    'transition-duration': Effect.duration + 'ms',
                    '-webkit-transform': scale,
                    '-moz-transform': scale,
                    '-ms-transform': scale,
                    '-o-transform': scale,
                    'transform': scale,
                };

                ripple.setAttribute('style', convertStyle(style));

                setTimeout(function() {
                    try {
                        el.removeChild(ripple);
                    } catch (e) {
                        return false;
                    }
                }, Effect.duration);
            }, delay);
        },

        // Little hack to make <input> can perform ink effect
        wrapInput: function(elements) {

            for (var a = 0; a < elements.length; a++) {

                var el = elements[a];

                if (el.tagName.toLowerCase() === 'input') {

                    var parent = el.parentNode;

                    // If input already have parent just pass through
                    if (parent.tagName.toLowerCase() === 'i' &&
                        parent.className.indexOf('ink') !== -1 &&
                        parent.className.indexOf('tab-item') !== -1 &&
                        parent.className.indexOf('button-fab') !== -1 &&
                        parent.className.indexOf('button-raised') !== -1 &&
                        parent.className.indexOf('button-flat') !== -1 &&
                        parent.className.indexOf('button-clear') !== -1 &&
                        parent.className.indexOf('button') !== -1 &&
                        parent.className.indexOf('item') !== -1) {
                        return false;
                    }

                    // Put element class and style to the specified parent
                    var wrapper = document.createElement('i');
                    wrapper.className = el.className + ' ink-input-wrapper';

                    var elementStyle = el.getAttribute('style');

                    if (!elementStyle) {
                        elementStyle = '';
                    }

                    wrapper.setAttribute('style', elementStyle);

                    el.className = 'ink-button-input';
                    el.removeAttribute('style');

                    // Put element as child
                    parent.replaceChild(wrapper, el);
                    wrapper.appendChild(el);
                }
            }
        }
    };

    Waves.displayEffect = function(options) {
        options = options || {};

        if ('duration' in options) {
            Effect.duration = options.duration;
        }

        //Wrap input inside <i> tag
        var selectors = '.ink,.tab-item,.button-fab,.button-raised,.button-flat,.button-clear,a.item,.popup .button';
        Effect.wrapInput($$(selectors));

        Array.prototype.forEach.call($$(selectors), function(i) {
            if ('ontouchstart' in window) {
                i.addEventListener('touchstart', Effect.show, false);
                i.addEventListener('touchend', Effect.hide, false);
                i.addEventListener('touchcancel', Effect.hide, false);
            } else {
                i.addEventListener('mousedown', Effect.show, false);
                i.addEventListener('mouseup', Effect.hide, false);
                i.addEventListener('mouseleave', Effect.hide, false);
            }
        });
    };

    return Waves;

})();
<|endoftext|>


<commit_before>/* jshint ignore: start */

// *** DO NOT MODIFY THIS FILE ***
// This file was generated from src/html/header.template
// Regenerate using bin/gen-template

var incrementalDom = require('../../lib/incremental-dom');
var elementOpen = incrementalDom.elementOpen;
var elementClose = incrementalDom.elementClose;
var elementVoid = incrementalDom.elementVoid;
var text = incrementalDom.text;
var images = require("./images-factory");

module.exports = template;

function template (data, handlers, translate) {
  elementOpen("div", null, ["class", "o-header__container"])
    elementOpen("section", null, ["class", "o-header__section"])
      elementOpen("div", null, ["class", "o-header__brand"])
        if (data.mode === 'Basic' || data.mode === 'Legacy Course') {
          elementOpen("a", null, null, "href", data.links.home)
            elementOpen("div", null, ["class", "o-header__logo o-header__logo--pearson"])
            if (!data.logo) {
              elementOpen("img", null, null, "src", images.logoLarge, "alt", translate('Pearson - Home'))
            } else {
              elementOpen("img", null, null, "src", data.logo, "alt", translate('Pearson - Home'))
            }
              elementClose("img")
            elementClose("div")
          elementClose("a")
        }
        if (data.mode ==='Signed Out' || data.mode === 'Integration') {
          elementOpen("div", null, ["class", "o-header__logo o-header__logo--pearson"])
          if (!data.logo) {
            elementOpen("img", null, null, "src", images.logoLarge, "alt", translate('Pearson - Home'))
          } else {
            elementOpen("img", null, null, "src", data.logo, "alt", translate('Pearson - Home'))
          }
            elementClose("img")
          elementClose("div")
        }
      elementClose("div")
    elementClose("section")
    elementOpen("section", null, ["class", "o-header__section o-header__section--right"])
      elementOpen("nav", null, ["class", "o-header__nav"])
        elementOpen("ul", null, ["class", "o-header__nav-items"])
          elementOpen("li", null, ["class", "o-header__nav-item o-app-header__nav-item-notification", "aria-hidden", "true"])
          elementClose("li")
          elementOpen("li", null, ["class", "o-header__nav-item o-app-header__nav-item-help"])
            if (!data.help) {
              elementOpen("a", null, ["href", "#", "id", "header-nav-link"], "onclick", function ($event) {handlers.handleHelpNavItemClick($event)})
                elementOpen("i")
                  elementOpen("img", null, ["class", "hover-image"], "src", images.helpHoverNormal, "alt", translate('help'))
                  elementClose("img")
                elementClose("i")
              elementClose("a")
            }
            if (typeof data.help === 'string') {
              elementOpen("a", null, null, "href", data.help)
              elementClose("a")
            }
            if (typeof data.help === 'object') {
              elementOpen("div", null, ["class", "o-dropdown-menu o-dropdown-menu--right"])
                elementOpen("a", null, ["href", "#", "id", "o-app-header-help-menu-toggle", "class", "o-dropdown-menu__toggle", "data-toggle", "dropdown-menu", "aria-haspopup", "true", "aria-expanded", "false"])
                elementClose("a")
                elementOpen("ul", null, ["class", "o-dropdown-menu__menu-items", "aria-labelledby", "o-app-header-menu-toggle-help"])
                  ;(Array.isArray(data.help) ? data.help : Object.keys(data.help)).forEach(function(key, $index) {
                    elementOpen("li", $index, ["class", "o-dropdown-menu__menu-item"])
                      if (typeof data.help[key] === 'string') {
                        elementOpen("a", null, null, "href", data.help[key])
                          text("" + (key) + "")
                        elementClose("a")
                      }
                      if (data.help[key].href) {
                        elementOpen("a", null, null, "href", data.help[key].href, "target", data.help[key].target)
                          text("" + (key) + "")
                        elementClose("a")
                      }
                      if (typeof data.help[key].onClick === 'function') {
                        elementOpen("a", null, ["href", "#"], "onclick", function ($event) {data.help[key].onClick($event)})
                          text("" + (key) + "")
                        elementClose("a")
                      }
                    elementClose("li")
                  }, data.help)
                elementClose("ul")
              elementClose("div")
            }
          elementClose("li")
          elementOpen("li", null, null, "class", data.menuNavItemClasses)
            if (data.mode === 'Signed Out' && data.showLoginControls) {
              elementOpen("a", null, ["href", "#"], "onclick", function ($event) {handlers.handleLogin($event)})
                text("" + (translate('Sign In')) + "")
              elementClose("a")
            }
            if (data.mode === 'Basic' || data.mode === 'Legacy Course') {
              elementOpen("div", null, ["class", "o-dropdown-menu o-dropdown-menu--right o-app-header__menu-menu"])
                elementOpen("button", null, ["type", "button", "class", "o-dropdown-menu__toggle", "id", "header-nav-link-account", "data-toggle", "dropdown-menu", "aria-haspopup", "true", "aria-expanded", "false"])
                  elementOpen("span", null, ["id", "o-app-header-user-menu-label", "class", "o-app-header--sr-only"])
                    text("" + (translate('User account menu')) + "")
                  elementClose("span")
                  elementOpen("span", null, ["class", "o-app-header__username o-app-header--truncate o-header__viewport-tablet--visible o-header__viewport-desktop--visible"])
                    text("" + (data.user.givenName) + "")
                  elementClose("span")
                  elementOpen("span", null, ["class", "o-header__viewport-tablet--hidden o-header__viewport-desktop--hidden"])
                    elementOpen("i")
                      elementOpen("img", null, ["class", "hover-image"], "src", images.personHoverNormal, "alt", translate('User account menu'))
                      elementClose("img")
                    elementClose("i")
                  elementClose("span")
                elementClose("button")
                elementOpen("ul", null, ["class", "o-dropdown-menu__menu-items", "aria-labelledby", "o-app-header-user-menu-label"])
                  elementOpen("li")
                    elementOpen("h2", null, ["class", "o-dropdown-menu__menu-item-title"])
                      text("" + (translate('My Account')) + "")
                    elementClose("h2")
                    elementOpen("div", null, ["class", "o-dropdown-menu__menu-close"])
                      elementOpen("button", null, ["class", "dropdown-close-button"])
                        elementOpen("img", null, null, "src", images.close, "alt", translate('close'))
                        elementClose("img")
                      elementClose("button")
                    elementClose("div")
                  elementClose("li")
                  ;(Array.isArray(data.menuItems) ? data.menuItems : Object.keys(data.menuItems)).forEach(function(item, $index) {
                    elementOpen("li", item.key, null, "class", item.classes)
                      if (item.href) {
                        elementOpen("a", null, ["class", "o-app-header--truncate"], "href", item.href, "target", item.target)
                          text("" + (item.text) + "")
                        elementClose("a")
                      }
                      if (typeof item.onClick === 'function') {
                        elementOpen("a", null, ["class", "pe-btn__primary--btn_xlarge o-app-header--truncate sign-out-button", "href", "#"], "onclick", function ($event) {item.onClick($event)})
                          text("" + (item.text) + "")
                        elementClose("a")
                      }
                      if (item.isCourseNav) {
                        elementOpen("ul", null, ["class", "o-app-header__menu-items-course-nav o-header__viewport-tablet--hidden o-header__viewport-desktop--hidden"])
                          ;(Array.isArray(item.courseNavMenuItems) ? item.courseNavMenuItems : Object.keys(item.courseNavMenuItems)).forEach(function(courseNavItem, $index) {
                            elementOpen("li", courseNavItem.key, null, "class", courseNavItem.classes)
                              if (courseNavItem.href) {
                                elementOpen("a", null, ["class", "o-app-header--truncate"], "href", courseNavItem.href, "target", courseNavItem.target)
                                  text("" + (courseNavItem.text) + "")
                                elementClose("a")
                              }
                              if (typeof courseNavItem.onClick === 'function') {
                                elementOpen("a", null, ["class", "o-app-header--truncate", "href", "#"], "onclick", function ($event) {courseNavItem.onClick($event)})
                                  text("" + (courseNavItem.text) + "")
                                elementClose("a")
                              }
                            elementClose("li")
                          }, item.courseNavMenuItems)
                        elementClose("ul")
                      }
                    elementClose("li")
                  }, data.menuItems)
                elementClose("ul")
              elementClose("div")
            }
          elementClose("li")
        elementClose("ul")
      elementClose("nav")
    elementClose("section")
  elementClose("div")
}<commit_msg>Changes in the condition of the logo display<commit_after>/* jshint ignore: start */

// *** DO NOT MODIFY THIS FILE ***
// This file was generated from src/html/header.template
// Regenerate using bin/gen-template

var incrementalDom = require('../../lib/incremental-dom');
var elementOpen = incrementalDom.elementOpen;
var elementClose = incrementalDom.elementClose;
var elementVoid = incrementalDom.elementVoid;
var text = incrementalDom.text;
var images = require("./images-factory");

module.exports = template;

function template (data, handlers, translate) {
  elementOpen("div", null, ["class", "o-header__container"])
    elementOpen("section", null, ["class", "o-header__section"])
      elementOpen("div", null, ["class", "o-header__brand"])
      var logo = data.logo ? data.logo : images.logoLarge;
        if (data.mode === 'Basic' || data.mode === 'Legacy Course') {
          elementOpen("a", null, null, "href", data.links.home)
            elementOpen("div", null, ["class", "o-header__logo o-header__logo--pearson"])
            elementOpen("img", null, null, "src", logo, "alt", translate('Pearson - Home'))
              elementClose("img")
            elementClose("div")
          elementClose("a")
        }
        if (data.mode ==='Signed Out' || data.mode === 'Integration') {
          elementOpen("div", null, ["class", "o-header__logo o-header__logo--pearson"])
            elementOpen("img", null, null, "src", logo, "alt", translate('Pearson - Home'))
            elementClose("img")
          elementClose("div")
        }
      elementClose("div")
    elementClose("section")
    elementOpen("section", null, ["class", "o-header__section o-header__section--right"])
      elementOpen("nav", null, ["class", "o-header__nav"])
        elementOpen("ul", null, ["class", "o-header__nav-items"])
          elementOpen("li", null, ["class", "o-header__nav-item o-app-header__nav-item-notification", "aria-hidden", "true"])
          elementClose("li")
          elementOpen("li", null, ["class", "o-header__nav-item o-app-header__nav-item-help"])
            if (!data.help) {
              elementOpen("a", null, ["href", "#", "id", "header-nav-link"], "onclick", function ($event) {handlers.handleHelpNavItemClick($event)})
                elementOpen("i")
                  elementOpen("img", null, ["class", "hover-image"], "src", images.helpHoverNormal, "alt", translate('help'))
                  elementClose("img")
                elementClose("i")
              elementClose("a")
            }
            if (typeof data.help === 'string') {
              elementOpen("a", null, null, "href", data.help)
              elementClose("a")
            }
            if (typeof data.help === 'object') {
              elementOpen("div", null, ["class", "o-dropdown-menu o-dropdown-menu--right"])
                elementOpen("a", null, ["href", "#", "id", "o-app-header-help-menu-toggle", "class", "o-dropdown-menu__toggle", "data-toggle", "dropdown-menu", "aria-haspopup", "true", "aria-expanded", "false"])
                elementClose("a")
                elementOpen("ul", null, ["class", "o-dropdown-menu__menu-items", "aria-labelledby", "o-app-header-menu-toggle-help"])
                  ;(Array.isArray(data.help) ? data.help : Object.keys(data.help)).forEach(function(key, $index) {
                    elementOpen("li", $index, ["class", "o-dropdown-menu__menu-item"])
                      if (typeof data.help[key] === 'string') {
                        elementOpen("a", null, null, "href", data.help[key])
                          text("" + (key) + "")
                        elementClose("a")
                      }
                      if (data.help[key].href) {
                        elementOpen("a", null, null, "href", data.help[key].href, "target", data.help[key].target)
                          text("" + (key) + "")
                        elementClose("a")
                      }
                      if (typeof data.help[key].onClick === 'function') {
                        elementOpen("a", null, ["href", "#"], "onclick", function ($event) {data.help[key].onClick($event)})
                          text("" + (key) + "")
                        elementClose("a")
                      }
                    elementClose("li")
                  }, data.help)
                elementClose("ul")
              elementClose("div")
            }
          elementClose("li")
          elementOpen("li", null, null, "class", data.menuNavItemClasses)
            if (data.mode === 'Signed Out' && data.showLoginControls) {
              elementOpen("a", null, ["href", "#"], "onclick", function ($event) {handlers.handleLogin($event)})
                text("" + (translate('Sign In')) + "")
              elementClose("a")
            }
            if (data.mode === 'Basic' || data.mode === 'Legacy Course') {
              elementOpen("div", null, ["class", "o-dropdown-menu o-dropdown-menu--right o-app-header__menu-menu"])
                elementOpen("button", null, ["type", "button", "class", "o-dropdown-menu__toggle", "id", "header-nav-link-account", "data-toggle", "dropdown-menu", "aria-haspopup", "true", "aria-expanded", "false"])
                  elementOpen("span", null, ["id", "o-app-header-user-menu-label", "class", "o-app-header--sr-only"])
                    text("" + (translate('User account menu')) + "")
                  elementClose("span")
                  elementOpen("span", null, ["class", "o-app-header__username o-app-header--truncate o-header__viewport-tablet--visible o-header__viewport-desktop--visible"])
                    text("" + (data.user.givenName) + "")
                  elementClose("span")
                  elementOpen("span", null, ["class", "o-header__viewport-tablet--hidden o-header__viewport-desktop--hidden"])
                    elementOpen("i")
                      elementOpen("img", null, ["class", "hover-image"], "src", images.personHoverNormal, "alt", translate('User account menu'))
                      elementClose("img")
                    elementClose("i")
                  elementClose("span")
                elementClose("button")
                elementOpen("ul", null, ["class", "o-dropdown-menu__menu-items", "aria-labelledby", "o-app-header-user-menu-label"])
                  elementOpen("li")
                    elementOpen("h2", null, ["class", "o-dropdown-menu__menu-item-title"])
                      text("" + (translate('My Account')) + "")
                    elementClose("h2")
                    elementOpen("div", null, ["class", "o-dropdown-menu__menu-close"])
                      elementOpen("button", null, ["class", "dropdown-close-button"])
                        elementOpen("img", null, null, "src", images.close, "alt", translate('close'))
                        elementClose("img")
                      elementClose("button")
                    elementClose("div")
                  elementClose("li")
                  ;(Array.isArray(data.menuItems) ? data.menuItems : Object.keys(data.menuItems)).forEach(function(item, $index) {
                    elementOpen("li", item.key, null, "class", item.classes)
                      if (item.href) {
                        elementOpen("a", null, ["class", "o-app-header--truncate"], "href", item.href, "target", item.target)
                          text("" + (item.text) + "")
                        elementClose("a")
                      }
                      if (typeof item.onClick === 'function') {
                        elementOpen("a", null, ["class", "pe-btn__primary--btn_xlarge o-app-header--truncate sign-out-button", "href", "#"], "onclick", function ($event) {item.onClick($event)})
                          text("" + (item.text) + "")
                        elementClose("a")
                      }
                      if (item.isCourseNav) {
                        elementOpen("ul", null, ["class", "o-app-header__menu-items-course-nav o-header__viewport-tablet--hidden o-header__viewport-desktop--hidden"])
                          ;(Array.isArray(item.courseNavMenuItems) ? item.courseNavMenuItems : Object.keys(item.courseNavMenuItems)).forEach(function(courseNavItem, $index) {
                            elementOpen("li", courseNavItem.key, null, "class", courseNavItem.classes)
                              if (courseNavItem.href) {
                                elementOpen("a", null, ["class", "o-app-header--truncate"], "href", courseNavItem.href, "target", courseNavItem.target)
                                  text("" + (courseNavItem.text) + "")
                                elementClose("a")
                              }
                              if (typeof courseNavItem.onClick === 'function') {
                                elementOpen("a", null, ["class", "o-app-header--truncate", "href", "#"], "onclick", function ($event) {courseNavItem.onClick($event)})
                                  text("" + (courseNavItem.text) + "")
                                elementClose("a")
                              }
                            elementClose("li")
                          }, item.courseNavMenuItems)
                        elementClose("ul")
                      }
                    elementClose("li")
                  }, data.menuItems)
                elementClose("ul")
              elementClose("div")
            }
          elementClose("li")
        elementClose("ul")
      elementClose("nav")
    elementClose("section")
  elementClose("div")
}<|endoftext|>


<commit_before>var VDomHoz = function(table){
	this.table = table;

	this.element = this.table.rowManager.tableElement;
	this.holderEl = this.table.rowManager.element;

	this.leftCol = 0;
	this.rightCol = 0;
	this.scrollLeft = 0;

	this.vDomScrollPosLeft = 0;
	this.vDomScrollPosRight = 0;

	this.vDomPadLeft = 0;
	this.vDomPadRight = 0;

	this.window = 50; //pixel margin to make column visible before it is shown on screen

	this.initialized = false;

	this.columns = [];

	this.initialize();
};

VDomHoz.prototype.initialize = function(){
	this.holderEl.addEventListener("scroll", () => {
		var left = this.holderEl.scrollLeft;

		if(this.scrollLeft != left){
			this.scrollLeft = left;
			this.scroll(left - (this.vDomScrollPosLeft + this.window));
		}
	});
};

VDomHoz.prototype.deinitialize = function(){
	this.initialized = false;
};

VDomHoz.prototype.clear = function(){
	this.columns = [];

	this.leftCol = -1;
	this.rightCol = 0;

	this.vDomScrollPosLeft = 0;
	this.vDomScrollPosRight = 0;
	this.vDomPadLeft = 0;
	this.vDomPadRight = 0;
};

VDomHoz.prototype.reinitialize = function(){
	this.clear();

	this.scrollLeft = this.holderEl.scrollLeft;

	this.vDomScrollPosLeft = this.scrollLeft - this.window;
	this.vDomScrollPosRight = this.vDomScrollPosLeft + this.holderEl.clientWidth + this.window;

	var colPos = 0;

	this.table.columnManager.columnsByIndex.forEach((column) => {
		var config = {};

		if(column.visible){
			var width = column.getWidth();

			config.leftPos = colPos;
			config.rightPos = colPos + width;

			if((colPos + width > this.vDomScrollPosLeft) && (colPos < this.vDomScrollPosRight)){
        		//column is visible

        		if(this.leftCol == -1){
        			this.leftCol = this.columns.length;
        			this.vDomPadLeft = colPos;
        		}

        		this.rightCol = this.columns.length;
        	}else{
        		// column is hidden
        		if(this.leftCol !== -1){
        			this.vDomPadRight += width;
        		}
        	}

        	this.columns.push(column);

        	column.modules.vdomHoz = config;

        	colPos += width;
        }
    });

	this.element.style.paddingLeft = this.vDomPadLeft + "px";
	this.element.style.paddingRight = this.vDomPadRight + "px";

	this.initialized = true;

	this.renitializeRows();

	this.holderEl.scrollLeft = this.scrollLeft;
};

VDomHoz.prototype.renitializeRows = function(){
	var rows = this.table.rowManager.getVisibleRows();
	rows.forEach((row) => {
		this.reinitializeRow(row, true);
	});
};

VDomHoz.prototype.scroll = function(diff){
	this.vDomScrollPosLeft += diff;
	this.vDomScrollPosRight += diff;

	if(diff > (this.holderEl.clientWidth * .8)){
		this.reinitialize();
	}else{
		if(diff > 0){
			//scroll right
			this.addColRight();
			this.removeColLeft();
		}else{
			//scroll left
			this.addColLeft();
			this.removeColRight();
		}
	}
};

VDomHoz.prototype.addColRight = function(){
	var column = this.columns[this.rightCol + 1],
	rows;

	if(column && column.modules.vdomHoz.leftPos <= this.vDomScrollPosRight){

		rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().appendChild(cell.getElement());
			cell.cellRendered();
		});

		this.vDomPadRight -= column.getWidth();
		this.element.style.paddingRight = this.vDomPadRight + "px";

		this.rightCol++;

		this.addColRight();
	}
};

VDomHoz.prototype.addColLeft = function(){
	var column = this.columns[this.leftCol - 1],
	rows;

	if(column && column.modules.vdomHoz.rightPos >= this.vDomScrollPosLeft){
		var rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().prepend(cell.getElement());
			cell.cellRendered();
		});

		this.vDomPadLeft -= column.getWidth();
		this.element.style.paddingLeft = this.vDomPadLeft + "px";

		this.leftCol--;

		this.addColLeft();
	}
};

VDomHoz.prototype.removeColRight = function(column){
	var column = this.columns[this.rightCol],
	rows;

	if(column && column.modules.vdomHoz.leftPos > this.vDomScrollPosRight){
		rows = this.table.rowManager.getVisibleRows();

		column.modules.vdomHoz.visible = false;

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().removeChild(cell.getElement());
		});

		this.vDomPadRight += column.getWidth();
		this.element.style.paddingRight = this.vDomPadRight + "px";

		this.rightCol --;

		this.removeColRight();
	}
};

VDomHoz.prototype.removeColLeft = function(){
	var column = this.columns[this.leftCol],
	rows;

	if(column && column.modules.vdomHoz.rightPos < this.vDomScrollPosLeft){

		rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().removeChild(cell.getElement());
		});

		this.vDomPadLeft += column.getWidth();
		this.element.style.paddingLeft = this.vDomPadLeft + "px";

		this.leftCol ++;

		this.removeColLeft();
	}
};

VDomHoz.prototype.initializeRow = function(row){
	row.modules.vdomHoz = {
		leftCol:this.leftCol,
		rightCol:this.rightCol,
	};

	for(let i = this.leftCol; i <= this.rightCol; i++){
		let column = this.table.columnManager.getColumnByIndex(i);

		if(column.visible){
			let cell = row.getCell(column);

			row.element.appendChild(cell.getElement());
			cell.cellRendered();
		}
	}
};

VDomHoz.prototype.reinitializeRow = function(row, force){
	if(force || !row.modules.vdomHoz || row.modules.vdomHoz.leftCol !== this.leftCol || row.modules.vdomHoz.rightCol !== this.rightCol){
		while(row.element.firstChild) row.element.removeChild(row.element.firstChild);

		this.initializeRow(row);
	}
};<commit_msg>allow recalculation of hoz vdom when column structure changes<commit_after>var VDomHoz = function(table){
	this.table = table;

	this.element = this.table.rowManager.tableElement;
	this.holderEl = this.table.rowManager.element;

	this.leftCol = 0;
	this.rightCol = 0;
	this.scrollLeft = 0;

	this.vDomScrollPosLeft = 0;
	this.vDomScrollPosRight = 0;

	this.vDomPadLeft = 0;
	this.vDomPadRight = 0;

	this.window = 200; //pixel margin to make column visible before it is shown on screen

	this.initialized = false;

	this.columns = [];

	this.initialize();
};

VDomHoz.prototype.initialize = function(){
	this.holderEl.addEventListener("scroll", () => {
		var left = this.holderEl.scrollLeft;

		if(this.scrollLeft != left){
			this.scrollLeft = left;
			this.scroll(left - (this.vDomScrollPosLeft + this.window));
		}
	});
};

VDomHoz.prototype.deinitialize = function(){
	this.initialized = false;
};

VDomHoz.prototype.clear = function(){
	this.columns = [];

	this.leftCol = -1;
	this.rightCol = 0;

	this.vDomScrollPosLeft = 0;
	this.vDomScrollPosRight = 0;
	this.vDomPadLeft = 0;
	this.vDomPadRight = 0;
};

VDomHoz.prototype.reinitialize = function(update){
	var old = {
		cols:this.columns,
		leftCol:this.leftCol,
		rightCol:this.rightCol,
	};

	console.log("reinit")

	this.clear();

	this.scrollLeft = this.holderEl.scrollLeft;

	this.vDomScrollPosLeft = this.scrollLeft - this.window;
	this.vDomScrollPosRight = this.scrollLeft + this.holderEl.clientWidth + this.window;

	var colPos = 0;

	this.table.columnManager.columnsByIndex.forEach((column) => {
		var config = {};

		if(column.visible){
			var width = column.getWidth();

			config.leftPos = colPos;
			config.rightPos = colPos + width;

			if((colPos + width > this.vDomScrollPosLeft) && (colPos < this.vDomScrollPosRight)){
        		//column is visible

        		if(this.leftCol == -1){
        			this.leftCol = this.columns.length;
        			this.vDomPadLeft = colPos;
        		}

        		this.rightCol = this.columns.length;
        	}else{
        		// column is hidden
        		if(this.leftCol !== -1){
        			this.vDomPadRight += width;
        		}
        	}

        	this.columns.push(column);

        	column.modules.vdomHoz = config;

        	colPos += width;
        }
    });

	this.element.style.paddingLeft = this.vDomPadLeft + "px";
	this.element.style.paddingRight = this.vDomPadRight + "px";

	this.initialized = true;

	if(!update || this.reinitChanged(old)){
		this.renitializeRows();
	}

	this.holderEl.scrollLeft = this.scrollLeft;
};

VDomHoz.prototype.reinitChanged = function(old){
	var match = true;

	if(old.cols.length !== this.columns.length || old.leftCol !== this.leftCol || old.rightCol !== this.rightCol){
		console.log("changed")
		return true;
	}

	old.cols.forEach((col, i) => {
		if(col !== this.columns[i]){
			match = false;
		}
	});

	return !match;
}

VDomHoz.prototype.renitializeRows = function(){
	var rows = this.table.rowManager.getVisibleRows();
	rows.forEach((row) => {
		this.reinitializeRow(row, true);
	});
};

VDomHoz.prototype.scroll = function(diff){
	this.vDomScrollPosLeft += diff;
	this.vDomScrollPosRight += diff;

	if(diff > (this.holderEl.clientWidth * .8)){
		this.reinitialize();
	}else{
		if(diff > 0){
			//scroll right
			this.addColRight();
			this.removeColLeft();
		}else{
			//scroll left
			this.addColLeft();
			this.removeColRight();
		}
	}
};

VDomHoz.prototype.addColRight = function(){
	var column = this.columns[this.rightCol + 1],
	rows;

	if(column && column.modules.vdomHoz.leftPos <= this.vDomScrollPosRight){

		rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().appendChild(cell.getElement());
			cell.cellRendered();
		});

		this.vDomPadRight -= column.getWidth();
		this.element.style.paddingRight = this.vDomPadRight + "px";

		this.rightCol++;

		this.addColRight();
	}
};

VDomHoz.prototype.addColLeft = function(){
	var column = this.columns[this.leftCol - 1],
	rows;

	if(column && column.modules.vdomHoz.rightPos >= this.vDomScrollPosLeft){
		var rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().prepend(cell.getElement());
			cell.cellRendered();
		});

		this.vDomPadLeft -= column.getWidth();
		this.element.style.paddingLeft = this.vDomPadLeft + "px";

		this.leftCol--;

		this.addColLeft();
	}
};

VDomHoz.prototype.removeColRight = function(column){
	var column = this.columns[this.rightCol],
	rows;

	if(column && column.modules.vdomHoz.leftPos > this.vDomScrollPosRight){
		rows = this.table.rowManager.getVisibleRows();

		column.modules.vdomHoz.visible = false;

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().removeChild(cell.getElement());
		});

		this.vDomPadRight += column.getWidth();
		this.element.style.paddingRight = this.vDomPadRight + "px";

		this.rightCol --;

		this.removeColRight();
	}
};

VDomHoz.prototype.removeColLeft = function(){
	var column = this.columns[this.leftCol],
	rows;

	if(column && column.modules.vdomHoz.rightPos < this.vDomScrollPosLeft){

		rows = this.table.rowManager.getVisibleRows();

		rows.forEach((row) => {
			var cell = row.getCell(column);
			row.getElement().removeChild(cell.getElement());
		});

		this.vDomPadLeft += column.getWidth();
		this.element.style.paddingLeft = this.vDomPadLeft + "px";

		this.leftCol ++;

		this.removeColLeft();
	}
};

VDomHoz.prototype.initializeRow = function(row){
	row.modules.vdomHoz = {
		leftCol:this.leftCol,
		rightCol:this.rightCol,
	};

	for(let i = this.leftCol; i <= this.rightCol; i++){
		let column = this.table.columnManager.getColumnByIndex(i);

		if(column.visible){
			let cell = row.getCell(column);

			row.element.appendChild(cell.getElement());
			cell.cellRendered();
		}
	}
};

VDomHoz.prototype.reinitializeRow = function(row, force){
	if(force || !row.modules.vdomHoz || row.modules.vdomHoz.leftCol !== this.leftCol || row.modules.vdomHoz.rightCol !== this.rightCol){
		while(row.element.firstChild) row.element.removeChild(row.element.firstChild);

		this.initializeRow(row);
	}
};<|endoftext|>


<commit_before>// Copyright (c) 2009, Darrin Thompson

// Tiny javascript quickcheck port.
// See Tiny demo below.

var allProps = [];

function declare(name, gens, body) {
    var theProp = new Prop(name, gens, body);
    allProps.push(theProp);
    return theProp;
}

function Prop(name, gens, body) {
    this.name = name;
    this.gens = gens;
    this.body = body;
}

Prop.prototype.generateArgs = function(size) {
    var i;
    var args = [];
    for (i = 0; i < this.gens.length; i += 1) {
	var gen = this.gens[i];
	args.push(gen(size));
    }
    return args;
};

function Case(args) {
    this.classes = [];
    this.args = args;
}

Case.prototype.assert = function(bool) {
    if(!bool) {
	throw("AssertFailed");
    }
};

Case.prototype.guard = function(bool) {
    if (!bool) {
        throw("InvalidCase");
    }
};

Case.prototype.classify = function(tag) {};

Case.prototype.noteArg = function(arg) {
    this.args.push(arg);
};

function Config(pass, invalid) {
    this.maxPass = pass;
    this.maxInvalid = invalid;
}

Config.prototype.needsWork = function(count) {
    return count.invalid < this.maxInvalid &&
    count.pass < this.maxPass;
};

function Counts(pass, invalid, classes) {
    this.pass = pass;
    this.invalid = invalid;
    this.classes = classes;
}

Counts.prototype.incInvalid = function() { this.invalid += 1; };
Counts.prototype.incPass = function() { this.pass += 1; };
Counts.prototype.newResult = function(prop) {
    if(this.pass > 0) {
	return new Pass(prop, this);
    } else {
	return new Invalid(prop, this);
    }
};

function Invalid(prop, counts) {
    this.status = "invalid";
    this.prop = prop;
    this.counts = counts;
    this.name = prop.name;
}

function Pass(prop, counts) {
    this.status = "pass";
    this.prop = prop;
    this.counts = counts;
    this.name = prop.name;
}

function Fail(prop, counts, failedCase) {
    this.status = "fail";
    this.prop = prop;
    this.counts = counts;
    this.failedCase = failedCase;
    this.name = prop.name;
}

function runProp(config, prop) {
    var counts = new Counts(0, 0, {});
    var size = 0;
    while (config.needsWork(counts)) {
	var args = prop.generateArgs(size);
	var testCase = new Case(args);
	try {
	    prop.body.apply(prop, [testCase].concat(args));
            counts.incPass();
	}
	catch (e if e == "AssertFailed") {
	    return new Fail(prop, counts, args);
	}
	catch (e if e == "InvalidCase") {
	    counts.incInvalid();
	}
	size += 1;
    }
    return counts.newResult(prop);
}

function runAllProps(config, listener) {
    var i = 0;
    // Use set timeout so listeners can draw in response to events.
    var once = function() {
        if (i >= allProps.length) {
            listener.done();
            return;
        }
	var currentProp = allProps[i];
	var result = runProp(config, currentProp);
        listener.noteResult(result);
        i += 1;
        setTimeout(once, 0);
    };
    once();
}

// A listener which works with Firebug's console.
function FBCListener() {
}

FBCListener.prototype.noteResult = function(result) {
    var status_string = result.status + ": " + result.name;
    if (result.status == "pass") {
        console.log(status_string);
        console.log(result.counts);
    } else {
        console.warn(status_string);
        console.log(result);
    }
    if (result.status == "fail") {
        console.log("Failed case:");
        console.log(result.failedCase);
    }
};

FBCListener.prototype.done = function(result) {
    console.log('done.');
};

// some starter generators and support utilities.

function randWhole(top) {
    return Math.floor(Math.random() * top);
}

function randInt(top) {
    return randWhole(2 * top) - top;
}

function randRange(a, b) {
    return randWhole(b - a) + a;
}

function justSize() {
    return function(size) {
        return size;
    };
}

function arbWholeNum() {
    return function(size) {
	return randWhole(size);
    };
}

function arbInt() {
    return function(size) {
        return randInt(size);
    };
}

function arbRange(a, b) {
    var min = Math.min(a, b);
    var max = Math.max(a, b);
    return function(size) {
        return Math.floor(Math.random() * (max - min)) - min;
    };
}

function arbList(innerGen) {
    return function(size) {
        var listSize = randWhole(size);
	var list = [];
	var i;
	for (i = 0; i < listSize; i += 1) {
	    list.push(innerGen(size));
	}
	return list;
    };
}

<commit_msg>Add a reset method to forget about known properties.<commit_after>// Copyright (c) 2009, Darrin Thompson

// Tiny javascript quickcheck port.
// See Tiny demo below.

var allProps = [];

function declare(name, gens, body) {
    var theProp = new Prop(name, gens, body);
    allProps.push(theProp);
    return theProp;
}

function resetProps() {
    allProps = [];
}

function Prop(name, gens, body) {
    this.name = name;
    this.gens = gens;
    this.body = body;
}

Prop.prototype.generateArgs = function(size) {
    var i;
    var args = [];
    for (i = 0; i < this.gens.length; i += 1) {
	var gen = this.gens[i];
	args.push(gen(size));
    }
    return args;
};

function Case(args) {
    this.classes = [];
    this.args = args;
}

Case.prototype.assert = function(bool) {
    if(!bool) {
	throw("AssertFailed");
    }
};

Case.prototype.guard = function(bool) {
    if (!bool) {
        throw("InvalidCase");
    }
};

Case.prototype.classify = function(tag) {};

Case.prototype.noteArg = function(arg) {
    this.args.push(arg);
};

function Config(pass, invalid) {
    this.maxPass = pass;
    this.maxInvalid = invalid;
}

Config.prototype.needsWork = function(count) {
    return count.invalid < this.maxInvalid &&
    count.pass < this.maxPass;
};

function Counts(pass, invalid, classes) {
    this.pass = pass;
    this.invalid = invalid;
    this.classes = classes;
}

Counts.prototype.incInvalid = function() { this.invalid += 1; };
Counts.prototype.incPass = function() { this.pass += 1; };
Counts.prototype.newResult = function(prop) {
    if(this.pass > 0) {
	return new Pass(prop, this);
    } else {
	return new Invalid(prop, this);
    }
};

function Invalid(prop, counts) {
    this.status = "invalid";
    this.prop = prop;
    this.counts = counts;
    this.name = prop.name;
}

function Pass(prop, counts) {
    this.status = "pass";
    this.prop = prop;
    this.counts = counts;
    this.name = prop.name;
}

function Fail(prop, counts, failedCase) {
    this.status = "fail";
    this.prop = prop;
    this.counts = counts;
    this.failedCase = failedCase;
    this.name = prop.name;
}

function runProp(config, prop) {
    var counts = new Counts(0, 0, {});
    var size = 0;
    while (config.needsWork(counts)) {
	var args = prop.generateArgs(size);
	var testCase = new Case(args);
	try {
	    prop.body.apply(prop, [testCase].concat(args));
            counts.incPass();
	}
	catch (e if e == "AssertFailed") {
	    return new Fail(prop, counts, args);
	}
	catch (e if e == "InvalidCase") {
	    counts.incInvalid();
	}
	size += 1;
    }
    return counts.newResult(prop);
}

function runAllProps(config, listener) {
    var i = 0;
    // Use set timeout so listeners can draw in response to events.
    var once = function() {
        if (i >= allProps.length) {
            listener.done();
            return;
        }
	var currentProp = allProps[i];
	var result = runProp(config, currentProp);
        listener.noteResult(result);
        i += 1;
        setTimeout(once, 0);
    };
    once();
}

// A listener which works with Firebug's console.
function FBCListener() {
}

FBCListener.prototype.noteResult = function(result) {
    var status_string = result.status + ": " + result.name;
    if (result.status == "pass") {
        console.log(status_string);
        console.log(result.counts);
    } else {
        console.warn(status_string);
        console.log(result);
    }
    if (result.status == "fail") {
        console.log("Failed case:");
        console.log(result.failedCase);
    }
};

FBCListener.prototype.done = function(result) {
    console.log('done.');
};

// some starter generators and support utilities.

function randWhole(top) {
    return Math.floor(Math.random() * top);
}

function randInt(top) {
    return randWhole(2 * top) - top;
}

function randRange(a, b) {
    return randWhole(b - a) + a;
}

function justSize() {
    return function(size) {
        return size;
    };
}

function arbWholeNum() {
    return function(size) {
	return randWhole(size);
    };
}

function arbInt() {
    return function(size) {
        return randInt(size);
    };
}

function arbRange(a, b) {
    var min = Math.min(a, b);
    var max = Math.max(a, b);
    return function(size) {
        return Math.floor(Math.random() * (max - min)) - min;
    };
}

function arbList(innerGen) {
    return function(size) {
        var listSize = randWhole(size);
	var list = [];
	var i;
	for (i = 0; i < listSize; i += 1) {
	    list.push(innerGen(size));
	}
	return list;
    };
}

<|endoftext|>