<commit_before>const React      = require('react');
const classNames = require('classnames');

const Button   = require('./Button');
const Icon     = require('./Icon');
const Backdrop = require('./Backdrop');

/**
 * Dropdown (or up). Automatically bound to child Button.
 * See ButtonDropdown implementation to wrap something else than a button.
 *
 *  <Dropdown>
 *
 *      <Button ... />
 *
 *      <Dropdown.Item header>Category 1</Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *
 *      <Dropdown.Item divider />
 *      <Dropdown.Item header>Category 2</Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *
 *  </Dropdown>
 */

const ButtonDropdown = React.createClass({
    propTypes: {
        className:  React.PropTypes.string,
        children: React.PropTypes.node,
        up:    React.PropTypes.bool,
        width: React.PropTypes.string
    },

    getInitialState() {
        return {
            open: false
        };
    },

    /**
     * Toggle the dopdown
     * @param  {Event} e?
     */
    toggle(e) {
        if (e) {
            e.stopPropagation();
        }

        this.setState({
            open: !this.state.open
        });
    },

    /**
     * Close the dropdown
     */
    close() {
        this.setState({
            open: false
        });
    },

    render() {
        const that = this;
        let inner = [];
        let items = [];

        let { className, children, up, width, ...otherProps } = this.props;
        const { open } = this.state;

        className = classNames('dropdown', className, {
            'dropup': up
        });

        inner = React.Children.map(children, function(child) {
            // If the Button is connected through Redux.connect, it is
            // renamed to "Connect(Button...)"
            if (child && child.type && child.type.displayName.indexOf('Button') !== -1) {
                if (!child.props.onClick && !child.props.href) {
                    return React.cloneElement(child, {
                        onNativeClick: that.toggle,
                        dropdownToggle: true
                    });
                }
                return child;
            }

            return null;
        });

        items = React.Children.map(children, function(child) {
            if (child && child.type && child.type.displayName == 'DropdownItem') {
                return React.cloneElement(child, {
                    onClick() {
                        if (child.props.onClick) {
                            child.props.onClick();
                        }
                        that.close();
                    }
                });
            }
            return null;
        });

        const content = (
            <Button.Group {...otherProps} className={className}>
                {inner}
            </Button.Group>
        );

        // Wrap in a backdrop when open
        if (open) {
            return (
                <Backdrop wrapper={content} onClose={this.close}>
                    {open ? <DropdownMenu width={width} >{items}</DropdownMenu> : null}
                </Backdrop>
            );
        } else {
            return content;
        }
    }
});

const DropdownItem = React.createClass({
    propTypes: {
        children:  React.PropTypes.node,
        onClick:   React.PropTypes.func,
        href:      React.PropTypes.string,
        disabled:  React.PropTypes.bool,
        divider:   React.PropTypes.bool,
        header:    React.PropTypes.bool,
        checked:   React.PropTypes.bool
    },

    onClick(e) {
        if (!this.props.href) {
            e.preventDefault();
            e.stopPropagation();

            if (this.props.onClick) this.props.onClick();
        }
    },

    isInner(child) {
        return (!child || !child.type || child.type.displayName !== 'DropdownMenu');
    },

    render() {
        const { divider, header, checked } = this.props;

        if (divider) {
            return

;
        }
        if (header) {
            return
{this.props.children}
;
        }

        let inner = [], outer = [];

        inner = React.Children.map(this.props.children, function(child) {
            if (this.isInner(child)) return child;
            return null;
        }, this);

        outer = React.Children.map(this.props.children, function(child) {
            if (!this.isInner(child)) return child;
            return null;
        }, this);

        return

                {checked ?
<Icon id="check" />
 : ''}
                {inner}

            {outer}

;
    }
});

const DropdownMenu = React.createClass({
    propTypes: {
        className: React.PropTypes.string,
        children:  React.PropTypes.node,
        open:      React.PropTypes.bool,
        width:     React.PropTypes.string
    },

    getDefaultProps() {
        return {
            open:  true,
            width: null
        };
    },

    render() {
        const { width } = this.props;
        const className = classNames('dropdown-menu', width ? 'dropdown-' + width : '',
            {
                open: this.props.open
            }
        );

        return

            {this.props.children}

;
    }
});

const ItemHeader = React.createClass({
    propTypes: {
        children: React.PropTypes.node
    },

    render() {
        return

            {this.props.children}

;
    }
});

const ItemDesc = React.createClass({
    propTypes: {
        children: React.PropTypes.node
    },

    render() {
        return

            {this.props.children}

;
    }
});

module.exports             = ButtonDropdown;
module.exports.Item        = DropdownItem;
module.exports.Item.Header = ItemHeader;
module.exports.Item.Desc   = ItemDesc;
module.exports.Menu        = DropdownMenu;
<commit_msg>Fix missing condition on Dropdown component<commit_after>const React      = require('react');
const classNames = require('classnames');

const Button   = require('./Button');
const Icon     = require('./Icon');
const Backdrop = require('./Backdrop');

/**
 * Dropdown (or up). Automatically bound to child Button.
 * See ButtonDropdown implementation to wrap something else than a button.
 *
 *  <Dropdown>
 *
 *      <Button ... />
 *
 *      <Dropdown.Item header>Category 1</Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *
 *      <Dropdown.Item divider />
 *      <Dropdown.Item header>Category 2</Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *      <Dropdown.Item href={...}> ... </Dropdown.Item>
 *
 *  </Dropdown>
 */

const ButtonDropdown = React.createClass({
    propTypes: {
        className:  React.PropTypes.string,
        children: React.PropTypes.node,
        up:    React.PropTypes.bool,
        width: React.PropTypes.string
    },

    getInitialState() {
        return {
            open: false
        };
    },

    /**
     * Toggle the dopdown
     * @param  {Event} e?
     */
    toggle(e) {
        if (e) {
            e.stopPropagation();
        }

        this.setState({
            open: !this.state.open
        });
    },

    /**
     * Close the dropdown
     */
    close() {
        this.setState({
            open: false
        });
    },

    render() {
        const that = this;
        let inner = [];
        let items = [];

        let { className, children, up, width, ...otherProps } = this.props;
        const { open } = this.state;

        className = classNames('dropdown', className, {
            'dropup': up
        });

        inner = React.Children.map(children, function(child) {
            // If the Button is connected through Redux.connect, it is
            // renamed to "Connect(Button...)"
            if (
                child &&
                child.type &&
                child.type.displayName &&
                child.type.displayName.indexOf('Button') !== -1
            ) {
                if (!child.props.onClick && !child.props.href) {
                    return React.cloneElement(child, {
                        onNativeClick: that.toggle,
                        dropdownToggle: true
                    });
                }
                return child;
            }

            return null;
        });

        items = React.Children.map(children, function(child) {
            if (child && child.type && child.type.displayName == 'DropdownItem') {
                return React.cloneElement(child, {
                    onClick() {
                        if (child.props.onClick) {
                            child.props.onClick();
                        }
                        that.close();
                    }
                });
            }
            return null;
        });

        const content = (
            <Button.Group {...otherProps} className={className}>
                {inner}
            </Button.Group>
        );

        // Wrap in a backdrop when open
        if (open) {
            return (
                <Backdrop wrapper={content} onClose={this.close}>
                    {open ? <DropdownMenu width={width} >{items}</DropdownMenu> : null}
                </Backdrop>
            );
        } else {
            return content;
        }
    }
});

const DropdownItem = React.createClass({
    propTypes: {
        children:  React.PropTypes.node,
        onClick:   React.PropTypes.func,
        href:      React.PropTypes.string,
        disabled:  React.PropTypes.bool,
        divider:   React.PropTypes.bool,
        header:    React.PropTypes.bool,
        checked:   React.PropTypes.bool
    },

    onClick(e) {
        if (!this.props.href) {
            e.preventDefault();
            e.stopPropagation();

            if (this.props.onClick) this.props.onClick();
        }
    },

    isInner(child) {
        return (!child || !child.type || child.type.displayName !== 'DropdownMenu');
    },

    render() {
        const { divider, header, checked } = this.props;

        if (divider) {
            return

;
        }
        if (header) {
            return
{this.props.children}
;
        }

        let inner = [], outer = [];

        inner = React.Children.map(this.props.children, function(child) {
            if (this.isInner(child)) return child;
            return null;
        }, this);

        outer = React.Children.map(this.props.children, function(child) {
            if (!this.isInner(child)) return child;
            return null;
        }, this);

        return

                {checked ?
<Icon id="check" />
 : ''}
                {inner}

            {outer}

;
    }
});

const DropdownMenu = React.createClass({
    propTypes: {
        className: React.PropTypes.string,
        children:  React.PropTypes.node,
        open:      React.PropTypes.bool,
        width:     React.PropTypes.string
    },

    getDefaultProps() {
        return {
            open:  true,
            width: null
        };
    },

    render() {
        const { width } = this.props;
        const className = classNames('dropdown-menu', width ? 'dropdown-' + width : '',
            {
                open: this.props.open
            }
        );

        return

            {this.props.children}

;
    }
});

const ItemHeader = React.createClass({
    propTypes: {
        children: React.PropTypes.node
    },

    render() {
        return

            {this.props.children}

;
    }
});

const ItemDesc = React.createClass({
    propTypes: {
        children: React.PropTypes.node
    },

    render() {
        return

            {this.props.children}

;
    }
});

module.exports             = ButtonDropdown;
module.exports.Item        = DropdownItem;
module.exports.Item.Header = ItemHeader;
module.exports.Item.Desc   = ItemDesc;
module.exports.Menu        = DropdownMenu;
<|endoftext|>


<commit_before>var config = require('./config.json')

var fs = require('fs')

function Log () {}

Log.prototype.print = function (text) {
  setTimeout(function(){
    console.log(text)
    fs.appendFile(config.log.path + 'log-' + (new Date()).getDate() + '-' + (new Date()).getMonth(), '[' + getDate() + '] ' + text + '\n', 'utf8', function (err) {
      if (err) throw err
    })
  })
}

Log.prototype.echo = function (text) {
  console.log(text)
}

function getDate () {
  var date = new Date()
  return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + (date.getHours() + 1) + ':' + (date.getMinutes() + 1) + ':' + (date.getSeconds() + 1)
}

module.exports = new Log()
<commit_msg>fix date on logs<commit_after>var config = require('./config.json')

var fs = require('fs')

function Log () {}

Log.prototype.print = function (text) {
  setTimeout(function () {
    console.log(text)
    fs.appendFile(config.log.path + 'log-' + (new Date()).getDate() + '-' + ((new Date()).getMonth() + 1), '[' + getDate() + '] ' + text + '\n', 'utf8', function (err) {
      if (err) throw err
    })
  })
}

Log.prototype.echo = function (text) {
  console.log(text)
}

function getDate () {
  var date = new Date()
  return date.getDate() + '/' + (date.getMonth() + 1) + ' ' + (date.getHours() + 1) + ':' + (date.getMinutes() + 1) + ':' + (date.getSeconds() + 1)
}

module.exports = new Log()
<|endoftext|>


<commit_before>import {range} from "d3-arrays";
import {default as linear, rebind} from "./linear";
import nice from "./nice";

function newLog(linear, base, domain) {

  function log(x) {
    return (domain[0] < 0 ? -Math.log(x > 0 ? 0 : -x) : Math.log(x < 0 ? 0 : x)) / Math.log(base);
  }

  function pow(x) {
    return domain[0] < 0 ? -Math.pow(base, -x) : Math.pow(base, x);
  }

  function scale(x) {
    return linear(log(x));
  }

  scale.invert = function(x) {
    return pow(linear.invert(x));
  };

  scale.base = function(x) {
    if (!arguments.length) return base;
    base = +x;
    return scale.domain(domain);
  };

  scale.domain = function(x) {
    if (!arguments.length) return domain.slice();
    domain = x.map(Number);
    linear.domain(domain.map(log));
    return scale;
  };

  scale.nice = function() {
    var x = nice(linear.domain(), 1);
    linear.domain(x);
    domain = x.map(pow);
    return scale;
  };

  scale.ticks = function() {
    var u = domain[0],
        v = domain[domain.length - 1];
    if (v < u) i = u, u = v, v = i;
    var i = Math.floor(log(u)),
        j = Math.ceil(log(v)),
        k,
        t,
        n = base % 1 ? 2 : base,
        ticks = [];

    if (isFinite(j - i)) {
      if (u > 0) {
        for (k = 1, --j; k < n; ++k) if ((t = pow(i) * k) < u) continue; else ticks.push(t);
        while (++i < j) for (k = 1; k < n; ++k) ticks.push(pow(i) * k);
        for (k = 1; k < n; ++k) if ((t = pow(i) * k) > v) break; else ticks.push(t);
      } else {
        for (k = n - 1, ++i; k >= 1; --k) if ((t = pow(i) * k) < u) continue; else ticks.push(t);
        while (++i < j) for (k = n - 1; k >= 1; --k) ticks.push(pow(i) * k);
        for (k = n - 1; k >= 1; --k) if ((t = pow(i) * k) > v) break; else ticks.push(t);
      }
    }

    return ticks;
  };

  scale.tickFormat = function() {
    throw new Error("not yet implemented");
  };

  scale.copy = function() {
    return newLog(linear.copy(), base, domain);
  };

  return rebind(scale, linear);
}

export default function() {
  return newLog(linear(), 10, [1, 10]);
};
<commit_msg>Formatting tweak.<commit_after>import {range} from "d3-arrays";
import {default as linear, rebind} from "./linear";
import nice from "./nice";

function newLog(linear, base, domain) {

  function log(x) {
    return (domain[0] < 0 ? -Math.log(x > 0 ? 0 : -x) : Math.log(x < 0 ? 0 : x)) / Math.log(base);
  }

  function pow(x) {
    return domain[0] < 0 ? -Math.pow(base, -x) : Math.pow(base, x);
  }

  function scale(x) {
    return linear(log(x));
  }

  scale.invert = function(x) {
    return pow(linear.invert(x));
  };

  scale.base = function(x) {
    if (!arguments.length) return base;
    base = +x;
    return scale.domain(domain);
  };

  scale.domain = function(x) {
    if (!arguments.length) return domain.slice();
    domain = x.map(Number);
    linear.domain(domain.map(log));
    return scale;
  };

  scale.nice = function() {
    var x = nice(linear.domain(), 1);
    linear.domain(x);
    domain = x.map(pow);
    return scale;
  };

  scale.ticks = function() {
    var u = domain[0],
        v = domain[domain.length - 1];
    if (v < u) i = u, u = v, v = i;
    var i = Math.floor(log(u)),
        j = Math.ceil(log(v)),
        k,
        t,
        n = base % 1 ? 2 : base,
        ticks = [];

    if (isFinite(j - i)) {
      if (u > 0) {
        for (--j, k = 1; k < n; ++k) if ((t = pow(i) * k) < u) continue; else ticks.push(t);
        while (++i < j) for (k = 1; k < n; ++k) ticks.push(pow(i) * k);
        for (k = 1; k < n; ++k) if ((t = pow(i) * k) > v) break; else ticks.push(t);
      } else {
        for (++i, k = n - 1; k >= 1; --k) if ((t = pow(i) * k) < u) continue; else ticks.push(t);
        while (++i < j) for (k = n - 1; k >= 1; --k) ticks.push(pow(i) * k);
        for (k = n - 1; k >= 1; --k) if ((t = pow(i) * k) > v) break; else ticks.push(t);
      }
    }

    return ticks;
  };

  scale.tickFormat = function() {
    throw new Error("not yet implemented");
  };

  scale.copy = function() {
    return newLog(linear.copy(), base, domain);
  };

  return rebind(scale, linear);
}

export default function() {
  return newLog(linear(), 10, [1, 10]);
};
<|endoftext|>


<commit_before>(function (root, factory) {
  var name = 'mag';
  if (typeof define === 'function' && define.amd) {
    define([], function () {
        return (root[name] = factory());
    });
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root[name] = factory();
  }
}(this, function () {

  // var model = {
  //   lens: {
  //     x: 0,
  //     y: 0,
  //     w: 0.5,
  //     h: 0.5
  //   },
  //   focus: {
  //     x: 0,
  //     y: 0
  //   }
  // };

  // var world = {
  //   frame: {
  //     w: 100,
  //     h: 100
  //   },
  // };

  var fillXY = function (r) {
    r = r || {};
    r.x = r.x || 0;
    r.y = r.y || 0;
    return r;
  };

  var fillWH = function (r) {
    r = r || {};
    r.w = r.w || 0;
    r.h = r.h || 0;
    return r;
  };

  var fillModel = function (model) {
    model = model || {};
    model.mode = model.mode || 'lag';
    model.focus = fillXY(model.focus);
    model.lens = fillXY(fillWH(model.lens));
    model.full = fillXY(fillWH(model.full));
    model.boundedLens = fillXY(fillWH(model.boundedLens));
    model.zoom = model.zoom || 1;
    return model;
  };

  var compute = function (model, options) {
    var lens, focus, full, zoom, dw, dh;
    options = options || {
      constrainLens: true
    };
    model = fillModel(model);
    lens = model.lens;
    focus = model.focus;
    full = model.full;
    zoom = model.zoom;

    dw = 1 / zoom;
    dh = 1 / zoom;
    lens.x = focus.x - (dw / 2);
    lens.y = focus.y - (dh / 2);
    lens.w = dw;
    lens.h = dh;

    if (options.constrainLens) {
      lens = constrainLens(lens);
    }

    full.w = zoom;
    full.h = zoom;
    full.x = 0.5 - focus.x * zoom;
    full.y = 0.5 - focus.y * zoom;

    if (options.constrainZoomed) {
      full.x = minMax(full.x, 1 - zoom, 0);
      full.y = minMax(full.y, 1 - zoom, 0);
    }

    model.lens = lens;
    model.focus = focus;
    model.full = full;
    model.zoom = zoom;
  };

  var minMax = function (val, min, max) {
    return val < min ? min : ( val > max ? max : val );
  };

  var minMax1 = function (val, min) {
    return minMax(val, min, 1);
  };

  var constrainLensWH = function (r) {
    return {
      w: minMax1(r.w, 0.1),
      h: minMax1(r.h, 0.1),
      x: r.x,
      y: r.y
    };
  };

  var constrainLensXY = function (r) {
    return {
      x: minMax(r.x, 0),
      y: minMax(r.y, 0),
      w: r.w,
      h: r.h
    };
  };

  var constrainLens = function (r) {
    var c = constrainLensXY(constrainLensWH(r));
    if (((c.w + c.x) > 1)) {
      c.x = Math.max(0, 1 - c.w);
    }
    if (((c.h + c.y) > 1)) {
      c.y = Math.max(0, 1 - c.h);
    }
    return c;
  };

  var project = function (model, frame) {
    model = fillModel(model);
    var lens = model.lens;
    return {
      x: lens.x * frame.w,
      y: lens.y * frame.h,
      w: lens.w * frame.w,
      h: lens.h * frame.h
    };
  };

  var mag = {};

  mag.compute = compute;
  mag.project = project;
  mag.constrainLens = constrainLens;
  mag.constrainLensWH = constrainLensWH;
  mag.constrainLensXY = constrainLensXY;
  mag.minMax = minMax;

  return mag;
}));
<commit_msg>update commented model example<commit_after>(function (root, factory) {
  var name = 'mag';
  if (typeof define === 'function' && define.amd) {
    define([], function () {
        return (root[name] = factory());
    });
  } else if (typeof exports === 'object') {
    module.exports = factory();
  } else {
    root[name] = factory();
  }
}(this, function () {

  // var model = {
  //   zoom: 1,
  //   focus: {
  //     x: 0,
  //     y: 0
  //   },
  //   lens: {
  //     x: 0,
  //     y: 0,
  //     w: 0.5,
  //     h: 0.5
  //   },
  //   full: {
  //     x: 0,
  //     y: 0,
  //     w: 0.5,
  //     h: 0.5
  //   }
  // };

  var fillXY = function (r) {
    r = r || {};
    r.x = r.x || 0;
    r.y = r.y || 0;
    return r;
  };

  var fillWH = function (r) {
    r = r || {};
    r.w = r.w || 0;
    r.h = r.h || 0;
    return r;
  };

  var fillModel = function (model) {
    model = model || {};
    model.mode = model.mode || 'lag';
    model.focus = fillXY(model.focus);
    model.lens = fillXY(fillWH(model.lens));
    model.full = fillXY(fillWH(model.full));
    model.boundedLens = fillXY(fillWH(model.boundedLens));
    model.zoom = model.zoom || 1;
    return model;
  };

  var compute = function (model, options) {
    var lens, focus, full, zoom, dw, dh;
    options = options || {
      constrainLens: true
    };
    model = fillModel(model);
    lens = model.lens;
    focus = model.focus;
    full = model.full;
    zoom = model.zoom;

    dw = 1 / zoom;
    dh = 1 / zoom;
    lens.x = focus.x - (dw / 2);
    lens.y = focus.y - (dh / 2);
    lens.w = dw;
    lens.h = dh;

    if (options.constrainLens) {
      lens = constrainLens(lens);
    }

    full.w = zoom;
    full.h = zoom;
    full.x = 0.5 - focus.x * zoom;
    full.y = 0.5 - focus.y * zoom;

    if (options.constrainZoomed) {
      full.x = minMax(full.x, 1 - zoom, 0);
      full.y = minMax(full.y, 1 - zoom, 0);
    }

    model.lens = lens;
    model.focus = focus;
    model.full = full;
    model.zoom = zoom;
  };

  var minMax = function (val, min, max) {
    return val < min ? min : ( val > max ? max : val );
  };

  var minMax1 = function (val, min) {
    return minMax(val, min, 1);
  };

  var constrainLensWH = function (r) {
    return {
      w: minMax1(r.w, 0.1),
      h: minMax1(r.h, 0.1),
      x: r.x,
      y: r.y
    };
  };

  var constrainLensXY = function (r) {
    return {
      x: minMax(r.x, 0),
      y: minMax(r.y, 0),
      w: r.w,
      h: r.h
    };
  };

  var constrainLens = function (r) {
    var c = constrainLensXY(constrainLensWH(r));
    if (((c.w + c.x) > 1)) {
      c.x = Math.max(0, 1 - c.w);
    }
    if (((c.h + c.y) > 1)) {
      c.y = Math.max(0, 1 - c.h);
    }
    return c;
  };

  var project = function (model, frame) {
    model = fillModel(model);
    var lens = model.lens;
    return {
      x: lens.x * frame.w,
      y: lens.y * frame.h,
      w: lens.w * frame.w,
      h: lens.h * frame.h
    };
  };

  var mag = {};

  mag.compute = compute;
  mag.project = project;
  mag.constrainLens = constrainLens;
  mag.constrainLensWH = constrainLensWH;
  mag.constrainLensXY = constrainLensXY;
  mag.minMax = minMax;

  return mag;
}));
<|endoftext|>


<commit_before>var glob = require("glob"),
    path = require("path-posix"),
    merge = require("merge-stream"),
    gulpif = require("gulp-if"),
    gulp = require("gulp"),
    newer = require("gulp-newer"),
	plumber = require("gulp-plumber"),
    sourcemaps = require("gulp-sourcemaps"),
    less = require("gulp-less"),
	autoprefixer = require("gulp-autoprefixer"),
	minify = require("gulp-minify-css"),
    typescript = require("gulp-typescript"),
	uglify = require("gulp-uglify"),
	rename = require("gulp-rename"),
    concat = require("gulp-concat"),
	header = require("gulp-header"),
    notify = require("gulp-notify")

/*
** GULP TASKS
---------------------------------------
   Checks Themes, Modules, and Core directories for an Assets.json file.
   Assets.json defines what Less, CSS, TypeScript, JS files should be processed by Gulp.

   When defining your own Assets.json file, it should be saved in the root of module or theme project

   Assets.json example:
   Saved to /Modules/My.Custom.Module/Assets.json
   [
      {
        "inputs": [ "Less/master.less" ], //Specifies which files to process during the Build task
        "output": "Styles/@.css", //When @ is specified, each file specified in "inputs" will be converted to [filename].css
        "watch": ["Less/*.less"], //specifies which files to watch, use this when you have a master Less file that imports other Less files
        "generateSourceMaps": true //Will include source maps in unminified version, defaults to 'true'
      }
    ]
    "inputs" and "output" are required.  All other properties are optional.
*/

// Incremental build (each asset group is built only if one or more inputs are newer than the output).
gulp.task("build", function () {
    var assetGroupTasks = getAssetGroups().map(function (assetGroup) {
        var doRebuild = false;
        return createAssetGroupTask(assetGroup, doRebuild);
    });
    return merge(assetGroupTasks);
});

// Full rebuild (all assets groups are built regardless of timestamps).
gulp.task("rebuild", function () {
    var assetGroupTasks = getAssetGroups().map(function (assetGroup) {
        var doRebuild = true;
        return createAssetGroupTask(assetGroup, doRebuild);
    });
    return merge(assetGroupTasks);
});

// Continuous watch (each asset group is built whenever one of its inputs changes).
gulp.task("watch", function () {
    getAssetGroups().forEach(function (assetGroup) {
        gulp.watch(assetGroup.watchPaths, function (event) {
            console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding output '" + assetGroup.outputPath + "'.");
            var doRebuild = true;
            var task = createAssetGroupTask(assetGroup, doRebuild);
        });
    });
});

/*
** ASSET GROUPS
*/

function getAssetGroups() {
    var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json");
    var assetGroups = [];
    assetManifestPaths.forEach(function (assetManifestPath) {
        var assetManifest = require("./" + assetManifestPath);
        assetManifest.forEach(function (assetGroup) {
            resolveAssetGroupPaths(assetGroup, assetManifestPath);
            assetGroups.push(assetGroup);
        });
    });
    return assetGroups;
}

function resolveAssetGroupPaths(assetGroup, assetManifestPath) {
    assetGroup.basePath = path.dirname(assetManifestPath);
    assetGroup.inputPaths = assetGroup.inputs.map(function (inputPath) {
        return path.join(assetGroup.basePath, inputPath);
    });

    assetGroup.watchPaths = !!assetGroup.watch ?
        assetGroup.watch.map(function (watchPath) {
            return path.join(assetGroup.basePath, watchPath);
        }).concat(assetGroup.inputPaths) : assetGroup.inputPaths;

    assetGroup.outputPath = path.join(assetGroup.basePath, assetGroup.output);
    assetGroup.outputDir = path.dirname(assetGroup.outputPath);
    assetGroup.outputFileName = path.basename(assetGroup.output);
}

function createAssetGroupTask(assetGroup, doRebuild) {
    var outputExt = path.extname(assetGroup.output).toLowerCase();
    switch (outputExt) {
        case ".css":
            return buildCssPipeline(assetGroup, doRebuild);
        case ".js":
            return buildJsPipeline(assetGroup, doRebuild);
    }
}

/*
** PROCESSING PIPELINES
*/

function buildCssPipeline(assetGroup, doRebuild) {
    assetGroup.inputPaths.forEach(function (inputPath) {
        var ext = path.extname(inputPath).toLowerCase();
        if (ext !== ".less" && ext !== ".css")
            throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
    });
    var doConcat = path.basename(assetGroup.outputFileName, ".css") !== "@";
    if (!doRebuild) {
        console.log("CSS will only rebuild if less files specified in 'inputs' are newer.");
    }
    else {
        console.log("Force Rebuild is enabled, rebuilding all input files.");
    }
    var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
    return gulp.src(assetGroup.inputPaths)
        .pipe(gulpif(!doRebuild,
            gulpif(doConcat,
                newer(assetGroup.outputPath),
                newer({
                    dest: assetGroup.outputDir,
                    ext: ".css"
                }))))
        .pipe(plumber())
        .pipe(gulpif(generateSourceMaps, sourcemaps.init()))
        .pipe(gulpif("*.less", less()))
        .pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
        .pipe(autoprefixer({ browsers: ["last 2 versions"] }))
        // TODO: Start using below whenever gulp-header supports sourcemaps.
        //.pipe(header(
        //    "/*\n" +
        //    "** NOTE: This file is generated by Gulp compilation and should not be edited directly!\n" +
        //    "** Any changes made directly to this file will be overwritten next time the Gulp compilation runs.\n" +
        //    "** For more information, see the Readme.txt file in the Gulp solution folder.\n" +
        //    "*/\n\n"))
        .pipe(gulpif(generateSourceMaps, sourcemaps.write()))
        .pipe(gulp.dest(assetGroup.outputDir))
        .pipe(minify())
        .pipe(rename({
            suffix: ".min"
        }))
        .pipe(gulp.dest(assetGroup.outputDir))
        .pipe(gulpif(doRebuild, notify("Rebuild complete"), notify("Build process complete")));
}

function buildJsPipeline(assetGroup, doRebuild) {
    assetGroup.inputPaths.forEach(function (inputPath) {
        var ext = path.extname(inputPath).toLowerCase();
        if (ext !== ".ts" && ext !== ".js")
            throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
    });
    var doConcat = path.basename(assetGroup.outputFileName, ".js") !== "@";
    var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
    return gulp.src(assetGroup.inputPaths)
        .pipe(gulpif(!doRebuild,
            gulpif(doConcat,
                newer(assetGroup.outputPath),
                newer({
                    dest: assetGroup.outputDir,
                    ext: ".js"
                }))))
        .pipe(plumber())
        .pipe(gulpif(generateSourceMaps, sourcemaps.init()))
        .pipe(gulpif("*.ts", typescript({
            declaration: false,
            //noImplicitAny: true,
            noEmitOnError: true,
            sortOutput: true,
        }).js))
		.pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
        // TODO: Start using below whenever gulp-header supports sourcemaps.
        //.pipe(header(
        //    "/*\n" +
        //    "** NOTE: This file is generated by Gulp compilation and should not be edited directly!\n" +
        //    "** Any changes made directly to this file will be overwritten next time the Gulp compilation runs.\n" +
        //    "** For more information, see the Readme.txt file in the Gulp solution folder.\n" +
        //    "*/\n\n"))
        .pipe(gulpif(generateSourceMaps, sourcemaps.write()))
        .pipe(gulp.dest(assetGroup.outputDir))
		.pipe(uglify())
		.pipe(rename({
		    suffix: ".min"
		}))
		.pipe(gulp.dest(assetGroup.outputDir));
}
<commit_msg>Updates to gulpfile.js<commit_after>var glob = require("glob"),
    path = require("path-posix"),
    merge = require("merge-stream"),
    gulpif = require("gulp-if"),
    gulp = require("gulp"),
    newer = require("gulp-newer"),
    plumber = require("gulp-plumber"),
    sourcemaps = require("gulp-sourcemaps"),
    less = require("gulp-less"),
    autoprefixer = require("gulp-autoprefixer"),
    minify = require("gulp-minify-css"),
    typescript = require("gulp-typescript"),
    uglify = require("gulp-uglify"),
    rename = require("gulp-rename"),
    concat = require("gulp-concat"),
    header = require("gulp-header")

// Incremental build (each asset group is built only if one or more inputs are newer than the output).
gulp.task("build", function () {
    var assetGroupTasks = getAssetGroups().map(function (assetGroup) {
        var doRebuild = false;
        return createAssetGroupTask(assetGroup, doRebuild);
    });
    return merge(assetGroupTasks);
});

// Full rebuild (all assets groups are built regardless of timestamps).
gulp.task("rebuild", function () {
    var assetGroupTasks = getAssetGroups().map(function (assetGroup) {
        var doRebuild = true;
        return createAssetGroupTask(assetGroup, doRebuild);
    });
    return merge(assetGroupTasks);
});

// Continuous watch (each asset group is built whenever one of its inputs changes).
gulp.task("watch", function () {
    getAssetGroups().forEach(function (assetGroup) {
        gulp.watch(assetGroup.watchPaths, function (event) {
            console.log("Asset file '" + event.path + "' was " + event.type + ", rebuilding output '" + assetGroup.outputPath + "'.");
            var doRebuild = true;
            var task = createAssetGroupTask(assetGroup, doRebuild);
        });
    });
});

/*
** ASSET GROUPS
*/

function getAssetGroups() {
    var assetManifestPaths = glob.sync("Orchard.Web/{Core,Modules,Themes}/*/Assets.json");
    var assetGroups = [];
    assetManifestPaths.forEach(function (assetManifestPath) {
        var assetManifest = require("./" + assetManifestPath);
        assetManifest.forEach(function (assetGroup) {
            resolveAssetGroupPaths(assetGroup, assetManifestPath);
            assetGroups.push(assetGroup);
        });
    });
    return assetGroups;
}

function resolveAssetGroupPaths(assetGroup, assetManifestPath) {
    assetGroup.basePath = path.dirname(assetManifestPath);
    assetGroup.inputPaths = assetGroup.inputs.map(function (inputPath) {
        return path.join(assetGroup.basePath, inputPath);
    });

    assetGroup.watchPaths = !!assetGroup.watch ?
        assetGroup.watch.map(function (watchPath) {
            return path.join(assetGroup.basePath, watchPath);
        }).concat(assetGroup.inputPaths) : assetGroup.inputPaths;

    assetGroup.outputPath = path.join(assetGroup.basePath, assetGroup.output);
    assetGroup.outputDir = path.dirname(assetGroup.outputPath);
    assetGroup.outputFileName = path.basename(assetGroup.output);
}

function createAssetGroupTask(assetGroup, doRebuild) {
    var outputExt = path.extname(assetGroup.output).toLowerCase();
    switch (outputExt) {
        case ".css":
            return buildCssPipeline(assetGroup, doRebuild);
        case ".js":
            return buildJsPipeline(assetGroup, doRebuild);
    }
}

/*
** PROCESSING PIPELINES
*/

function buildCssPipeline(assetGroup, doRebuild) {
    assetGroup.inputPaths.forEach(function (inputPath) {
        var ext = path.extname(inputPath).toLowerCase();
        if (ext !== ".less" && ext !== ".css")
            throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
    });
    var doConcat = path.basename(assetGroup.outputFileName, ".css") !== "@";
    var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
    return gulp.src(assetGroup.inputPaths)
        .pipe(gulpif(!doRebuild,
            gulpif(doConcat,
                newer(assetGroup.outputPath),
                newer({
                    dest: assetGroup.outputDir,
                    ext: ".css"
                }))))
        .pipe(plumber())
        .pipe(gulpif(generateSourceMaps, sourcemaps.init()))
        .pipe(gulpif("*.less", less()))
        .pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
        .pipe(autoprefixer({ browsers: ["last 2 versions"] }))
        // TODO: Start using below whenever gulp-header supports sourcemaps.
        //.pipe(header(
        //    "/*\n" +
        //    "** NOTE: This file is generated by Gulp compilation and should not be edited directly!\n" +
        //    "** Any changes made directly to this file will be overwritten next time the Gulp compilation runs.\n" +
        //    "** For more information, see the Readme.txt file in the Gulp solution folder.\n" +
        //    "*/\n\n"))
        .pipe(gulpif(generateSourceMaps, sourcemaps.write()))
        .pipe(gulp.dest(assetGroup.outputDir))
        .pipe(minify())
        .pipe(rename({
            suffix: ".min"
        }))
        .pipe(gulp.dest(assetGroup.outputDir));
}

function buildJsPipeline(assetGroup, doRebuild) {
    assetGroup.inputPaths.forEach(function (inputPath) {
        var ext = path.extname(inputPath).toLowerCase();
        if (ext !== ".ts" && ext !== ".js")
            throw "Input file '" + inputPath + "' is not of a valid type for output file '" + assetGroup.outputPath + "'.";
    });
    var doConcat = path.basename(assetGroup.outputFileName, ".js") !== "@";
    var generateSourceMaps = assetGroup.hasOwnProperty("generateSourceMaps") ? assetGroup.generateSourceMaps : true;
    return gulp.src(assetGroup.inputPaths)
        .pipe(gulpif(!doRebuild,
            gulpif(doConcat,
                newer(assetGroup.outputPath),
                newer({
                    dest: assetGroup.outputDir,
                    ext: ".js"
                }))))
        .pipe(plumber())
        .pipe(gulpif(generateSourceMaps, sourcemaps.init()))
        .pipe(gulpif("*.ts", typescript({
            declaration: false,
            //noImplicitAny: true,
            noEmitOnError: true,
            sortOutput: true,
        }).js))
		.pipe(gulpif(doConcat, concat(assetGroup.outputFileName)))
        // TODO: Start using below whenever gulp-header supports sourcemaps.
        //.pipe(header(
        //    "/*\n" +
        //    "** NOTE: This file is generated by Gulp compilation and should not be edited directly!\n" +
        //    "** Any changes made directly to this file will be overwritten next time the Gulp compilation runs.\n" +
        //    "** For more information, see the Readme.txt file in the Gulp solution folder.\n" +
        //    "*/\n\n"))
        .pipe(gulpif(generateSourceMaps, sourcemaps.write()))
        .pipe(gulp.dest(assetGroup.outputDir))
		.pipe(uglify())
		.pipe(rename({
		    suffix: ".min"
		}))
		.pipe(gulp.dest(assetGroup.outputDir));
}
<|endoftext|>


<commit_before>PROTOTYPE._update = function(content, element, reposition) {
	var self = this,
		cache = this.cache;

	// Make sure tooltip is rendered and content is defined. If not return
	if(!this.rendered || !content) { return FALSE; }

	// Use function to parse content
	if($.isFunction(content)) {
		content = content.call(this.elements.target, cache.event, this) || '';
	}

	// Handle deferred content
	if($.isFunction(content.then)) {
		cache.waiting = TRUE;
		return content.then(function(c) {
			cache.waiting = FALSE;
			return self._update(c, element, reposition);
		}, NULL, function(e) {
			return self._update(e, element, reposition);
		});
	}

	// If content is null... return false
	if(content === FALSE || (!content && content !== '')) { return FALSE; }

	// Append new content if its a DOM array and show it if hidden
	if(content.jquery && content.length > 0) {
		element.children().detach().end().append( content.css({ display: 'block' }) );
	}

	// Content is a regular string, insert the new content
	else { element.html(content); }

	// If imagesLoaded is included, ensure images have loaded and return promise
	cache.waiting = TRUE;
	return ( $.fn.imagesLoaded ? element.imagesLoaded() : $.Deferred().resolve($()).promise() )
		.done(function(images) {
			cache.waiting = FALSE;

			// Reposition if rendered
			if(reposition !== FALSE && self.rendered && self.tooltip[0].offsetWidth > 0) {
				self.reposition(cache.event, !images.length);
			}
		})
		.promise();
};

PROTOTYPE._updateContent = function(content, reposition) {
	this._update(content, this.elements.content, reposition);
};

PROTOTYPE._updateTitle = function(content, reposition) {
	if(this._update(content, this.elements.title, reposition) === FALSE) {
		this._removeTitle(FALSE);
	}
};

PROTOTYPE._createTitle = function()
{
	var elements = this.elements,
		id = this._id+'-title';

	// Destroy previous title element, if present
	if(elements.titlebar) { this._removeTitle(); }

	// Create title bar and title elements
	elements.titlebar = $('<div />', {
		'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass('header') : '')
	})
	.append(
		elements.title = $('<div />', {
			'id': id,
			'class': NAMESPACE + '-title',
			'aria-atomic': TRUE
		})
	)
	.insertBefore(elements.content)

	// Button-specific events
	.delegate('.qtip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
		$(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
	})
	.delegate('.qtip-close', 'mouseover mouseout', function(event){
		$(this).toggleClass('ui-state-hover', event.type === 'mouseover');
	});

	// Create button if enabled
	if(this.options.content.button) { this._createButton(); }
};

PROTOTYPE._removeTitle = function(reposition)
{
	var elements = this.elements;

	if(elements.title) {
		elements.titlebar.remove();
		elements.titlebar = elements.title = elements.button = NULL;

		// Reposition if enabled
		if(reposition !== FALSE) { this.reposition(); }
	}
};

<commit_msg>Always reposition after deferred has finished (especially for ajax). Fixes #518 displacement problem with images.<commit_after>PROTOTYPE._update = function(content, element, reposition) {
	var self = this,
		cache = this.cache;

	// Make sure tooltip is rendered and content is defined. If not return
	if(!this.rendered || !content) { return FALSE; }

	// Use function to parse content
	if($.isFunction(content)) {
		content = content.call(this.elements.target, cache.event, this) || '';
	}

	// Handle deferred content
	if($.isFunction(content.then)) {
		cache.waiting = TRUE;
		return content.then(function(c) {
			cache.waiting = FALSE;
			return self._update(c, element);
		}, NULL, function(e) {
			return self._update(e, element);
		});
	}

	// If content is null... return false
	if(content === FALSE || (!content && content !== '')) { return FALSE; }

	// Append new content if its a DOM array and show it if hidden
	if(content.jquery && content.length > 0) {
		element.children().detach().end().append( content.css({ display: 'block' }) );
	}

	// Content is a regular string, insert the new content
	else { element.html(content); }

	// If imagesLoaded is included, ensure images have loaded and return promise
	cache.waiting = TRUE;

	return ( $.fn.imagesLoaded ? element.imagesLoaded() : $.Deferred().resolve($([])) )
		.done(function(images) {
			cache.waiting = FALSE;

			// Reposition if rendered
			if(images.length && self.rendered && self.tooltip[0].offsetWidth > 0) {
				self.reposition(cache.event, !images.length);
			}
		})
		.promise();
};

PROTOTYPE._updateContent = function(content, reposition) {
	this._update(content, this.elements.content, reposition);
};

PROTOTYPE._updateTitle = function(content, reposition) {
	if(this._update(content, this.elements.title, reposition) === FALSE) {
		this._removeTitle(FALSE);
	}
};

PROTOTYPE._createTitle = function()
{
	var elements = this.elements,
		id = this._id+'-title';

	// Destroy previous title element, if present
	if(elements.titlebar) { this._removeTitle(); }

	// Create title bar and title elements
	elements.titlebar = $('<div />', {
		'class': NAMESPACE + '-titlebar ' + (this.options.style.widget ? createWidgetClass('header') : '')
	})
	.append(
		elements.title = $('<div />', {
			'id': id,
			'class': NAMESPACE + '-title',
			'aria-atomic': TRUE
		})
	)
	.insertBefore(elements.content)

	// Button-specific events
	.delegate('.qtip-close', 'mousedown keydown mouseup keyup mouseout', function(event) {
		$(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
	})
	.delegate('.qtip-close', 'mouseover mouseout', function(event){
		$(this).toggleClass('ui-state-hover', event.type === 'mouseover');
	});

	// Create button if enabled
	if(this.options.content.button) { this._createButton(); }
};

PROTOTYPE._removeTitle = function(reposition)
{
	var elements = this.elements;

	if(elements.title) {
		elements.titlebar.remove();
		elements.titlebar = elements.title = elements.button = NULL;

		// Reposition if enabled
		if(reposition !== FALSE) { this.reposition(); }
	}
};

<|endoftext|>


<commit_before>// HACK: using this to obfuscate loading of modules in nodejs
// Instead, we should not use `require()` but use stub modules for bundling
export default function (p) {
  let f = require
  if (f) {
    return f(p)
  }
}
<commit_msg>Only use require in nodejs.<commit_after>import { platform } from 'substance'

// HACK: using this to obfuscate loading of modules in nodejs
// Instead, we should not use `require()` but use stub modules for bundling
export default function (p) {
  let f = require
  if (platform.inNodeJS || platform.inElectron) {
    return f(p)
  }
}
<|endoftext|>


<commit_before>/*jshint browser:true */
/*global devizr: true, test: true, DocumentTouch:true, SVGFEColorMatrixElement:true */
"use strict";
var // Please do not change the first four lines!!!
tests = {

  /*** Device related APIs **************************************************************/

  'fullscreen': function() {
    return test(window, 'fullScreen') ||
      test(document.documentElement, 'requestFullscreen', true);
  },

  'ambientlight': function() {
    return test(window, 'ondevicelight');
  },

  'battery': function() {
    return test(navigator, 'battery', true);
  },

  'geolocation': function() {
    return test(navigator, 'geolocation');
  },

  'pointerlock': function() {
    return test(document.documentElement, 'requestPointerLock', true) &&
      test(document, 'exitPointerLock', true) &&
      test(document, 'pointerLockElement', true);
  },

  'userproximity': function() {
    return test(window, 'onuserproximity');
  },

  'devicemotion': function() {
    return test(window, 'DeviceMotionEvent');
  },

  'deviceorientation': function() {
    return test(window, 'DeviceOrientationEvent');
  },

  'orientationchange': function() {
    return test(screen, 'onmozorientationchange') ||
      test(screen, 'onmsorientationchange');
  },

  'vibrate': function() {
    return test(navigator, 'vibrate', true);
  },

  'gamepads': function() {
    return test(navigator, 'getGamepads');
  },

  'getusermedia': function() {
    return test(navigator, 'getUserMedia', true);
  },

  'touch': function() {
    return test(window, 'ontouchstart') ||
      (test(navigator, 'MaxTouchPoints') && navigator.MaxTouchPoints > 0) ||
      (test(navigator, 'msMaxTouchPoints') && navigator.msMaxTouchPoints > 0) ||
      (test(window, 'DocumentTouch') && document instanceof DocumentTouch);
  },

  'draganddrop': function() {
    return test(document.documentElement, 'draggable') &&
      test(document, 'ondrag') &&
      test(document, 'ondrop');
  },

  /*** Communication related APIs *******************************************************/

  'online': function() {
    return test(navigator, 'onLine');
  },

  'onlineevents': function() {
    return test(window, 'ononline') &&
      test(window, 'onoffline');
  },

  'eventsource': function() {
    return test(window, 'EventSource');
  },

  'applicationcache': function() {
    return test(window, 'applicationCache');
  },

  'rtcpeerconnection': function() {
    return test(window, 'RTCPeerConnection', true);
    //return test(navigator, 'connection');
  },

  'notification': function() {
    return test(window, 'Notification', true);
  },

  'postmessage': function() {
    return test(window, 'postMessage');
  },

  'websocket': function() {
    return test(window, 'WebSocket');
  },

  'xhr2': function() {
    return test(window, 'FormData') &&
      test(window, 'XMLHttpRequestUpload');
  },

  'cors': function() {
    return test(window, "XMLHttpRequest") &&
      'withCredentials' in new XMLHttpRequest();
  },

  'sendbeacon': function() {
    return test(navigator, "sendBeacon");
  },

  /*** Data related APIs ****************************************************************/

  'blobconstructor': function() {
    return test(window, 'Blob');
  },

  'dataset': function() {
    return test(document.documentElement, 'dataset');
  },

  'filereader': function() {
    return test(window, 'File') &&
      test(window, 'FileReader') &&
      test(window, 'FileList');
  },

  'fileapi': function() {
    return test(window, 'File') &&
      test(window, 'FileReader') &&
      test(window, 'FileList') &&
      test(window, 'Blob') &&
      test(window, 'URL');
  },

  'json': function() {
    return test(window, 'JSON') && !! JSON.parse;
  },

  'namevaluestorage': function() {
    return test(window, 'localStorage') && test(window, 'sessionStorage');
  },

  'websqldatabase': function() {
    return test(window, 'openDatabase');
  },

  'indexeddb': function() {
    return test(window, 'indexedDB', true) &&
      test(window, 'IDBTransaction', true) &&
      test(window, 'IDBKeyRange', true);
  },

  /*** User related APIs ****************************************************************/

  'hashchange': function() {
    return test(window, 'onhashchange');
  },

  'pagevisibility': function() {
    return test(document, 'hidden', true);
  },

  'donottrack': function() {
    return test(navigator, 'doNotTrack');
  },

  /*** DOM related APIs *****************************************************************/

  'mutationobserver': function() {
    return test(window, 'MutationObserver');
  },

  'treewalker': function() {
    return test(window, 'TreeWalker');
  },

  'nodeiterator': function() {
    return test(window, 'NodeIterator');
  },

  'range': function() {
    return test(window, 'Range');
  },

  'matchmedia': function() {
    return test(window, 'matchMedia');
  },

  /*** Graphic related APIs *************************************************************/

  'webgl': function() {
    return test(window, 'WebGLRenderingContext');
  },

  'svg': function() {
    return document.createElementNS &&
      document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect;
  },

  'svgfilters': function() {
    return test(window, 'SVGFEColorMatrixElement') &&
      SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2;
  },

  /*** Audio related APIs ***************************************************************/

  'webaudio': function() {
    return test(window, 'AudioContext', true);
  },

  'speechsynthesis': function() {
    return test(window, 'speechSynthesis') &&
      test(window, 'SpeechSynthesisUtterance', true);
  },

  /*** Time related APIs ****************************************************************/

  'performance': function() {
    return test(window, 'performance', true);
  },

  'highresolutiontime': function() {
    return devizr.feature('performance') &&
      typeof window.performance.now === 'function';
  },

  'usertiming': function() {
    return devizr.feature('highresolutiontime') &&
      typeof window.performance.mark === 'function' &&
      typeof window.performance.clearMarks === 'function' &&
      typeof window.performance.measure === 'function' &&
      typeof window.performance.clearMeasures === 'function' &&
      typeof window.performance.getEntriesByType === 'function';
  },

  'requestanimationframe': function() {
    return test(window, 'requestAnimationFrame', true);
  },

  /*** Scripting related APIs ***********************************************************/

  'worker': function() {
    return test(window, 'Worker');
  },

  'sharedworker': function() {
    return test(window, 'SharedWorker');
  },

  'currentscript': function() {
    return test(document, 'currentScript') &&
      test(document, 'onbeforescriptexecute') &&
      test(document, 'onafterscriptexecute');
  },

  /*** HTML5 Elements & Attributes ******************************************************/

  'elem-template': function() {
    return test(window, 'HTMLTemplateElement') &&
      test('template', 'content');
  },

  'elem-video': function() {
    return test(window, 'HTMLVideoElement');
  },

  'elem-audio': function() {
    return test(window, 'HTMLAudioElement');
  },

  'elem-picture': function() {
    return test(window, 'HTMLPictureElement');
  },

  'elem-progress': function() {
    return test(window, 'HTMLProgressElement') &&
      test('progress', 'max');
  },

  'elem-meter': function() {
    return test(window, 'HTMLMeterElement') &&
      test('meter', 'max');
  },

  'elem-output': function() {
    return test(window, 'HTMLOutputElement') &&
      test('output', 'htmlFor') &&
      test('output', 'form') &&
      test('output', 'name');
  },

  'elem-datalist': function() {
    return test(window, 'HTMLDataListElement');
  },

  'elem-keygen': function() {
    return test(window, 'HTMLKeygenElement') &&
      test('keygen', 'challenge');
    //return test('form' in document.createElement('keygen'));
  },

  'elem-details': function() {
    return test('open' in document.createElement('details'));
    //return test(window, 'HTMLDetailsElement');
  },

  'attr-download': function() {
    return test('a', 'download');
  },

  'attr-sandbox': function() {
    return test('iframe', 'sandbox');
  },

  'attr-input-pattern': function() {
    return test('input', 'pattern');
  },

  'contextmenu': function() {
    return test(document.documentElement, 'contextMenu') &&
      test(window, 'HTMLMenuItemElement');
  },

  'contenteditable': function() {
    return test(document.documentElement, 'contentEditable');
  },

  /*** Environment detection (Experimental!) ********************************************/

  'SSL': function() {
    return location.protocol === 'https:';
  },

  'ES3': function() {
    return (function(){ return !!this; }()) &&
      !Function.prototype.bind;
  },

  'ES5': function() {
    return (function(){ return !this; }()) &&
      Function.prototype.bind;
  },

  'MOBILE': function() {
    return (test('android|blackberry') && test('mobile')) ||
      (test('firefox') && test('fennec')) ||
      (test('windows') && test('phone')) ||
      (test('opera') && test('presto')) ||
      (test('netfront') && !test('kindle')) ||
      (test('kindle|silk|kfot|kftt|kfjwi|kfjwa') && test('mobile')) ||
      test('iphone|ipod|meego|webos|iemobile') ||
      test('symbianos|doris|dorothy|gobrowser|maemo|minimo') ||
      test('semc-browser|skyfire|teashark|teleca|uzardweb');
  },

  'TABLET': function() {
    return (!test('MOBILE') && devizr.feature('touch')) ||
      test('tablet|kindle|silk|ipad');
  },

  'DESKTOP': function() {
    return !test('MOBILE') && !test('TABLET');
  },

  'SLOWCONNECTION': function() {
    var connection = (test(navigator, 'connection') &&  navigator.connection) || { type: 0 };
    return connection.type == 3 || connection.type == 4 || /^[23]g$/.test(connection.type);
  },

  'RETINA': function() {
    return window.devicePixelRatio > 1 || (window.matchMedia && window.matchMedia(
      "(-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)").matches
    );
  },

  'MACOSX': function() {
    return test('mac os|macos');
  },

  'WINDOWS': function() {
    return test('windows|htc_hd2|xblwp|zunewp|IEMobile');
  },

  'LINUX': function() {
    return test('linux') &&
      (test('debian|fedora|ubuntu|gentoo|red hat|suse|arch|centos') ||
      test('slackware|mint|midori|kanotix|linspire|maemo|mageia|mandriva'));
  },

  'BSD': function() {
    return test('freebsd|openbsd|netbsd|dragonfly');
  },

  'ANDROID': function() {
    return test('android');
  },

  'BLACKBERRY': function() {
    return test('blackberry|bb10');
  },

  'IOS': function() {
    return (test('like Mac OS') && test('iphone|ipad|ipod')) ||
      (test('Puffin') && test('Linux'));
  },

  'FIREFOXOS': function() {
    return test('firefox') && test('mobile');
  },

  'CHROMEOS': function() {
    return test('cros');
  },

  'UBUNTUTOUCH': function() {
    return test('ubuntu') && test('touch|tablet|mobile');
  },

  'GNUOS': function() {
    return test('gnu|icecat');
  },

  'WEBOS': function() {
    return test('webos|hpwos');
  },

  'SOLARIS': function() {
    return test('sunos');
  },

  'SYMBIAN': function() {
    return test('symbos');
  },

  'XBOX': function() {
    return test('xbox');
  },

  'WII': function() {
    return test('wii|nintendo');
  },

  'JAVA': function() {
    return test('java');
  }

};
<commit_msg>updating existing tests<commit_after>/*jshint browser:true */
/*global devizr: true, test: true, DocumentTouch:true, SVGFEColorMatrixElement:true */
"use strict";
var // Please do not change the first four lines!!!
tests = {

  /*** Device related APIs **************************************************************/

  'fullscreen': function() {
    return test(window, 'fullScreen') ||
      test(document.documentElement, 'requestFullscreen', true);
  },

  'ambientlight': function() {
    return test(window, 'ondevicelight');
  },

  'battery': function() {
    return test(navigator, 'battery', true);
  },

  'geolocation': function() {
    return test(navigator, 'geolocation');
  },

  'pointerlock': function() {
    return test(document.documentElement, 'requestPointerLock', true) &&
      test(document, 'exitPointerLock', true) &&
      test(document, 'pointerLockElement', true);
  },

  'userproximity': function() {
    return test(window, 'onuserproximity');
  },

  'devicemotion': function() {
    return test(window, 'DeviceMotionEvent');
  },

  'deviceorientation': function() {
    return test(window, 'DeviceOrientationEvent');
  },

  'orientationchange': function() {
    return test(screen, 'onmozorientationchange') ||
      test(screen, 'onmsorientationchange');
  },

  'vibrate': function() {
    return test(navigator, 'vibrate', true);
  },

  'gamepads': function() {
    return test(navigator, 'getGamepads');
  },

  'getusermedia': function() {
    return test(navigator, 'getUserMedia', true);
  },

  'touch': function() {
    return test(window, 'ontouchstart') ||
      (test(navigator, 'MaxTouchPoints') && navigator.MaxTouchPoints > 0) ||
      (test(navigator, 'msMaxTouchPoints') && navigator.msMaxTouchPoints > 0) ||
      (test(window, 'DocumentTouch') && document instanceof DocumentTouch);
  },

  'draganddrop': function() {
    return test(document.documentElement, 'draggable') &&
      test(document, 'ondrag') &&
      test(document, 'ondrop');
  },

  /*** Communication related APIs *******************************************************/

  'online': function() {
    return test(navigator, 'onLine');
  },

  'onlineevents': function() {
    return test(window, 'ononline') &&
      test(window, 'onoffline');
  },

  'eventsource': function() {
    return test(window, 'EventSource');
  },

  'applicationcache': function() {
    return test(window, 'applicationCache');
  },

  'connection': function() {
    return test(navigator, 'connection', true);
  },

  'rtcpeerconnection': function() {
    return test(window, 'RTCPeerConnection', true);
  },

  'notification': function() {
    return test(window, 'Notification', true);
  },

  'postmessage': function() {
    return test(window, 'postMessage');
  },

  'websocket': function() {
    return test(window, 'WebSocket');
  },

  'xhr2': function() {
    return test(window, 'FormData') &&
      test(window, 'XMLHttpRequestUpload');
  },

  'cors': function() {
    return test(window, "XMLHttpRequest") &&
      'withCredentials' in new XMLHttpRequest();
  },

  'sendbeacon': function() {
    return test(navigator, "sendBeacon");
  },

  /*** Data related APIs ****************************************************************/

  'blobconstructor': function() {
    return test(window, 'Blob');
  },

  'dataset': function() {
    return test(document.documentElement, 'dataset');
  },

  'filereader': function() {
    return test(window, 'File') &&
      test(window, 'FileReader') &&
      test(window, 'FileList');
  },

  'fileapi': function() {
    return test(window, 'File') &&
      test(window, 'FileReader') &&
      test(window, 'FileList') &&
      test(window, 'Blob') &&
      test(window, 'URL');
  },

  'json': function() {
    return test(window, 'JSON') && !! JSON.parse;
  },

  'namevaluestorage': function() {
    return test(window, 'localStorage') && test(window, 'sessionStorage');
  },

  'websqldatabase': function() {
    return test(window, 'openDatabase');
  },

  'indexeddb': function() {
    return test(window, 'indexedDB', true) &&
      test(window, 'IDBTransaction', true) &&
      test(window, 'IDBKeyRange', true);
  },

  /*** User related APIs ****************************************************************/

  'hashchange': function() {
    return test(window, 'onhashchange');
  },

  'pagevisibility': function() {
    return test(document, 'hidden', true);
  },

  'donottrack': function() {
    return test(navigator, 'doNotTrack');
  },

  /*** DOM related APIs *****************************************************************/

  'mutationobserver': function() {
    return test(window, 'MutationObserver');
  },

  'treewalker': function() {
    return test(window, 'TreeWalker');
  },

  'nodeiterator': function() {
    return test(window, 'NodeIterator');
  },

  'range': function() {
    return test(window, 'Range');
  },

  'matchmedia': function() {
    return test(window, 'matchMedia');
  },

  /*** Graphic related APIs *************************************************************/

  'webgl': function() {
    return test(window, 'WebGLRenderingContext');
  },

  'svg': function() {
    return document.createElementNS &&
      document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGRect;
  },

  'svgfilters': function() {
    return test(window, 'SVGFEColorMatrixElement') &&
      SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2;
  },

  /*** Audio related APIs ***************************************************************/

  'webaudio': function() {
    return test(window, 'AudioContext', true);
  },

  'speechsynthesis': function() {
    return test(window, 'speechSynthesis') &&
      test(window, 'SpeechSynthesisUtterance', true);
  },

  /*** Time related APIs ****************************************************************/

  'performance': function() {
    return test(window, 'performance', true);
  },

  'highresolutiontime': function() {
    return devizr.feature('performance') &&
      typeof window.performance.now === 'function';
  },

  'usertiming': function() {
    return devizr.feature('highresolutiontime') &&
      typeof window.performance.mark === 'function' &&
      typeof window.performance.clearMarks === 'function' &&
      typeof window.performance.measure === 'function' &&
      typeof window.performance.clearMeasures === 'function' &&
      typeof window.performance.getEntriesByType === 'function';
  },

  'requestanimationframe': function() {
    return test(window, 'requestAnimationFrame', true);
  },

  /*** Scripting related APIs ***********************************************************/

  'worker': function() {
    return test(window, 'Worker');
  },

  'sharedworker': function() {
    return test(window, 'SharedWorker');
  },

  'currentscript': function() {
    return test(document, 'currentScript') &&
      test(document, 'onbeforescriptexecute') &&
      test(document, 'onafterscriptexecute');
  },

  /*** HTML5 Elements & Attributes ******************************************************/

  'elem-template': function() {
    return test(window, 'HTMLTemplateElement') &&
      test('template', 'content');
  },

  'elem-video': function() {
    return test(window, 'HTMLVideoElement');
  },

  'elem-audio': function() {
    return test(window, 'HTMLAudioElement');
  },

  'elem-picture': function() {
    return test(window, 'HTMLPictureElement');
  },

  'elem-progress': function() {
    return test(window, 'HTMLProgressElement') &&
      test('progress', 'max');
  },

  'elem-meter': function() {
    return test(window, 'HTMLMeterElement') &&
      test('meter', 'max');
  },

  'elem-output': function() {
    return test(window, 'HTMLOutputElement') &&
      test('output', 'htmlFor') &&
      test('output', 'form') &&
      test('output', 'name');
  },

  'elem-datalist': function() {
    return test(window, 'HTMLDataListElement');
  },

  'elem-keygen': function() {
    return test(window, 'HTMLKeygenElement') &&
      test('keygen', 'challenge');
    //return test('form' in document.createElement('keygen'));
  },

  'elem-details': function() {
    return test('open' in document.createElement('details'));
    //return test(window, 'HTMLDetailsElement');
  },

  'attr-download': function() {
    return test('a', 'download');
  },

  'attr-sandbox': function() {
    return test('iframe', 'sandbox');
  },

  'attr-input-pattern': function() {
    return test('input', 'pattern');
  },

  'contextmenu': function() {
    return test(document.documentElement, 'contextMenu') &&
      test(window, 'HTMLMenuItemElement');
  },

  'contenteditable': function() {
    return test(document.documentElement, 'contentEditable');
  },

  /*** Environment detection (Experimental!) ********************************************/

  'SSL': function() {
    return location.protocol === 'https:';
  },

  'ES3': function() {
    return (function(){ return !!this; }()) &&
      !Function.prototype.bind;
  },

  'ES5': function() {
    return (function(){ return !this; }()) &&
      Function.prototype.bind;
  },

  'MOBILE': function() {
    return (test('android|blackberry') && test('mobile')) ||
      (test('firefox') && test('fennec')) ||
      (test('windows') && test('phone')) ||
      (test('opera') && test('presto')) ||
      (test('netfront') && !test('kindle')) ||
      (test('kindle|silk|kfot|kftt|kfjwi|kfjwa') && test('mobile')) ||
      test('iphone|ipod|meego|webos|iemobile') ||
      test('symbianos|doris|dorothy|gobrowser|maemo|minimo') ||
      test('semc-browser|skyfire|teashark|teleca|uzardweb');
  },

  'TABLET': function() {
    return (!test('MOBILE') && devizr.feature('touch')) ||
      test('tablet|kindle|silk|ipad');
  },

  'DESKTOP': function() {
    return !test('MOBILE') && !test('TABLET');
  },

  'SLOWCONNECTION': function() {
    var connection = (test(navigator, 'connection') &&  navigator.connection) || { type: 0 };
    return connection.type == 3 || connection.type == 4 || /^[23]g$/.test(connection.type);
  },

  'RETINA': function() {
    return window.devicePixelRatio > 1 || (window.matchMedia && window.matchMedia(
      "(-webkit-min-device-pixel-ratio: 1.5),(-moz-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5)").matches
    );
  },

  'MACOSX': function() {
    return test('mac os|macos');
  },

  'WINDOWS': function() {
    return test('windows|htc_hd2|xblwp|zunewp|IEMobile');
  },

  'LINUX': function() {
    return test('linux') &&
      (test('debian|fedora|ubuntu|gentoo|red hat|suse|arch|centos') ||
      test('slackware|mint|midori|kanotix|linspire|maemo|mageia|mandriva'));
  },

  'BSD': function() {
    return test('freebsd|openbsd|netbsd|dragonfly');
  },

  'ANDROID': function() {
    return test('android');
  },

  'BLACKBERRY': function() {
    return test('blackberry|bb10');
  },

  'IOS': function() {
    return (test('like Mac OS') && test('iphone|ipad|ipod')) ||
      (test('Puffin') && test('Linux'));
  },

  'FIREFOXOS': function() {
    return test('firefox') && test('mobile');
  },

  'CHROMEOS': function() {
    return test('cros');
  },

  'UBUNTUTOUCH': function() {
    return test('ubuntu') && test('touch|tablet|mobile');
  },

  'GNUOS': function() {
    return test('gnu|icecat');
  },

  'WEBOS': function() {
    return test('webos|hpwos');
  },

  'SOLARIS': function() {
    return test('sunos');
  },

  'SYMBIAN': function() {
    return test('symbos');
  },

  'XBOX': function() {
    return test('xbox');
  },

  'WII': function() {
    return test('wii|nintendo');
  },

  'JAVA': function() {
    return test('java');
  }

};
<|endoftext|>


<commit_before>import elrUtlities from 'elr-utilities';
const $ = require('jquery');

let elr = elrUtlities();

const elrLightbox = function({
    $images = $('ul.elr-lightbox-thumbnails'),
    speed = 300
} = {}) {
    const self = {
        createThumbnails(list) {
            const $links = list.find('a');
            let thumbnailList = [];
            let thumbnails = '';

            $links.each(function() {
                thumbnailList.push($(this).attr('href'));
            });

            $.each(thumbnailList, function(k, v) {
                thumbnails += `<li><a href=${v}><img src=${v}></a></li>`;
            });

            return thumbnails;
        },

        createLightbox(thumbnails, speed) {
            const img = $(this).attr('href');

            const $imgVisible = elr.createElement('img', {
                class: 'img-visible',
                src: img,
                alt: 'thumbnail'
            });

            const $close = elr.createElement('button', {
                class: 'close',
                text: 'x'
            });

            const $thumbnails = elr.createElement('ul', {
                class: 'thumbnail-list',
                html: thumbnails
            });

            const $nav = elr.createElement('div', {
                class: 'lightbox-nav',
                html: `<button class="prev" data-dir="prev"><i class="fa fa-caret-left"></i></button><button class="next" data-dir="next"><i class="fa fa-caret-right"></i></button>`
            });

            const $lightbox = elr.createElement('div', {
                class: 'elr-blackout'
            });

            $lightbox.hide().appendTo('body').fadeIn(speed, function() {
                $close.appendTo($lightbox);
                $imgVisible.appendTo($lightbox);
                $nav.appendTo($lightbox);
                $thumbnails.appendTo($lightbox);
            });
        },

        getNextImageIndex(direction, $list, $currentImg) {
            const currentImgSrc = $currentImg.attr('src');
            const $currentThumb = $list.find(`img[src$="${currentImgSrc}"]`).closest('li').index();
            const len = $list.find('li').length - 1;

            if (direction === 'prev') {
                return ($currentThumb === 0) ? len : $currentThumb - 1;
            }

            return ($currentThumb === len) ? 0 : $currentThumb + 1;
        },

        advanceImage(direction, speed) {
            const $list = $('.thumbnail-list');
            const $currentImg = $('div.elr-blackout img.img-visible');
            const $nextImg = $list.find('li').eq(this.getNextImageIndex(direction, $list, $currentImg)).find('img').attr('src');

            $currentImg.fadeOut(speed, function() {
                $(this).attr('src', $nextImg).fadeIn(speed);
            });
        },

        changeImage(speed) {
            const img = $(this).attr('href');
            const $oldImg = $('div.elr-blackout img.img-visible');
            const oldImgSrc = $oldImg.attr('src');

            if (oldImgSrc !== img) {
                $oldImg.fadeOut(speed, function() {
                    $(this).attr('src', img).fadeIn(speed);
                });
            }
        },

        removeLightbox(speed) {
            $('div.elr-blackout').fadeOut(speed, function() {
                $(this).remove();
            });
        }
    };

    if ($images.length) {
        const thumbnails = self.createThumbnails($images);
        const $body = $('body');

        $images.on('click', 'a', function(e) {
            e.preventDefault();
            self.createLightbox.call(this, thumbnails, speed);
        });

        $body.on('click', 'div.elr-blackout button.close', self.removeLightbox);
        $body.on('click', 'div.elr-blackout', function(e) {
            e.stopPropagation();
            self.removeLightbox(speed);
        });

        $body.on('click', 'div.elr-blackout ul.thumbnail-list a', function(e) {
            e.preventDefault();
            e.stopPropagation();
            self.changeImage.call(this, speed);
        });

        elr.killEvent($body, 'click', 'div.elr-blackout .img-visible');
        elr.killEvent($body, 'click', 'div.elr-blackout .lightbox-nav button');

        $body.on('click', 'div.elr-blackout .lightbox-nav button', function(e) {
            e.preventDefault();
            e.stopPropagation();

            const direction = $(this).data('dir');

            self.advanceImage(direction, speed);
        });

        // page image slideshow when user hits left/right arrow keys
        $body.on('keydown', function(e) {
            if (e.which === 37) {
                self.advanceImage('prev', speed);
            } else if (e.which === 39) {
                self.advanceImage('next', speed);
            }
        });

        // close lightbox when user hits the escape key
        $body.on('keydown', function(e) {
            if (e.which === 27) {
                self.removeLightbox();
            }
        });
    }

    return self;
};

export default elrLightbox;<commit_msg>fix elr-utility-lib include<commit_after>import elrUtlities from 'elr-utility-lib';
const $ = require('jquery');

let elr = elrUtlities();

const elrLightbox = function({
    $images = $('ul.elr-lightbox-thumbnails'),
    speed = 300
} = {}) {
    const self = {
        createThumbnails(list) {
            const $links = list.find('a');
            let thumbnailList = [];
            let thumbnails = '';

            $links.each(function() {
                thumbnailList.push($(this).attr('href'));
            });

            $.each(thumbnailList, function(k, v) {
                thumbnails += `<li><a href=${v}><img src=${v}></a></li>`;
            });

            return thumbnails;
        },

        createLightbox(thumbnails, speed) {
            const img = $(this).attr('href');

            const $imgVisible = elr.createElement('img', {
                class: 'img-visible',
                src: img,
                alt: 'thumbnail'
            });

            const $close = elr.createElement('button', {
                class: 'close',
                text: 'x'
            });

            const $thumbnails = elr.createElement('ul', {
                class: 'thumbnail-list',
                html: thumbnails
            });

            const $nav = elr.createElement('div', {
                class: 'lightbox-nav',
                html: `<button class="prev" data-dir="prev"><i class="fa fa-caret-left"></i></button><button class="next" data-dir="next"><i class="fa fa-caret-right"></i></button>`
            });

            const $lightbox = elr.createElement('div', {
                class: 'elr-blackout'
            });

            $lightbox.hide().appendTo('body').fadeIn(speed, function() {
                $close.appendTo($lightbox);
                $imgVisible.appendTo($lightbox);
                $nav.appendTo($lightbox);
                $thumbnails.appendTo($lightbox);
            });
        },

        getNextImageIndex(direction, $list, $currentImg) {
            const currentImgSrc = $currentImg.attr('src');
            const $currentThumb = $list.find(`img[src$="${currentImgSrc}"]`).closest('li').index();
            const len = $list.find('li').length - 1;

            if (direction === 'prev') {
                return ($currentThumb === 0) ? len : $currentThumb - 1;
            }

            return ($currentThumb === len) ? 0 : $currentThumb + 1;
        },

        advanceImage(direction, speed) {
            const $list = $('.thumbnail-list');
            const $currentImg = $('div.elr-blackout img.img-visible');
            const $nextImg = $list.find('li').eq(this.getNextImageIndex(direction, $list, $currentImg)).find('img').attr('src');

            $currentImg.fadeOut(speed, function() {
                $(this).attr('src', $nextImg).fadeIn(speed);
            });
        },

        changeImage(speed) {
            const img = $(this).attr('href');
            const $oldImg = $('div.elr-blackout img.img-visible');
            const oldImgSrc = $oldImg.attr('src');

            if (oldImgSrc !== img) {
                $oldImg.fadeOut(speed, function() {
                    $(this).attr('src', img).fadeIn(speed);
                });
            }
        },

        removeLightbox(speed) {
            $('div.elr-blackout').fadeOut(speed, function() {
                $(this).remove();
            });
        }
    };

    if ($images.length) {
        const thumbnails = self.createThumbnails($images);
        const $body = $('body');

        $images.on('click', 'a', function(e) {
            e.preventDefault();
            self.createLightbox.call(this, thumbnails, speed);
        });

        $body.on('click', 'div.elr-blackout button.close', self.removeLightbox);
        $body.on('click', 'div.elr-blackout', function(e) {
            e.stopPropagation();
            self.removeLightbox(speed);
        });

        $body.on('click', 'div.elr-blackout ul.thumbnail-list a', function(e) {
            e.preventDefault();
            e.stopPropagation();
            self.changeImage.call(this, speed);
        });

        elr.killEvent($body, 'click', 'div.elr-blackout .img-visible');
        elr.killEvent($body, 'click', 'div.elr-blackout .lightbox-nav button');

        $body.on('click', 'div.elr-blackout .lightbox-nav button', function(e) {
            e.preventDefault();
            e.stopPropagation();

            const direction = $(this).data('dir');

            self.advanceImage(direction, speed);
        });

        // page image slideshow when user hits left/right arrow keys
        $body.on('keydown', function(e) {
            if (e.which === 37) {
                self.advanceImage('prev', speed);
            } else if (e.which === 39) {
                self.advanceImage('next', speed);
            }
        });

        // close lightbox when user hits the escape key
        $body.on('keydown', function(e) {
            if (e.which === 27) {
                self.removeLightbox();
            }
        });
    }

    return self;
};

export default elrLightbox;<|endoftext|>


<commit_before>/**
 * Featherlight - ultra slim jQuery lightbox
 * Version 0.3.1 - http://noelboss.github.io/featherlight/
 *
 * Copyright 2014, Noël Raoul Bossart (http://www.noelboss.com)
 * MIT Licensed.
**/
(function($) {
	"use strict";
	if($ === 'undefined') {return; }

	/* featherlight object */
	var fl = {
		id: 0,                                    /* Used to id single featherlight instances */
		defaults: {                               /* You can access and override all defaults using $.fl.defaults */
			autostart:    true,                   /* Initialize all links with that match "selector" on document ready */
			namespace:    'featherlight',         /* Name of the events and css class prefix */
			selector:     '[data-featherlight]',  /* Elements that trigger the lightbox */
			context:      'body',                 /* Context used to search for the lightbox content and triggers */
			type: {                               /* Manually set type of lightbox. Otherwise, it will check for the targetAttrs value. */
				image: false,
				ajax: false
			},
			targetAttr:   'data-featherlight',    /* Attribute of the triggered element that contains the selector to the lightbox content */
			variant:      null,                   /* Class that will be added to change look of the lightbox */
			resetCss:     false,                  /* Reset all css */
			background:   null,                   /* Custom DOM for the background, wrapper and the closebutton */
			openTrigger:  'click',                /* Event that triggers the lightbox */
			closeTrigger: 'click',                /* Event that triggers the closing of the lightbox */
			openSpeed:    250,                    /* Duration of opening animation */
			closeSpeed:   250,                    /* Duration of closing animation */
			closeOnBg:    true,                   /* Close lightbox on click on the background */
			closeOnEsc:   true,                   /* Close lightbox when pressing esc */
			closeOnAny:   false,                  /* Close lightbox when clicking anywhere */
			closeIcon:    '✕',             /* Close icon */
			beforeOpen:   null,                   /* Called before open. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
			beforeClose:  null,                   /* Called before close. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
			afterOpen:    null,                   /* Called after open. Gets event as parameter, this contains all data */
			afterClose:   null,                   /* Called after close. Gets event as parameter, this contains all data */
			/* opens the lightbox "this" contains $instance with the lightbox, and with the config */
			open: function(event){
				var open = true;
				/* check if before function exists */
				if(typeof $.featherlight.defaults.beforeOpen === 'function'){
					open = $.proxy($.featherlight.defaults.beforeOpen, this, event)();
				}
				/* if no before function or before function did not stop propagation */
				if(open !== false){
					/* call open method */
					open = $.proxy($.featherlight.methods.open, this, event)();
				}

				/* check if after function exists */
				if(open !== false && typeof $.featherlight.defaults.afterOpen === 'function'){
					$.proxy($.featherlight.defaults.afterOpen, this, event)();
				}
			},
			/* closes the lightbox "this" contains $instance with the lightbox, and with the config */
			close: function(event){
				var close = true;
				/* check if before Function exists */
				if(typeof $.featherlight.defaults.beforeClose === 'function'){
					close = $.proxy($.featherlight.defaults.beforeClose, this, event)();
				}

				/* if no before function or before function did not stop propagation */
				if(close !== false){
					/* call open method */
					close = $.proxy($.featherlight.methods.close, this, event)();
				}

				/* check if after Function exists */
				if(close !== false && typeof $.featherlight.defaults.afterClose === 'function'){
					$.proxy($.featherlight.defaults.afterClose, this, event)();
				}
			}
		},
		/* you can access and override all methods using $.featherlight.methods */
		methods: {
			/* setup iterates over a single instance of featherlight and prepares the background and binds the events */
			setup: function(config, content){
				config = $.extend({}, fl.defaults, config);

				var $elm = $(this) || $(),
					variant = $elm.attr('data-'+config.namespace+'-variant') || config.variant,
					css = !config.resetCss ? config.namespace : config.namespace+'-reset', /* by adding -reset to the classname, we reset all the default css */
					$background = $(config.background || '

'+config.closeIcon+'

'),

					/* everything that we need later is stored in self (target) */
					self = {
						id: fl.id++,
						config: config,
						content: content,
						$elm: $elm,
						$instance: $background.clone().addClass(variant) /* clone DOM for the background, wrapper and the close button */
					};

				/* close when click on background */
				self.$instance.on(config.closeTrigger+'.'+config.namespace, $.proxy(config.close, self));

				/* bind close on esc */
				if(self.config.closeOnEsc){
					$(document).bind('keyup.'+self.config.namespace+self.id, function(e) {
						if (e.keyCode === 27) { // esc keycode
							self.$instance.find('.'+self.config.namespace+'-close').click();
						}
					});
				}

				/* bind or call open function */
				if($elm.length > 0 && this.tagName){
					$elm.on(config.openTrigger+'.'+config.namespace, $.proxy(config.open, self));
				} else {
					$.proxy(config.open, self)();
				}

			},

			/* this method prepares the content and converts it into a jQuery object */
			getContent: function(){
				var self = this,
					ok = true,
					content = self.content,
					$content = null,
					attr = self.$elm.attr(self.config.targetAttr) || '',
					url = '';

				/* if we have DOM, convert to jQuery Object */
				if(self.$content instanceof $ === false && typeof content === 'string'){
					$content = $(content);
				} else if(content instanceof $ === false){ /* if we have no jQuery Object */
					/* check if we have an image and create element */
					if(self.config.type.image === true || attr === 'image' || attr.match(/\.(png|jpg|jpeg|gif|tiff|bmp)$/i)){
						url = attr.match(/\.(png|jpg|jpeg|gif|tiff|bmp)$/i) ? attr : self.$elm.attr('href');
						$content = $('');
					}
					/* check if we have an ajax link */
					else if(self.config.type.ajax === true || attr === 'ajax' || attr.match(/(http|htm|php)/i)){
						url = attr.match(/(http|htm|php)/i) ? attr : self.$elm.attr('href');
						/* we are using load so one can specify a target with: url.html #targetelement */
						content = url ? $('

').load(url, function(response, status){
							if ( status !== "error" ) {
								$.featherlight(content.html(), self.config);
							}
						}) : null;
						ok = false;
					}
					/* otherwise create jquery element by using the attribute as selector */
					else if(attr) {
						$content = $($(attr), self.config.context);
					}
					/* could not find any content */
					else {
						ok = false;
					}
				}
				if(ok && $content instanceof $){
					/* we need a special class for the iframe */
					if($content.is('iframe') || $('iframe', $content).length > 0){
						self.$instance.addClass(self.config.namespace+'-iframe');
					}
					$content.addClass(self.config.namespace+'-inner');
					self.$content = $content.clone();

					/* remove existing content */
					self.$instance.find('.'+self.config.namespace+'-inner').remove();
					self.$instance.find('.'+self.config.namespace+'-content').append(self.$content);
				}
				return ok;
			},

			/* opens the lightbox "this" contains $instance with the lightbox, and with the config */
			open: function(event){
				if(event){event.preventDefault();}
				var self = this;

				/* If we have content, add it and show lightbox */
				if($.proxy(fl.methods.getContent, self)() !== false){
					self.$instance.prependTo('body').fadeIn(self.config.openSpeed);
				} else {
					return false;
				}
			},

			/* closes the lightbox "this" contains $instance with the lightbox, and with the config */
			close: function(event){
				var self = this,
					config = self.config,
					$instance = $(event.target);

				if(config.closeOnAny || (config.closeOnBg && $instance.is('.'+config.namespace)) || $instance.is('.'+config.namespace+'-close')){
					if(event){
						event.preventDefault();
					}
					if(self.config.closeOnEsc){
						$(document).unbind('keyup.'+self.config.namespace+self.id);
					}
					self.$instance.fadeOut(self.config.closeSpeed,function(){
						self.$instance.detach();
					});
				}
			}
		}
	};

	/* extend jQuery with standalone featherlight method  $.featherlight(elm, config); */
	$.featherlight = function($content, config) {
		/* if $.featherlight() was called only with config or without anything, initialize manually */
		if(typeof $content !== 'string' && $content instanceof $ === false){
			config = typeof $content === 'Object' ? $.extend({}, fl.defaults, $content) : fl.defaults;

			$(config.selector, config.context).featherlight();
		} else {
			$.proxy(fl.methods.setup, null, config, $content)();
		}
	};

	/* extend jQuery with selector featherlight method $(elm).featherlight(config, elm); */
	$.fn.featherlight = function(config, $content) {
		$(this).each(function(){
			$.proxy(fl.methods.setup, this, config, $content)();
		});
	};

	/* extend featherlight with defaults and methods */
	$.extend($.featherlight, fl);

	/* bind featherlight on ready if config autostart is true */
	$(document).ready(function(){
		var config = $.featherlight.defaults;
		if(config.autostart){
			$(config.selector, config.context).featherlight();
		}
	});
}(typeof jQuery === 'function' ? jQuery : alert('Too much lightness, Featherlight needs jQuery.')));
<commit_msg>Add missing periods<commit_after>/**
 * Featherlight - ultra slim jQuery lightbox
 * Version 0.3.1 - http://noelboss.github.io/featherlight/
 *
 * Copyright 2014, Noël Raoul Bossart (http://www.noelboss.com)
 * MIT Licensed.
**/
(function($) {
	"use strict";
	if($ === 'undefined') {return; }

	/* featherlight object */
	var fl = {
		id: 0,                                    /* Used to id single featherlight instances */
		defaults: {                               /* You can access and override all defaults using $.fl.defaults */
			autostart:    true,                   /* Initialize all links with that match "selector" on document ready */
			namespace:    'featherlight',         /* Name of the events and css class prefix */
			selector:     '[data-featherlight]',  /* Elements that trigger the lightbox */
			context:      'body',                 /* Context used to search for the lightbox content and triggers */
			type: {                               /* Manually set type of lightbox. Otherwise, it will check for the targetAttrs value. */
				image: false,
				ajax: false
			},
			targetAttr:   'data-featherlight',    /* Attribute of the triggered element that contains the selector to the lightbox content */
			variant:      null,                   /* Class that will be added to change look of the lightbox */
			resetCss:     false,                  /* Reset all css */
			background:   null,                   /* Custom DOM for the background, wrapper and the closebutton */
			openTrigger:  'click',                /* Event that triggers the lightbox */
			closeTrigger: 'click',                /* Event that triggers the closing of the lightbox */
			openSpeed:    250,                    /* Duration of opening animation */
			closeSpeed:   250,                    /* Duration of closing animation */
			closeOnBg:    true,                   /* Close lightbox on click on the background */
			closeOnEsc:   true,                   /* Close lightbox when pressing esc */
			closeOnAny:   false,                  /* Close lightbox when clicking anywhere */
			closeIcon:    '✕',             /* Close icon */
			beforeOpen:   null,                   /* Called before open. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
			beforeClose:  null,                   /* Called before close. can return false to prevent opening of lightbox. Gets event as parameter, this contains all data */
			afterOpen:    null,                   /* Called after open. Gets event as parameter, this contains all data */
			afterClose:   null,                   /* Called after close. Gets event as parameter, this contains all data */
			/* opens the lightbox. "this" contains $instance with the lightbox, and with the config */
			open: function(event){
				var open = true;
				/* check if before function exists */
				if(typeof $.featherlight.defaults.beforeOpen === 'function'){
					open = $.proxy($.featherlight.defaults.beforeOpen, this, event)();
				}
				/* if no before function or before function did not stop propagation */
				if(open !== false){
					/* call open method */
					open = $.proxy($.featherlight.methods.open, this, event)();
				}

				/* check if after function exists */
				if(open !== false && typeof $.featherlight.defaults.afterOpen === 'function'){
					$.proxy($.featherlight.defaults.afterOpen, this, event)();
				}
			},
			/* closes the lightbox. "this" contains $instance with the lightbox, and with the config */
			close: function(event){
				var close = true;
				/* check if before Function exists */
				if(typeof $.featherlight.defaults.beforeClose === 'function'){
					close = $.proxy($.featherlight.defaults.beforeClose, this, event)();
				}

				/* if no before function or before function did not stop propagation */
				if(close !== false){
					/* call open method */
					close = $.proxy($.featherlight.methods.close, this, event)();
				}

				/* check if after Function exists */
				if(close !== false && typeof $.featherlight.defaults.afterClose === 'function'){
					$.proxy($.featherlight.defaults.afterClose, this, event)();
				}
			}
		},
		/* you can access and override all methods using $.featherlight.methods */
		methods: {
			/* setup iterates over a single instance of featherlight and prepares the background and binds the events */
			setup: function(config, content){
				config = $.extend({}, fl.defaults, config);

				var $elm = $(this) || $(),
					variant = $elm.attr('data-'+config.namespace+'-variant') || config.variant,
					css = !config.resetCss ? config.namespace : config.namespace+'-reset', /* by adding -reset to the classname, we reset all the default css */
					$background = $(config.background || '

'+config.closeIcon+'

'),

					/* everything that we need later is stored in self (target) */
					self = {
						id: fl.id++,
						config: config,
						content: content,
						$elm: $elm,
						$instance: $background.clone().addClass(variant) /* clone DOM for the background, wrapper and the close button */
					};

				/* close when click on background */
				self.$instance.on(config.closeTrigger+'.'+config.namespace, $.proxy(config.close, self));

				/* bind close on esc */
				if(self.config.closeOnEsc){
					$(document).bind('keyup.'+self.config.namespace+self.id, function(e) {
						if (e.keyCode === 27) { // esc keycode
							self.$instance.find('.'+self.config.namespace+'-close').click();
						}
					});
				}

				/* bind or call open function */
				if($elm.length > 0 && this.tagName){
					$elm.on(config.openTrigger+'.'+config.namespace, $.proxy(config.open, self));
				} else {
					$.proxy(config.open, self)();
				}

			},

			/* this method prepares the content and converts it into a jQuery object */
			getContent: function(){
				var self = this,
					ok = true,
					content = self.content,
					$content = null,
					attr = self.$elm.attr(self.config.targetAttr) || '',
					url = '';

				/* if we have DOM, convert to jQuery Object */
				if(self.$content instanceof $ === false && typeof content === 'string'){
					$content = $(content);
				} else if(content instanceof $ === false){ /* if we have no jQuery Object */
					/* check if we have an image and create element */
					if(self.config.type.image === true || attr === 'image' || attr.match(/\.(png|jpg|jpeg|gif|tiff|bmp)$/i)){
						url = attr.match(/\.(png|jpg|jpeg|gif|tiff|bmp)$/i) ? attr : self.$elm.attr('href');
						$content = $('');
					}
					/* check if we have an ajax link */
					else if(self.config.type.ajax === true || attr === 'ajax' || attr.match(/(http|htm|php)/i)){
						url = attr.match(/(http|htm|php)/i) ? attr : self.$elm.attr('href');
						/* we are using load so one can specify a target with: url.html #targetelement */
						content = url ? $('

').load(url, function(response, status){
							if ( status !== "error" ) {
								$.featherlight(content.html(), self.config);
							}
						}) : null;
						ok = false;
					}
					/* otherwise create jquery element by using the attribute as selector */
					else if(attr) {
						$content = $($(attr), self.config.context);
					}
					/* could not find any content */
					else {
						ok = false;
					}
				}
				if(ok && $content instanceof $){
					/* we need a special class for the iframe */
					if($content.is('iframe') || $('iframe', $content).length > 0){
						self.$instance.addClass(self.config.namespace+'-iframe');
					}
					$content.addClass(self.config.namespace+'-inner');
					self.$content = $content.clone();

					/* remove existing content */
					self.$instance.find('.'+self.config.namespace+'-inner').remove();
					self.$instance.find('.'+self.config.namespace+'-content').append(self.$content);
				}
				return ok;
			},

			/* opens the lightbox. "this" contains $instance with the lightbox, and with the config */
			open: function(event){
				if(event){event.preventDefault();}
				var self = this;

				/* If we have content, add it and show lightbox */
				if($.proxy(fl.methods.getContent, self)() !== false){
					self.$instance.prependTo('body').fadeIn(self.config.openSpeed);
				} else {
					return false;
				}
			},

			/* closes the lightbox. "this" contains $instance with the lightbox, and with the config */
			close: function(event){
				var self = this,
					config = self.config,
					$instance = $(event.target);

				if(config.closeOnAny || (config.closeOnBg && $instance.is('.'+config.namespace)) || $instance.is('.'+config.namespace+'-close')){
					if(event){
						event.preventDefault();
					}
					if(self.config.closeOnEsc){
						$(document).unbind('keyup.'+self.config.namespace+self.id);
					}
					self.$instance.fadeOut(self.config.closeSpeed,function(){
						self.$instance.detach();
					});
				}
			}
		}
	};

	/* extend jQuery with standalone featherlight method  $.featherlight(elm, config); */
	$.featherlight = function($content, config) {
		/* if $.featherlight() was called only with config or without anything, initialize manually */
		if(typeof $content !== 'string' && $content instanceof $ === false){
			config = typeof $content === 'Object' ? $.extend({}, fl.defaults, $content) : fl.defaults;

			$(config.selector, config.context).featherlight();
		} else {
			$.proxy(fl.methods.setup, null, config, $content)();
		}
	};

	/* extend jQuery with selector featherlight method $(elm).featherlight(config, elm); */
	$.fn.featherlight = function(config, $content) {
		$(this).each(function(){
			$.proxy(fl.methods.setup, this, config, $content)();
		});
	};

	/* extend featherlight with defaults and methods */
	$.extend($.featherlight, fl);

	/* bind featherlight on ready if config autostart is true */
	$(document).ready(function(){
		var config = $.featherlight.defaults;
		if(config.autostart){
			$(config.selector, config.context).featherlight();
		}
	});
}(typeof jQuery === 'function' ? jQuery : alert('Too much lightness, Featherlight needs jQuery.')));
<|endoftext|>