<commit_before>goog.provide('ngeo.profileDirective');

goog.require('goog.asserts');
goog.require('goog.events');
goog.require('ngeo');
goog.require('ngeo.profile');
goog.require('ngeo.Debounce');

/**
 * Provides a directive used to insert an elevation profile chart
 * in the DOM.
 *
 * Example:
 *
 *

 *

 *
 * Where "ctrl.profileOptions" is of type {@link ngeox.profile.ProfileOptions};
 * "ctrl.profileData" and "ctrl.profilePois" are arrays which will be
 * processed by {@link ngeox.profile.ElevationExtractor} and
 * {@link ngeox.profile.PoiExtractor}.
 *
 * See our live example: [../examples/profile.html](../examples/profile.html)
 *
 * @htmlAttribute {?Object} ngeo-profile The profile data.
 * @htmlAttribute {ngeox.profile.ProfileOptions} ngeo-profile-options The options.
 * @htmlAttribute {?Array} ngeo-profile-pois The data for POIs.
 * @htmlAttribute {*} ngeo-profile-highlight Any property on the scope which
 * evaluated value may correspond to distance from origin.
 * @param {ngeo.Debounce} ngeoDebounce ngeo Debounce service.
 * @return {angular.Directive} Directive Definition Object.
 * @ngInject
 * @ngdoc directive
 * @ngname ngeoProfile
 */
ngeo.profileDirective = function(ngeoDebounce) {
  return {
    restrict: 'A',
    /**
     * @param {angular.Scope} scope Scope.
     * @param {angular.JQLite} element Element.
     * @param {angular.Attributes} attrs Atttributes.
     */
    link(scope, element, attrs) {

      const optionsAttr = attrs['ngeoProfileOptions'];
      goog.asserts.assert(optionsAttr !== undefined);

      const selection = d3.select(element[0]);
      let profile, elevationData, poiData;

      scope.$watchCollection(optionsAttr, (newVal) => {

        const options = /** @type {ngeox.profile.ProfileOptions} */
                (ol.obj.assign({}, newVal));

        if (options !== undefined) {

          // proxy the hoverCallback and outCallbackin order to be able to
          // call $applyAsync
          //
          // We're using $applyAsync here because the callback may be
          // called inside the Angular context. For example, it's the case
          // when the user hover's the line geometry on the map and the
          // profileHighlight property is changed.
          //
          // For that reason we use $applyAsync instead of $apply here.
          if (options.hoverCallback !== undefined) {
            const origHoverCallback = options.hoverCallback;
            options.hoverCallback = function(...args) {
              origHoverCallback(...args);
              scope.$applyAsync();
            };
          }

          if (options.outCallback !== undefined) {
            const origOutCallback = options.outCallback;
            options.outCallback = function() {
              origOutCallback();
              scope.$applyAsync();
            };
          }

          profile = ngeo.profile(options);
          refreshData();
        }
      });

      scope.$watch(attrs['ngeoProfile'], (newVal, oldVal) => {
        elevationData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfilePois'], (newVal, oldVal) => {
        poiData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfileHighlight'],
        (newVal, oldVal) => {
          if (newVal === undefined) {
            return;
          }
          if (newVal > 0) {
            profile.highlight(newVal);
          } else {
            profile.clearHighlight();
          }
        });

      goog.events.listen(window, 'resize',
        ngeoDebounce(refreshData, 50, true),
        false, this);

      function refreshData() {
        if (profile !== undefined) {
          selection.datum(elevationData).call(profile);
          if (elevationData !== undefined) {
            profile.showPois(poiData);
          }
        }
      }
    }
  };
};

ngeo.module.directive('ngeoProfile', ngeo.profileDirective);
<commit_msg>Remove usage of goog.events (#3092)<commit_after>goog.provide('ngeo.profileDirective');

goog.require('goog.asserts');
goog.require('ngeo');
goog.require('ngeo.profile');
goog.require('ngeo.Debounce');

/**
 * Provides a directive used to insert an elevation profile chart
 * in the DOM.
 *
 * Example:
 *
 *

 *

 *
 * Where "ctrl.profileOptions" is of type {@link ngeox.profile.ProfileOptions};
 * "ctrl.profileData" and "ctrl.profilePois" are arrays which will be
 * processed by {@link ngeox.profile.ElevationExtractor} and
 * {@link ngeox.profile.PoiExtractor}.
 *
 * See our live example: [../examples/profile.html](../examples/profile.html)
 *
 * @htmlAttribute {?Object} ngeo-profile The profile data.
 * @htmlAttribute {ngeox.profile.ProfileOptions} ngeo-profile-options The options.
 * @htmlAttribute {?Array} ngeo-profile-pois The data for POIs.
 * @htmlAttribute {*} ngeo-profile-highlight Any property on the scope which
 * evaluated value may correspond to distance from origin.
 * @param {ngeo.Debounce} ngeoDebounce ngeo Debounce service.
 * @return {angular.Directive} Directive Definition Object.
 * @ngInject
 * @ngdoc directive
 * @ngname ngeoProfile
 */
ngeo.profileDirective = function(ngeoDebounce) {
  return {
    restrict: 'A',
    /**
     * @param {angular.Scope} scope Scope.
     * @param {angular.JQLite} element Element.
     * @param {angular.Attributes} attrs Atttributes.
     */
    link(scope, element, attrs) {

      const optionsAttr = attrs['ngeoProfileOptions'];
      goog.asserts.assert(optionsAttr !== undefined);

      const selection = d3.select(element[0]);
      let profile, elevationData, poiData;

      scope.$watchCollection(optionsAttr, (newVal) => {

        const options = /** @type {ngeox.profile.ProfileOptions} */
                (ol.obj.assign({}, newVal));

        if (options !== undefined) {

          // proxy the hoverCallback and outCallbackin order to be able to
          // call $applyAsync
          //
          // We're using $applyAsync here because the callback may be
          // called inside the Angular context. For example, it's the case
          // when the user hover's the line geometry on the map and the
          // profileHighlight property is changed.
          //
          // For that reason we use $applyAsync instead of $apply here.
          if (options.hoverCallback !== undefined) {
            const origHoverCallback = options.hoverCallback;
            options.hoverCallback = function(...args) {
              origHoverCallback(...args);
              scope.$applyAsync();
            };
          }

          if (options.outCallback !== undefined) {
            const origOutCallback = options.outCallback;
            options.outCallback = function() {
              origOutCallback();
              scope.$applyAsync();
            };
          }

          profile = ngeo.profile(options);
          refreshData();
        }
      });

      scope.$watch(attrs['ngeoProfile'], (newVal, oldVal) => {
        elevationData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfilePois'], (newVal, oldVal) => {
        poiData = newVal;
        refreshData();
      });

      scope.$watch(attrs['ngeoProfileHighlight'],
        (newVal, oldVal) => {
          if (newVal === undefined) {
            return;
          }
          if (newVal > 0) {
            profile.highlight(newVal);
          } else {
            profile.clearHighlight();
          }
        });

      ol.events.listen(window, 'resize', ngeoDebounce(refreshData, 50, true), this);

      function refreshData() {
        if (profile !== undefined) {
          selection.datum(elevationData).call(profile);
          if (elevationData !== undefined) {
            profile.showPois(poiData);
          }
        }
      }
    }
  };
};

ngeo.module.directive('ngeoProfile', ngeo.profileDirective);
<|endoftext|>


<commit_before>/*!
 * jQuery Sticky Alert v0.0.3
 * https://github.com/tlongren/jquery-sticky-alert
 *
 * Copyright 2013 Tyler Longren
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * Date: April 13, 2014
 */
(function($){

  $.fn.extend({

    stickyalert: function(options) {

        var defaults = {
            barColor: '#222',
            barFontColor: '#FFF',
            barFontSize: '1.1rem',
            barText: 'I like to work! Hire me!',
            barTextLink: 'http://longren.io/work-with-me/',
        };

        var options = $.extend(defaults, options);

        return this.each(function() {

          if( jQuery.cookie('jquery-sticky-alert-closed') === 'closed' ){

            $('
' + options.barText + '✖
').appendTo(this);

            $(".alert-box").delegate("a.close", "click", function(event) {

              event.preventDefault();

              $(this).closest(".alert-box").fadeOut(function(event){

                $(this).remove();

                var date = new Date();

                var minutes = 9988;

                date.setTime(date.getTime() + (minutes * 60 * 1000));

                $.cookie('jquery-sticky-alert-closed', 'closed', { path: '/', expires: date });

              });

            });

          }

        });
      }
  });

})(jQuery);<commit_msg>Make it work so I can go to sleep.<commit_after>/*!
 * jQuery Sticky Alert v0.0.3
 * https://github.com/tlongren/jquery-sticky-alert
 *
 * Copyright 2013 Tyler Longren
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * Date: April 13, 2014
 */
(function($){

  $.fn.extend({

    stickyalert: function(options) {

        var defaults = {
            barColor: '#222',
            barFontColor: '#FFF',
            barFontSize: '1.1rem',
            barText: 'I like to work! Hire me!',
            barTextLink: 'http://longren.io/work-with-me/',
        };

        var options = $.extend(defaults, options);

        return this.each(function() {

          /*if( jQuery.cookie('jquery-sticky-alert-closed') === 'closed' ){*/

            $('
' + options.barText + '✖
').appendTo(this);

            $(".alert-box").delegate("a.close", "click", function(event) {

              event.preventDefault();

              $(this).closest(".alert-box").fadeOut(function(event){

                $(this).remove();

                var date = new Date();

                var minutes = 9988;

                date.setTime(date.getTime() + (minutes * 60 * 1000));

                $.cookie('jquery-sticky-alert-closed', 'closed', { path: '/', expires: date });

              });

            });

          /*}*/

        });
      }
  });

})(jQuery);<|endoftext|>


<commit_before>var React = require('react');
var cloneWithProps = React.addons.cloneWithProps;
import PropTypes from 'prop-types';

function isNodeInRoot(node, root) {
  while (node) {
    if (node === root) {
      return true;
    }
    node = node.parentNode;
  }

  return false;
}

var Selectable = React.createClass({

  /**
   * This is stored outside the state, so that setting it doesn't
   * rerender the app during selection. shouldComponentUpdate() could work around that.
   * @type {Object}
   */
  _mouseDownData: null,

  /**
   * @return {Object}
   */
  getInitialState: function() {
    return {
      isBoxSelecting: false,
      persist: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: []
    };
  },

  /**
   * @return {Object}
   */
  getDefaultProps: function() {
    return {
      onSelection: function () {},
      component: 'div',
      distance: 0,
      tolerance: 0,
      globalMouse: false,
      disableSingleSelection: false
    };
  },

  /**
   * Attach global event listeners
   */
  componentDidMount: function() {
    var node = this.getDOMNode();
    node.addEventListener('mousedown', this._mouseDown);
    node.addEventListener('keydown', this._keyListener);
    node.addEventListener('keyup', this._keyListener);
  },

  /**
   * Remove global event listeners
   */
  componentWillUnmount: function() {
    var node = this.getDOMNode();
    node.removeEventListener('mousedown', this._mouseDown);
    node.removeEventListener('keydown', this._keyListener);
    node.removeEventListener('keyup', this._keyListener);
  },

  /**
   * Renders the component
   * @return {ReactComponent}
   */
  render: function() {
    var boxStyle = {
      left: this.state.boxLeft,
      top: this.state.boxTop,
      width: this.state.boxWidth,
      height: this.state.boxHeight,
      zIndex: 9000,
      position: 'absolute',
      cursor: 'default'
    };
    var spanStyle = {
      backgroundColor: 'transparent',
      border: '1px dashed #999',
      width: '100%',
      height: '100%',
      float: 'left'
    };

    return (
      <this.props.component {...this.props}>
    {this.state.isBoxSelecting &&

    }
    {React.Children.map(this.props.children, function (child, i) {
      return cloneWithProps(child, {
        key: child.key || i,
        ref: 'selectable_'+child.key,
        selected: this.state.selectedItems.indexOf(child.key) > -1
      })
    }.bind(this))}
    </this.props.component>

    );
  },

  /**
   * Called while moving the mouse with the button down. Changes the boundaries
   * of the selection box
   */
  _openSelector: function (e) {
    var w = Math.abs(this._mouseDownData.initialW - e.pageX);
    var h = Math.abs(this._mouseDownData.initialH - e.pageY);

    this.setState({
      isBoxSelecting: true,
      boxWidth: w,
      boxHeight: h,
      boxLeft: Math.min(e.pageX, this._mouseDownData.initialW),
      boxTop: Math.min(e.pageY, this._mouseDownData.initialH),
      selectedItems: this.state.persist ? this.state.selectedItems : []
    });
  },

  /**
   * Called when a user presses the mouse button. Determines if a select box should
   * be added, and if so, attach event listeners
   */
  _mouseDown: function (e) {
    var node = this.getDOMNode(),collides, offsetData, distanceData;

    document.addEventListener('mouseup', this._mouseUp);

    // Right clicks
    if(e.which === 3 || e.button === 2) return;

    if(!isNodeInRoot(e.target, node) && !this.props.globalMouse) {
      distanceData = this._getDistanceData();
      offsetData = this._getBoundsForNode(node);
      collides = this._objectsCollide(
        {
          top: offsetData.top - distanceData.top,
          left: offsetData.left - distanceData.left,
          bottom: offsetData.offsetHeight + distanceData.bottom,
          right: offsetData.offsetWidth + distanceData.right
        },
        {
          top: e.pageY,
          left: e.pageX,
          offsetWidth: 0,
          offsetHeight: 0
        }
      );

      if(!collides) return;
    }

    this._mouseDownData = {
      boxLeft: e.pageX,
      boxTop: e.pageY,
      initialW: e.pageX,
      initialH: e.pageY
    };

    if (this.props.strictSelection){
        if (e.target.getAttribute('data-reactid') !== node.getAttribute('data-reactid')) {
            return
        }
    }

    e.preventDefault();

    this.setState({selectedItems: []});
    document.addEventListener('mousemove', this._openSelector);
  },

  /**
   * Called when the user has completed selection
   */
  _mouseUp: function (e) {

    document.removeEventListener('mousemove', this._openSelector);
    document.removeEventListener('mouseup', this._mouseUp);

    if(!this._mouseDownData) return;

    var inRoot = isNodeInRoot(e.target, this.getDOMNode());
    var click = (e.pageX === this._mouseDownData.initialW && e.pageY === this._mouseDownData.initialH);

    // Clicks outside the Selectable node should reset clear selection
    if(click && !inRoot) {
      this.setState({
        selectedItems: []
      });
      return this.props.onSelection([]);
    }

    if (!this.props.disableSingleSelection) {
      // Handle selection of a single element
      if(click && inRoot) {
        return this._selectElement(e.pageX, e.pageY)
      }
    }

    // User drag-clicked in the Selectable area
    if(!click && inRoot) {
      return this._selectElements(e);
    }
  },

  /**
   * Selects a single child, given the x/y coords of the mouse
   * @param  {int} x
   * @param  {int} y
   */
  _selectElement: function (x, y) {
    var currentItems = this.state.selectedItems,
      index;

    React.Children.forEach(this.props.children, function (child) {
      var node = this.refs['selectable_'+child.key].getDOMNode();
      var collision = this._objectsCollide(
        node,
        {
          top: y,
          left: x,
          offsetWidth: 0,
          offsetHeight: 0
        },
        this.props.tolerance
      );

      if(collision) {
        index = currentItems.indexOf(child.key);
        if(this.state.persist) {
          if(index > -1) {
            currentItems.splice(index, 1);
          }
          else {
            currentItems.push(child.key);
          }
        }
        else {
          currentItems = [child.key];
        }
      }

    }.bind(this));

    this._mouseDownData = null;

    this.setState({
      isBoxSelecting: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: currentItems
    });

    this.props.onSelection(currentItems);
  },

  /**
   * Selects multiple children given x/y coords of the mouse
   */
  _selectElements: function (e) {
    var currentItems = this.state.selectedItems;

    if (this.props.strictSelection && !this.state.isBoxSelecting){
      return
    }

    this._mouseDownData = null;

    React.Children.forEach(this.props.children, function (child) {
      var collision = this._objectsCollide(
        this.refs.selectbox.getDOMNode(),
        this.refs['selectable_'+child.key].getDOMNode(),
        this.props.tolerance
      );
      if(collision) {
        currentItems.push(child.key);
      }

    }.bind(this));

    this.setState({
      isBoxSelecting: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: currentItems
    });

    this.props.onSelection(currentItems);

  },

  /**
   * Given a node, get everything needed to calculate its boundaries
   * @param  {HTMLElement} node
   * @return {Object}
   */
  _getBoundsForNode: function (node) {
    var rect = node.getBoundingClientRect();

    return {
      top: rect.top+document.body.scrollTop,
      left: rect.left+document.body.scrollLeft,
      offsetWidth: node.offsetWidth,
      offsetHeight: node.offsetHeight
    };
  },

  /**
   * Resolve the disance prop from either an Int or an Object
   * @return {Object}
   */
  _getDistanceData: function () {
    var distance = this.props.distance;

    if(!distance) {
      distance = 0;
    }

    if(typeof distance !== 'object') {
      return {
        top: distance,
        left: distance,
        right: distance,
        bottom: distance
      };
    }

    return distance;
  },

  /**
   * Given two objects containing "top", "left", "offsetWidth" and "offsetHeight"
   * properties, determine if they collide.
   * @param  {Object|HTMLElement} a
   * @param  {Object|HTMLElement} b
   * @return {bool}
   */
  _objectsCollide: function (a, b, tolerance) {
    var aObj = (a instanceof HTMLElement) ? this._getBoundsForNode(a) : a,
      bObj = (b instanceof HTMLElement) ? this._getBoundsForNode(b) : b;

    return this._coordsCollide(
      aObj.top,
      aObj.left,
      bObj.top,
      bObj.left,
      aObj.offsetWidth,
      aObj.offsetHeight,
      bObj.offsetWidth,
      bObj.offsetHeight,
      tolerance
    );
  },

  /**
   * Given offsets, widths, and heights of two objects, determine if they collide (overlap).
   * @param  {int} aTop    The top position of the first object
   * @param  {int} aLeft   The left position of the first object
   * @param  {int} bTop    The top position of the second object
   * @param  {int} bLeft   The left position of the second object
   * @param  {int} aWidth  The width of the first object
   * @param  {int} aHeight The height of the first object
   * @param  {int} bWidth  The width of the second object
   * @param  {int} bHeight The height of the second object
   * @return {bool}
   */
  _coordsCollide: function (aTop, aLeft, bTop, bLeft, aWidth, aHeight, bWidth, bHeight, tolerance) {
    if(typeof tolerance === 'undefined') {
      tolerance = 0;
    }

    return !(
      // 'a' bottom doesn't touch 'b' top
      ( (aTop + aHeight - tolerance ) < bTop ) ||
        // 'a' top doesn't touch 'b' bottom
      ( (aTop + tolerance) > (bTop + bHeight) ) ||
        // 'a' right doesn't touch 'b' left
      ( (aLeft + aWidth - tolerance) < bLeft ) ||
        // 'a' left doesn't touch 'b' right
      ( (aLeft + tolerance) > (bLeft + bWidth) )
    );
  },

  /**
   * Listens for the meta key
   */
  _keyListener: function (e) {
    this.setState({
      persist: !!e.metaKey
    });
  }
});

Selectable.propTypes = {
  /**
    * Event that will fire when items are selected. Passes an array of keys
    */
  onSelection: PropTypes.func,

  /**
    * The component that will represent the Selectable DOM node
    */
  component: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.string
  ]),

  /**
    * Expands the boundary of the selectable area. It can be an integer, which
    * applies to all sides, or an object containing "top", "bottom", "left",
    * and "right" values for custom distance on each side
    */
  distance: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.number
  ]),

  /**
    * Amount of forgiveness an item will offer to the selectbox before registering
    * a selection, i.e. if only 1px of the item is in the selection, it shouldn't be
    * included.
    */
  tolerance: PropTypes.number,

  /**
    * If true, a click-and-drag with the mouse will generate a select box anywhere
    * in the document.
    */
  globalMouse: PropTypes.bool,

  /**
    * If true, a click will not generate event onSelection
    */
  disableSingleSelection: PropTypes.bool,

  /**
    * If true, select will not start selection when you click on child elements.
    */
  strictSelection: PropTypes.bool
};

module.exports = Selectable;<commit_msg>Changes required for React 16 upgrade<commit_after>var React = require('react');
import PropTypes from 'prop-types';

function isNodeInRoot(node, root) {
  while (node) {
    if (node === root) {
      return true;
    }
    node = node.parentNode;
  }

  return false;
}

class Selectable extends React.Component {
  constructor(props) {
    super(props);
    this._mouseDownData = null;

    this.state = {
      isBoxSelecting: false,
      persist: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: []
    };
  }

  /**
   * Attach global event listeners
   */
  componentDidMount() {
    var node = this.getDOMNode();
    node.addEventListener('mousedown', this._mouseDown);
    node.addEventListener('keydown', this._keyListener);
    node.addEventListener('keyup', this._keyListener);
  };

  /**
   * Remove global event listeners
   */
  componentWillUnmount() {
    var node = this.getDOMNode();
    node.removeEventListener('mousedown', this._mouseDown);
    node.removeEventListener('keydown', this._keyListener);
    node.removeEventListener('keyup', this._keyListener);
  };

  /**
   * Renders the component
   * @return {ReactComponent}
   */
  render() {
    var boxStyle = {
      left: this.state.boxLeft,
      top: this.state.boxTop,
      width: this.state.boxWidth,
      height: this.state.boxHeight,
      zIndex: 9000,
      position: 'absolute',
      cursor: 'default'
    };
    var spanStyle = {
      backgroundColor: 'transparent',
      border: '1px dashed #999',
      width: '100%',
      height: '100%',
      float: 'left'
    };

    return (
      <this.props.component {...this.props}>
    {this.state.isBoxSelecting &&

    }
    {React.Children.map(this.props.children, function (child, i) {
      return React.cloneElement(child, {
        key: child.key || i,
        ref: 'selectable_'+child.key,
        selected: this.state.selectedItems.indexOf(child.key) > -1
      })
    }.bind(this))}
    </this.props.component>

    );
  }

  /**
   * Called while moving the mouse with the button down. Changes the boundaries
   * of the selection box
   */
  _openSelector(e) {
    var w = Math.abs(this._mouseDownData.initialW - e.pageX);
    var h = Math.abs(this._mouseDownData.initialH - e.pageY);

    this.setState({
      isBoxSelecting: true,
      boxWidth: w,
      boxHeight: h,
      boxLeft: Math.min(e.pageX, this._mouseDownData.initialW),
      boxTop: Math.min(e.pageY, this._mouseDownData.initialH),
      selectedItems: this.state.persist ? this.state.selectedItems : []
    });
  }

  /**
   * Called when a user presses the mouse button. Determines if a select box should
   * be added, and if so, attach event listeners
   */
  _mouseDown(e) {
    var node = this.getDOMNode(),collides, offsetData, distanceData;

    document.addEventListener('mouseup', this._mouseUp);

    // Right clicks
    if(e.which === 3 || e.button === 2) return;

    if(!isNodeInRoot(e.target, node) && !this.props.globalMouse) {
      distanceData = this._getDistanceData();
      offsetData = this._getBoundsForNode(node);
      collides = this._objectsCollide(
        {
          top: offsetData.top - distanceData.top,
          left: offsetData.left - distanceData.left,
          bottom: offsetData.offsetHeight + distanceData.bottom,
          right: offsetData.offsetWidth + distanceData.right
        },
        {
          top: e.pageY,
          left: e.pageX,
          offsetWidth: 0,
          offsetHeight: 0
        }
      );

      if(!collides) return;
    }

    this._mouseDownData = {
      boxLeft: e.pageX,
      boxTop: e.pageY,
      initialW: e.pageX,
      initialH: e.pageY
    };

    if (this.props.strictSelection){
        if (e.target.getAttribute('data-reactid') !== node.getAttribute('data-reactid')) {
            return
        }
    }

    e.preventDefault();

    this.setState({selectedItems: []});
    document.addEventListener('mousemove', this._openSelector);
  }

  /**
   * Called when the user has completed selection
   */
  _mouseUp(e) {

    document.removeEventListener('mousemove', this._openSelector);
    document.removeEventListener('mouseup', this._mouseUp);

    if(!this._mouseDownData) return;

    var inRoot = isNodeInRoot(e.target, this.getDOMNode());
    var click = (e.pageX === this._mouseDownData.initialW && e.pageY === this._mouseDownData.initialH);

    // Clicks outside the Selectable node should reset clear selection
    if(click && !inRoot) {
      this.setState({
        selectedItems: []
      });
      return this.props.onSelection([]);
    }

    if (!this.props.disableSingleSelection) {
      // Handle selection of a single element
      if(click && inRoot) {
        return this._selectElement(e.pageX, e.pageY)
      }
    }

    // User drag-clicked in the Selectable area
    if(!click && inRoot) {
      return this._selectElements(e);
    }
  }

  /**
   * Selects a single child, given the x/y coords of the mouse
   * @param  {int} x
   * @param  {int} y
   */
  _selectElement(x, y) {
    var currentItems = this.state.selectedItems,
      index;

    React.Children.forEach(this.props.children, function (child) {
      var node = this.refs['selectable_'+child.key].getDOMNode();
      var collision = this._objectsCollide(
        node,
        {
          top: y,
          left: x,
          offsetWidth: 0,
          offsetHeight: 0
        },
        this.props.tolerance
      );

      if(collision) {
        index = currentItems.indexOf(child.key);
        if(this.state.persist) {
          if(index > -1) {
            currentItems.splice(index, 1);
          }
          else {
            currentItems.push(child.key);
          }
        }
        else {
          currentItems = [child.key];
        }
      }

    }.bind(this));

    this._mouseDownData = null;

    this.setState({
      isBoxSelecting: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: currentItems
    });

    this.props.onSelection(currentItems);
  }

  /**
   * Selects multiple children given x/y coords of the mouse
   */
  _selectElements(e) {
    var currentItems = this.state.selectedItems;

    if (this.props.strictSelection && !this.state.isBoxSelecting){
      return
    }

    this._mouseDownData = null;

    React.Children.forEach(this.props.children, function (child) {
      var collision = this._objectsCollide(
        this.refs.selectbox.getDOMNode(),
        this.refs['selectable_'+child.key].getDOMNode(),
        this.props.tolerance
      );
      if(collision) {
        currentItems.push(child.key);
      }

    }.bind(this));

    this.setState({
      isBoxSelecting: false,
      boxWidth: 0,
      boxHeight: 0,
      selectedItems: currentItems
    });

    this.props.onSelection(currentItems);

  }

  /**
   * Given a node, get everything needed to calculate its boundaries
   * @param  {HTMLElement} node
   * @return {Object}
   */
  _getBoundsForNode(node) {
    var rect = node.getBoundingClientRect();

    return {
      top: rect.top+document.body.scrollTop,
      left: rect.left+document.body.scrollLeft,
      offsetWidth: node.offsetWidth,
      offsetHeight: node.offsetHeight
    };
  }

  /**
   * Resolve the disance prop from either an Int or an Object
   * @return {Object}
   */
  _getDistanceData() {
    var distance = this.props.distance;

    if(!distance) {
      distance = 0;
    }

    if(typeof distance !== 'object') {
      return {
        top: distance,
        left: distance,
        right: distance,
        bottom: distance
      };
    }

    return distance;
  }

  /**
   * Given two objects containing "top", "left", "offsetWidth" and "offsetHeight"
   * properties, determine if they collide.
   * @param  {Object|HTMLElement} a
   * @param  {Object|HTMLElement} b
   * @return {bool}
   */
  _objectsCollide(a, b, tolerance) {
    var aObj = (a instanceof HTMLElement) ? this._getBoundsForNode(a) : a,
      bObj = (b instanceof HTMLElement) ? this._getBoundsForNode(b) : b;

    return this._coordsCollide(
      aObj.top,
      aObj.left,
      bObj.top,
      bObj.left,
      aObj.offsetWidth,
      aObj.offsetHeight,
      bObj.offsetWidth,
      bObj.offsetHeight,
      tolerance
    );
  }

  /**
   * Given offsets, widths, and heights of two objects, determine if they collide (overlap).
   * @param  {int} aTop    The top position of the first object
   * @param  {int} aLeft   The left position of the first object
   * @param  {int} bTop    The top position of the second object
   * @param  {int} bLeft   The left position of the second object
   * @param  {int} aWidth  The width of the first object
   * @param  {int} aHeight The height of the first object
   * @param  {int} bWidth  The width of the second object
   * @param  {int} bHeight The height of the second object
   * @return {bool}
   */
  _coordsCollide(aTop, aLeft, bTop, bLeft, aWidth, aHeight, bWidth, bHeight, tolerance) {
    if(typeof tolerance === 'undefined') {
      tolerance = 0;
    }

    return !(
      // 'a' bottom doesn't touch 'b' top
      ( (aTop + aHeight - tolerance ) < bTop ) ||
        // 'a' top doesn't touch 'b' bottom
      ( (aTop + tolerance) > (bTop + bHeight) ) ||
        // 'a' right doesn't touch 'b' left
      ( (aLeft + aWidth - tolerance) < bLeft ) ||
        // 'a' left doesn't touch 'b' right
      ( (aLeft + tolerance) > (bLeft + bWidth) )
    );
  }

  /**
   * Listens for the meta key
   */
  _keyListener(e) {
    this.setState({
      persist: !!e.metaKey
    });
  }
}

Selectable.propTypes = {
  /**
    * Event that will fire when items are selected. Passes an array of keys
    */
  onSelection: PropTypes.func,

  /**
    * The component that will represent the Selectable DOM node
    */
  component: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.string
  ]),

  /**
    * Expands the boundary of the selectable area. It can be an integer, which
    * applies to all sides, or an object containing "top", "bottom", "left",
    * and "right" values for custom distance on each side
    */
  distance: PropTypes.oneOfType([
    PropTypes.object,
    PropTypes.number
  ]),

  /**
    * Amount of forgiveness an item will offer to the selectbox before registering
    * a selection, i.e. if only 1px of the item is in the selection, it shouldn't be
    * included.
    */
  tolerance: PropTypes.number,

  /**
    * If true, a click-and-drag with the mouse will generate a select box anywhere
    * in the document.
    */
  globalMouse: PropTypes.bool,

  /**
    * If true, a click will not generate event onSelection
    */
  disableSingleSelection: PropTypes.bool,

  /**
    * If true, select will not start selection when you click on child elements.
    */
  strictSelection: PropTypes.bool
};

Selectable.defaultProps = {
  onSelection: function() {},
  component: 'div',
  distance: 0,
  tolerance: 0,
  globalMouse: false,
  disableSingleSelection: false
};

module.exports = Selectable;<|endoftext|>


<commit_before>import { addClass, elt, rmClass } from "../util/dom"
import { on } from "../util/event"
import { scrollGap, paddingVert } from "../measurement/position_measurement"
import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser"
import { updateHeightsInViewport } from "./update_lines"
import { Delayed } from "../util/misc"

import { setScrollLeft, setScrollTop } from "./scroll_events"

// SCROLLBARS

// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
export function measureForScrollbars(cm) {
  let d = cm.display, gutterW = d.gutters.offsetWidth
  let docH = Math.round(cm.doc.height + paddingVert(cm.display))
  return {
    clientHeight: d.scroller.clientHeight,
    viewHeight: d.wrapper.clientHeight,
    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
    viewWidth: d.wrapper.clientWidth,
    barLeft: cm.options.fixedGutter ? gutterW : 0,
    docHeight: docH,
    scrollHeight: docH + scrollGap(cm) + d.barHeight,
    nativeBarWidth: d.nativeBarWidth,
    gutterWidth: gutterW
  }
}

class NativeScrollbars {
  constructor(place, scroll, cm) {
    this.cm = cm
    let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
    let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
    place(vert); place(horiz)

    on(vert, "scroll", () => {
      if (vert.clientHeight) scroll(vert.scrollTop, "vertical")
    })
    on(horiz, "scroll", () => {
      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal")
    })

    this.checkedZeroWidth = false
    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"
  }

  update(measure) {
    let needsH = measure.scrollWidth > measure.clientWidth + 1
    let needsV = measure.scrollHeight > measure.clientHeight + 1
    let sWidth = measure.nativeBarWidth

    if (needsV) {
      this.vert.style.display = "block"
      this.vert.style.bottom = needsH ? sWidth + "px" : "0"
      let totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
      // A bug in IE8 can cause this value to be negative, so guard it.
      this.vert.firstChild.style.height =
        Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
    } else {
      this.vert.style.display = ""
      this.vert.firstChild.style.height = "0"
    }

    if (needsH) {
      this.horiz.style.display = "block"
      this.horiz.style.right = needsV ? sWidth + "px" : "0"
      this.horiz.style.left = measure.barLeft + "px"
      let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
      this.horiz.firstChild.style.width =
        Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
    } else {
      this.horiz.style.display = ""
      this.horiz.firstChild.style.width = "0"
    }

    if (!this.checkedZeroWidth && measure.clientHeight > 0) {
      if (sWidth == 0) this.zeroWidthHack()
      this.checkedZeroWidth = true
    }

    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
  }

  setScrollLeft(pos) {
    if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos
    if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz)
  }

  setScrollTop(pos) {
    if (this.vert.scrollTop != pos) this.vert.scrollTop = pos
    if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert)
  }

  zeroWidthHack() {
    let w = mac && !mac_geMountainLion ? "12px" : "18px"
    this.horiz.style.height = this.vert.style.width = w
    this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
    this.disableHoriz = new Delayed
    this.disableVert = new Delayed
  }

  enableZeroWidthBar(bar, delay) {
    bar.style.pointerEvents = "auto"
    function maybeDisable() {
      // To find out whether the scrollbar is still visible, we
      // check whether the element under the pixel in the bottom
      // left corner of the scrollbar box is the scrollbar box
      // itself (when the bar is still visible) or its filler child
      // (when the bar is hidden). If it is still visible, we keep
      // it enabled, if it's hidden, we disable pointer events.
      let box = bar.getBoundingClientRect()
      let elt = document.elementFromPoint(box.left + 1, box.bottom - 1)
      if (elt != bar) bar.style.pointerEvents = "none"
      else delay.set(1000, maybeDisable)
    }
    delay.set(1000, maybeDisable)
  }

  clear() {
    let parent = this.horiz.parentNode
    parent.removeChild(this.horiz)
    parent.removeChild(this.vert)
  }
}

class NullScrollbars {
  update() { return {bottom: 0, right: 0} }
  setScrollLeft() {}
  setScrollTop() {}
  clear() {}
}

export function updateScrollbars(cm, measure) {
  if (!measure) measure = measureForScrollbars(cm)
  let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
  updateScrollbarsInner(cm, measure)
  for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
      updateHeightsInViewport(cm)
    updateScrollbarsInner(cm, measureForScrollbars(cm))
    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
  }
}

// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
  let d = cm.display
  let sizes = d.scrollbars.update(measure)

  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"

  if (sizes.right && sizes.bottom) {
    d.scrollbarFiller.style.display = "block"
    d.scrollbarFiller.style.height = sizes.bottom + "px"
    d.scrollbarFiller.style.width = sizes.right + "px"
  } else d.scrollbarFiller.style.display = ""
  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
    d.gutterFiller.style.display = "block"
    d.gutterFiller.style.height = sizes.bottom + "px"
    d.gutterFiller.style.width = measure.gutterWidth + "px"
  } else d.gutterFiller.style.display = ""
}

export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}

export function initScrollbars(cm) {
  if (cm.display.scrollbars) {
    cm.display.scrollbars.clear()
    if (cm.display.scrollbars.addClass)
      rmClass(cm.display.wrapper, cm.display.scrollbars.addClass)
  }

  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => {
    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
    // Prevent clicks in the scrollbars from killing focus
    on(node, "mousedown", () => {
      if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0)
    })
    node.setAttribute("cm-not-content", "true")
  }, (pos, axis) => {
    if (axis == "horizontal") setScrollLeft(cm, pos)
    else setScrollTop(cm, pos)
  }, cm)
  if (cm.display.scrollbars.addClass)
    addClass(cm.display.wrapper, cm.display.scrollbars.addClass)
}
<commit_msg>Improve zero-width-scrollbar pointer-event hack<commit_after>import { addClass, elt, rmClass } from "../util/dom"
import { on } from "../util/event"
import { scrollGap, paddingVert } from "../measurement/position_measurement"
import { ie, ie_version, mac, mac_geMountainLion } from "../util/browser"
import { updateHeightsInViewport } from "./update_lines"
import { Delayed } from "../util/misc"

import { setScrollLeft, setScrollTop } from "./scroll_events"

// SCROLLBARS

// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
export function measureForScrollbars(cm) {
  let d = cm.display, gutterW = d.gutters.offsetWidth
  let docH = Math.round(cm.doc.height + paddingVert(cm.display))
  return {
    clientHeight: d.scroller.clientHeight,
    viewHeight: d.wrapper.clientHeight,
    scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
    viewWidth: d.wrapper.clientWidth,
    barLeft: cm.options.fixedGutter ? gutterW : 0,
    docHeight: docH,
    scrollHeight: docH + scrollGap(cm) + d.barHeight,
    nativeBarWidth: d.nativeBarWidth,
    gutterWidth: gutterW
  }
}

class NativeScrollbars {
  constructor(place, scroll, cm) {
    this.cm = cm
    let vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar")
    let horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar")
    place(vert); place(horiz)

    on(vert, "scroll", () => {
      if (vert.clientHeight) scroll(vert.scrollTop, "vertical")
    })
    on(horiz, "scroll", () => {
      if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal")
    })

    this.checkedZeroWidth = false
    // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
    if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"
  }

  update(measure) {
    let needsH = measure.scrollWidth > measure.clientWidth + 1
    let needsV = measure.scrollHeight > measure.clientHeight + 1
    let sWidth = measure.nativeBarWidth

    if (needsV) {
      this.vert.style.display = "block"
      this.vert.style.bottom = needsH ? sWidth + "px" : "0"
      let totalHeight = measure.viewHeight - (needsH ? sWidth : 0)
      // A bug in IE8 can cause this value to be negative, so guard it.
      this.vert.firstChild.style.height =
        Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"
    } else {
      this.vert.style.display = ""
      this.vert.firstChild.style.height = "0"
    }

    if (needsH) {
      this.horiz.style.display = "block"
      this.horiz.style.right = needsV ? sWidth + "px" : "0"
      this.horiz.style.left = measure.barLeft + "px"
      let totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0)
      this.horiz.firstChild.style.width =
        Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px"
    } else {
      this.horiz.style.display = ""
      this.horiz.firstChild.style.width = "0"
    }

    if (!this.checkedZeroWidth && measure.clientHeight > 0) {
      if (sWidth == 0) this.zeroWidthHack()
      this.checkedZeroWidth = true
    }

    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
  }

  setScrollLeft(pos) {
    if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos
    if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz")
  }

  setScrollTop(pos) {
    if (this.vert.scrollTop != pos) this.vert.scrollTop = pos
    if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert, "vert")
  }

  zeroWidthHack() {
    let w = mac && !mac_geMountainLion ? "12px" : "18px"
    this.horiz.style.height = this.vert.style.width = w
    this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none"
    this.disableHoriz = new Delayed
    this.disableVert = new Delayed
  }

  enableZeroWidthBar(bar, delay, type) {
    bar.style.pointerEvents = "auto"
    function maybeDisable() {
      // To find out whether the scrollbar is still visible, we
      // check whether the element under the pixel in the bottom
      // right corner of the scrollbar box is the scrollbar box
      // itself (when the bar is still visible) or its filler child
      // (when the bar is hidden). If it is still visible, we keep
      // it enabled, if it's hidden, we disable pointer events.
      let box = bar.getBoundingClientRect()
      let elt = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
          : document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1)
      if (elt != bar) bar.style.pointerEvents = "none"
      else delay.set(1000, maybeDisable)
    }
    delay.set(1000, maybeDisable)
  }

  clear() {
    let parent = this.horiz.parentNode
    parent.removeChild(this.horiz)
    parent.removeChild(this.vert)
  }
}

class NullScrollbars {
  update() { return {bottom: 0, right: 0} }
  setScrollLeft() {}
  setScrollTop() {}
  clear() {}
}

export function updateScrollbars(cm, measure) {
  if (!measure) measure = measureForScrollbars(cm)
  let startWidth = cm.display.barWidth, startHeight = cm.display.barHeight
  updateScrollbarsInner(cm, measure)
  for (let i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
    if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
      updateHeightsInViewport(cm)
    updateScrollbarsInner(cm, measureForScrollbars(cm))
    startWidth = cm.display.barWidth; startHeight = cm.display.barHeight
  }
}

// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
  let d = cm.display
  let sizes = d.scrollbars.update(measure)

  d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"
  d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"
  d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent"

  if (sizes.right && sizes.bottom) {
    d.scrollbarFiller.style.display = "block"
    d.scrollbarFiller.style.height = sizes.bottom + "px"
    d.scrollbarFiller.style.width = sizes.right + "px"
  } else d.scrollbarFiller.style.display = ""
  if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
    d.gutterFiller.style.display = "block"
    d.gutterFiller.style.height = sizes.bottom + "px"
    d.gutterFiller.style.width = measure.gutterWidth + "px"
  } else d.gutterFiller.style.display = ""
}

export let scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}

export function initScrollbars(cm) {
  if (cm.display.scrollbars) {
    cm.display.scrollbars.clear()
    if (cm.display.scrollbars.addClass)
      rmClass(cm.display.wrapper, cm.display.scrollbars.addClass)
  }

  cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](node => {
    cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller)
    // Prevent clicks in the scrollbars from killing focus
    on(node, "mousedown", () => {
      if (cm.state.focused) setTimeout(() => cm.display.input.focus(), 0)
    })
    node.setAttribute("cm-not-content", "true")
  }, (pos, axis) => {
    if (axis == "horizontal") setScrollLeft(cm, pos)
    else setScrollTop(cm, pos)
  }, cm)
  if (cm.display.scrollbars.addClass)
    addClass(cm.display.wrapper, cm.display.scrollbars.addClass)
}
<|endoftext|>


<commit_before>const { messages } = require('./stylelint-plugins/kaliber')
const stylelint = require('stylelint')

// patch in order to add support for filenames to tape
const originalLint = stylelint.lint.bind(stylelint)
stylelint.lint = function lint({ code, ...otherOptions }) {
  const options = (typeof code === 'object')
    ? { code: code.source, codeFilename: code.filename }
    : { code }
  return originalLint({ ...options, ...otherOptions })
}

function message(key) {
  const x = messages[key]
  return x || `programming error, message with key '${key}' not found`
}

function createMessages(key, values) {
  const x = messages[key]
  return values.map(x)
}

// TODO: add @media query tests
module.exports = {
  'kaliber/valid-stacking-context-in-root': [
    {
      source: '.bad { z-index: 0; }',
      warnings: [message('root - z-index without position relative')]
    },
    {
      source: '.bad { position: relative; z-index: 1; }',
      warnings: [message('root - z-index not 0')]
    },
    {
      source: `
        .bad {
          @media x {
            z-index: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: [message('root - z-index without position relative')]
      },
    { source: '.good { position: relative; z-index: 0; }', warnings: 0 },
    {
      source: `
        .good {
          position: relative;
          @media x {
            z-index: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      source: `
        .good {
          @media x {
            z-index: 0;
            position: relative;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
  ],
  'kaliber/require-stacking-context-in-parent': [
    {
      source: '.bad { & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    {
      source: '.bad { position: relative; & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    {
      source: '.bad { z-index: 0; & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    { source: '.good { position: relative; z-index: 0; & > .test { z-index: 1; } }', warnings: 0 },
  ],
  'kaliber/no-layout-related-props-in-root': [
    {
      source: `
        .bad {
          width: 100%; height: 100%;
          position: absolute;
          top: 0; right: 0; bottom: 0; left: 0;
          margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
          flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
        }
      `.replace(/        /g, ''),
      warnings: createMessages('root - no layout related props', [
        'width', 'height',
        'position: absolute',
        'top', 'right', 'bottom', 'left',
        'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
        'flex', 'flex-grow', 'flex-shrink', 'flex-basis',
      ])
    },
    {
      source: '.bad { width: 10px; height: 10px; }',
      warnings: createMessages('root - no layout related props', ['width', 'height'])
    },
    {
      source: '.bad { width: 10% !important; height: 10% !important; }',
      warnings: createMessages('root - no layout related props', ['width', 'height'])
    },
    {
      source: `
        .good {
          & > .test {
            width: 100%; height: 100%;
            position: absolute;
            top: 0; right: 0; bottom: 0; left: 0;
            margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      title: 'allow some layout related props in root in reset.css',
      source: {
        filename: 'reset.css',
        source: `
          div {
            width: 100%;
            margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
          }
        `.replace(/        /g, ''),
      },
      warnings: 0
    },
    {
      title: 'prevent some layout related props in root in reset.css',
      source: {
        filename: 'reset.css',
        source: `
          div {
            height: 100%;
            position: absolute;
            top: 0; right: 0; bottom: 0; left: 0;
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
          }
        `.replace(/        /g, ''),
      },
      warnings: createMessages('root - no layout related props', [
        'height',
        'position: absolute',
        'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
      ])
    },
    { source: '.good { width: 10px !important; height: 10px !important; }', warnings: 0 },
    { source: '.good { width: 10em !important; height: 10em !important; }', warnings: 0 },
    { source: '.good { width: 10rem !important; height: 10rem !important; }', warnings: 0 },
    { source: '.good { z-index: 0; position: relative; }', warnings: 0 },
    { source: '.good { position: relative; & > .test { position: absolute; } }', warnings: 0 },
    { source: '.good { position: relative; z-index: 0; & > .test { position: absolute; z-index: 1; } }', warnings: 0 },
    { source: '.good { &::before { position: absolute; } }', warnings: 0 },
  ],
  'kaliber/no-double-nesting': [
    {
      source: '.bad { & > .test1 { & > .test2 { } } }',
      warnings: [message('nested - no double nesting')]
    },
    { source: '.good { & > .test { } }', warnings: 0 },
    { source: '.good { & > .test { &:not(:last-child) { } } }', warnings: 0 },
  ],
  'kaliber/absolute-has-relative-parent': [
    {
      source: '.bad { & > .test { position: absolute; } }',
      warnings: [message('nested - absolute has relative parent')]
    },
    { source: '.good { position: relative; & > .test { position: absolute; } }'}
  ],
  'kaliber/only-layout-related-props-in-nested': [
    {
      source: '.bad { & > .test { padding: 100px; } }',
      warnings: [message('nested - only layout related props in nested')('padding')]
    },
    { source: '.good { & > .test { width: 100%; } }', warnings: 0 },
    { source: '.good { padding: 100px; }', warnings: 0 },
    { source: `.good { &::before { content: ''; color: back; } }`, warnings: 0 },
  ],
  'kaliber/no-component-class-name-in-nested': [
    {
      source: '.bad { & > .componentTest { } }',
      warnings: [message('nested - no component class name in nested')('componentTest')]
    },
    { source: '.componentGood { & > .test { } }', warnings: 0 },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/no-child-selectors-in-root': [
    {
      source: '.bad > .test { }',
      warnings: [message('root - no child selectors')]
    },
    { source: '.good { & > .test { } }', warnings: 0 }
  ],
  'kaliber/no-double-child-selectors-in-nested': [
    {
      source: '.bad { & > .one > .two { } }',
      warnings: [message('nested - no double child selectors')]
    },
    {
      source: `
        .good { & > .one { } }

        .one { & > .two { } }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      source: '.bad { & > .test::after { } }',
      warnings: [message('nested - no double child selectors')]
    },
    {
      source: `
        .good { & > .one { } }

        .one { &::after { } }
      `.replace(/        /g, ''),
      warnings: 0
    },
    { source: '.good { & > *:not(:first-child) { } }', warnings: 0 },
  ],
  'kaliber/no-child-tag-selectors': [
    {
      source: '.bad { & > div { } }',
      warnings: [message('nested - no child element selectors')]
    },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/only-direct-child-selectors': [
    {
      source: '.bad .test { }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad { & .test { } }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad { & > .test .one { } }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad + .test { }',
      warnings: [message('only direct child selectors')('+')]
    },
    {
      source: '.bad { & + * { } }',
      warnings: [message('only direct child selectors')('+')]
    },
    { source: '.good { &.test { } }', warnings: 0 },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/valid-flex-context-in-root': [
    {
      source: `
        .bad {
          & > .test {
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0; order: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: createMessages('nested - require display flex in parent', [
        'flex', 'flex-grow', 'flex-shrink', 'flex-basis', 'order'
      ])
    },
    {
      source: `
        .good {
          display: flex;

          & > .test {
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0; order: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    }
  ],
  'kaliber/media-no-child': [
    {
      source: `
        .bad {
          @media x {
            & > {
              width: 10px;
            }
          }
        }
      `.replace(/        /g, ''),
      warnings: ['?']
    },
    {
      source: `
        .good {
          & > {
            @media x {
              width: 10px;
            }
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    }
  ],
  'kaliber/only-element-selectors-in-reset': [
    {
      title: 'invalid - no tag in selector',
      source: { filename: 'other.css', source: `div { }` },
      warnings: ['?']
    },
    {
      title: 'valid - allow tag in reset.css',
      source: { filename: 'reset.css', source: `div { }` },
      warnings: 0
    }
  ],
  'kaliber/no-media-in-root': [
    {
      source: `.bad { } @media x { }`,
      warnings: ['?']
    },
    {
      source: `.good { @media x { } }`,
      warnings: 0
    }
  ]
}<commit_msg>added titles to reduce noise<commit_after>const { messages } = require('./stylelint-plugins/kaliber')
const stylelint = require('stylelint')

// patch in order to add support for filenames to tape
const originalLint = stylelint.lint.bind(stylelint)
stylelint.lint = function lint({ code, ...otherOptions }) {
  const options = (typeof code === 'object')
    ? { code: code.source, codeFilename: code.filename }
    : { code }
  return originalLint({ ...options, ...otherOptions })
}

function message(key) {
  const x = messages[key]
  return x || `programming error, message with key '${key}' not found`
}

function createMessages(key, values) {
  const x = messages[key]
  return values.map(x)
}

// TODO: add @media query tests
module.exports = {
  'kaliber/valid-stacking-context-in-root': [
    {
      title: "don't allow `z-index` in root without `position: relative`",
      source: '.bad { z-index: 0; }',
      warnings: [message('root - z-index without position relative')]
    },
    {
      title: "└─ take @media into account",
      source: `
        .bad {
          @media x {
            z-index: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: [message('root - z-index without position relative')]
      },
    {
      title: "only allow a `z-index: 0` in root",
      source: '.bad { position: relative; z-index: 1; }',
      warnings: [message('root - z-index not 0')]
    },
    { source: '.good { position: relative; z-index: 0; }', warnings: 0 },
    {
      title: "├─ take @media into account [1]",
      source: `
        .good {
          position: relative;
          @media x {
            z-index: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      title: "└─ take @media into account [2]",
      source: `
        .good {
          @media x {
            z-index: 0;
            position: relative;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
  ],
  'kaliber/require-stacking-context-in-parent': [
    {
      title: "report missing stacking context",
      source: '.bad { & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    {
      title: "report missing stacking context - only `position: relative`",
      source: '.bad { position: relative; & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    {
      title: "report missing stacking context - only `z-index: 0`",
      source: '.bad { z-index: 0; & > .test { z-index: 0; } }',
      warnings: [message('nested - missing stacking context in parent')]
    },
    { source: '.good { position: relative; z-index: 0; & > .test { z-index: 1; } }', warnings: 0 },
  ],
  'kaliber/no-layout-related-props-in-root': [
    {
      title: "report error when using layout related props in root",
      source: `
        .bad {
          width: 100%; height: 100%;
          position: absolute;
          top: 0; right: 0; bottom: 0; left: 0;
          margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
          flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
        }
      `.replace(/        /g, ''),
      warnings: createMessages('root - no layout related props', [
        'width', 'height',
        'position: absolute',
        'top', 'right', 'bottom', 'left',
        'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
        'flex', 'flex-grow', 'flex-shrink', 'flex-basis',
      ])
    },
    {
      title: "report error when using intrinsic size without !important",
      source: '.bad { width: 10px; height: 10px; }',
      warnings: createMessages('root - no layout related props', ['width', 'height'])
    },
    {
      title: "report error when using non intrinsic unit without !important",
      source: '.bad { width: 10% !important; height: 10% !important; }',
      warnings: createMessages('root - no layout related props', ['width', 'height'])
    },
    {
      title: "don't report errors when layout related props are used in child",
      source: `
        .good {
          & > .test {
            width: 100%; height: 100%;
            position: absolute;
            top: 0; right: 0; bottom: 0; left: 0;
            margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      title: 'allow some layout related props in root in reset.css',
      source: {
        filename: 'reset.css',
        source: `
          div {
            width: 100%;
            margin: 0; margin-top: 0; margin-right: 0; margin-bottom: 0; margin-left: 0;
          }
        `.replace(/        /g, ''),
      },
      warnings: 0
    },
    {
      title: 'prevent some layout related props in root in reset.css',
      source: {
        filename: 'reset.css',
        source: `
          div {
            height: 100%;
            position: absolute;
            top: 0; right: 0; bottom: 0; left: 0;
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0;
          }
        `.replace(/        /g, ''),
      },
      warnings: createMessages('root - no layout related props', [
        'height',
        'position: absolute',
        'margin', 'margin-top', 'margin-right', 'margin-bottom', 'margin-left',
      ])
    },
    { source: '.good { width: 10px !important; height: 10px !important; }', warnings: 0 },
    { source: '.good { width: 10em !important; height: 10em !important; }', warnings: 0 },
    { source: '.good { width: 10rem !important; height: 10rem !important; }', warnings: 0 },
    { source: '.good { z-index: 0; position: relative; }', warnings: 0 },
    { source: '.good { position: relative; & > .test { position: absolute; } }', warnings: 0 },
    { source: '.good { position: relative; z-index: 0; & > .test { position: absolute; z-index: 1; } }', warnings: 0 },
    { source: '.good { &::before { position: absolute; } }', warnings: 0 },
  ],
  'kaliber/no-double-nesting': [
    {
      source: '.bad { & > .test1 { & > .test2 { } } }',
      warnings: [message('nested - no double nesting')]
    },
    { source: '.good { & > .test { } }', warnings: 0 },
    { source: '.good { & > .test { &:not(:last-child) { } } }', warnings: 0 },
  ],
  'kaliber/absolute-has-relative-parent': [
    {
      source: '.bad { & > .test { position: absolute; } }',
      warnings: [message('nested - absolute has relative parent')]
    },
    { source: '.good { position: relative; & > .test { position: absolute; } }'}
  ],
  'kaliber/only-layout-related-props-in-nested': [
    {
      source: '.bad { & > .test { padding: 100px; } }',
      warnings: [message('nested - only layout related props in nested')('padding')]
    },
    { source: '.good { & > .test { width: 100%; } }', warnings: 0 },
    { source: '.good { padding: 100px; }', warnings: 0 },
    { source: `.good { &::before { content: ''; color: back; } }`, warnings: 0 },
  ],
  'kaliber/no-component-class-name-in-nested': [
    {
      source: '.bad { & > .componentTest { } }',
      warnings: [message('nested - no component class name in nested')('componentTest')]
    },
    { source: '.componentGood { & > .test { } }', warnings: 0 },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/no-child-selectors-in-root': [
    {
      source: '.bad > .test { }',
      warnings: [message('root - no child selectors')]
    },
    { source: '.good { & > .test { } }', warnings: 0 }
  ],
  'kaliber/no-double-child-selectors-in-nested': [
    {
      source: '.bad { & > .one > .two { } }',
      warnings: [message('nested - no double child selectors')]
    },
    {
      title: 'correctly nested',
      source: `
        .good { & > .one { } }

        .one { & > .two { } }
      `.replace(/        /g, ''),
      warnings: 0
    },
    {
      source: '.bad { & > .test::after { } }',
      warnings: [message('nested - no double child selectors')]
    },
    {
      title: 'correctly nested pseudo element',
      source: `
        .good { & > .one { } }

        .one { &::after { } }
      `.replace(/        /g, ''),
      warnings: 0
    },
    { source: '.good { & > *:not(:first-child) { } }', warnings: 0 },
  ],
  'kaliber/no-child-tag-selectors': [
    {
      source: '.bad { & > div { } }',
      warnings: [message('nested - no child element selectors')]
    },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/only-direct-child-selectors': [
    {
      source: '.bad .test { }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad { & .test { } }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad { & > .test .one { } }',
      warnings: [message('only direct child selectors')(' ')]
    },
    {
      source: '.bad + .test { }',
      warnings: [message('only direct child selectors')('+')]
    },
    {
      source: '.bad { & + * { } }',
      warnings: [message('only direct child selectors')('+')]
    },
    { source: '.good { &.test { } }', warnings: 0 },
    { source: '.good { & > .test { } }', warnings: 0 },
  ],
  'kaliber/valid-flex-context-in-root': [
    {
      title: 'report missing flex',
      source: `
        .bad {
          & > .test {
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0; order: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: createMessages('nested - require display flex in parent', [
        'flex', 'flex-grow', 'flex-shrink', 'flex-basis', 'order'
      ])
    },
    {
      title: "don't report when display flex is present",
      source: `
        .good {
          display: flex;

          & > .test {
            flex: 0; flex-grow: 0; flex-shrink: 0; flex-basis: 0; order: 0;
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    }
  ],
  'kaliber/media-no-child': [
    {
      title: "report nested child in media",
      source: `
        .bad {
          @media x {
            & > {
              width: 10px;
            }
          }
        }
      `.replace(/        /g, ''),
      warnings: ['?']
    },
    {
      title: "don't report media in nested child",
      source: `
        .good {
          & > {
            @media x {
              width: 10px;
            }
          }
        }
      `.replace(/        /g, ''),
      warnings: 0
    }
  ],
  'kaliber/only-element-selectors-in-reset': [
    {
      title: 'invalid - no tag in selector',
      source: { filename: 'other.css', source: `div { }` },
      warnings: ['?']
    },
    {
      title: 'valid - allow tag in reset.css',
      source: { filename: 'reset.css', source: `div { }` },
      warnings: 0
    }
  ],
  'kaliber/no-media-in-root': [
    {
      source: `.bad { } @media x { }`,
      warnings: ['?']
    },
    {
      source: `.good { @media x { } }`,
      warnings: 0
    }
  ]
}<|endoftext|>


<commit_before>/*
	Name: jquery.swipeButton.js
	Author: Andy Matthews
	Website: http://www.andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
*/
(function($){

	$.fn.swipeDelete = function(o){

		o = $.extend( {}, $.fn.swipeDelete.defaults, o );

		return this.each(function(i, el){

			var $e = $(el);
			var $parent = $(el).parent('ul');

			$e.bind(o.direction, function ( e ) {

				// reference the current item
				var $li = $(this);

				// remove all currently displayed buttons
				$('div.ui-btn', $parent).remove();

				// create button
				var $swipeBtn = $('' + o.btnLabel + '').attr({
									'data-role': 'button',
									'data-inline': 'true',
									'class': o.btnClass,
									'data-theme': o.btnTheme,
									'href': $li.data('swipeurl')
								})
								.bind('click tap', o.click);
				// insert button into list item
				$li.prepend($swipeBtn).find('.' + o.btnClass ).button();

				// override row click
				$('div a:not(' + o.btnClass + ')', $li).bind('click.swipe', function(e){
					e.stopPropagation();
					$a = $(this);
					$('div.ui-btn', $li).remove();
					$a.unbind('click.swipe');
				})

			});

		});

	}

	$.fn.swipeDelete.defaults = {
		direction: 'swiperight',
		btnLabel: 'Delete',
		btnTheme: 'e',
		btnClass: 'aSwipeBtn',
		click: function(){}
	};

})(jQuery);<commit_msg>Returning preventDefault to click.swipe.<commit_after>/*
	Name: jquery.swipeButton.js
	Author: Andy Matthews
	Website: http://www.andyMatthews.net
	Packed With: http://jsutility.pjoneil.net/
*/
(function($){

	$.fn.swipeDelete = function(o){

		o = $.extend( {}, $.fn.swipeDelete.defaults, o );

		return this.each(function(i, el){

			var $e = $(el);
			var $parent = $(el).parent('ul');

			$e.bind(o.direction, function ( e ) {

				// reference the current item
				var $li = $(this);

				// remove all currently displayed buttons
				$('div.ui-btn', $parent).remove();

				// create button
				var $swipeBtn = $('' + o.btnLabel + '').attr({
									'data-role': 'button',
									'data-inline': 'true',
									'class': o.btnClass,
									'data-theme': o.btnTheme,
									'href': $li.data('swipeurl')
								})
								.bind('click tap', o.click);
				// insert button into list item
				$li.prepend($swipeBtn).find('.' + o.btnClass ).button();

				// override row click
				$('div a:not(' + o.btnClass + ')', $li).bind('click.swipe', function(e){
					e.stopPropagation();
					e.preventDefault();
					$a = $(this);
					$('div.ui-btn', $li).remove();
					$a.unbind('click.swipe');
				})

			});

		});

	}

	$.fn.swipeDelete.defaults = {
		direction: 'swiperight',
		btnLabel: 'Delete',
		btnTheme: 'e',
		btnClass: 'aSwipeBtn',
		click: function(){}
	};

})(jQuery);<|endoftext|>


<commit_before>// Get Canvas
var canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d"),
  width = 512,
  height = 480;

canvas.tabIndex = 1;
canvas.width = width;
canvas.height = height;

// Background Image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
  bgReady = true;
};
bgImage.src = "http://placekitten.com/512/480";
// Hero Image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
  heroReady = true;
};
heroImage.src = "http://placekitten.com/32/32";

// Kitty Image
var kittyReady = false;
var kittyImage = new Image();
kittyImage.onload = function () {
  kittyReady = true;
};
kittyImage.src = "http://placekitten.com/30/32";

// Game objects
var hero = {
  speed: 256,
  x: 0,
  y: 0
};

var kitty = {
  x: 0,
  y: 0
};
var kittyCaught = 0;

// Handle keyboard controls
var keysDown = {};

addEventListener("keydown", function (e) {
  keysDown[e.keyCode] = true;
  e.preventDefault();
}, false);

addEventListener("keyup", function (e) {
  delete keysDown[e.keyCode];
}, false);

var reset = function () {
  hero.x = (canvas.width / 2) - 16;
  hero.y = (canvas.height / 2) - 16;

  kitty.x = 32 + (Math.random() * (canvas.width - 64));
  kitty.y = 32 + (Math.random() * (canvas.height - 64));
};

// Update game objects
var update = function (modifier) {
  if (38 in keysDown) {
    hero.y -= hero.speed * modifier;
  }
  if (40 in keysDown) {
    hero.y += hero.speed * modifier;
  }
  if (37 in keysDown) {
    hero.x -= hero.speed * modifier;
  }
  if (39 in keysDown) {
    hero.x += hero.speed * modifier;
  }

  // Stop from going off the page
  if (hero.x >= canvas.width - 32) {
    hero.x = canvas.width - 32;
  } else if (hero.x <= 0) {
    hero.x = 0;
  }

  if (hero.y >= canvas.height - 32) {
    hero.y = canvas.height - 32;
  } else if (hero.y <= 0) {
    hero.y = 0;
  }

  // Collision
  if (hero.x <= (kitty.x + 32) && kitty.x <= (hero.x + 32) && hero.y <= (kitty.y + 32) && kitty.y <= (hero.y + 32)) {
    ++kittyCaught;
    nowSwitch = thenSwitch;
    reset();
  }
};

// Render
var render = function () {
  if (bgReady) {
    ctx.drawImage(bgImage, 0, 0);
  }

  if (heroReady) {
    ctx.drawImage(heroImage, hero.x, hero.y);
  }

  if (kittyReady) {
    ctx.drawImage(kittyImage, kitty.x, kitty.y);
  }

  ctx.fillStyle = "#EEE";
  ctx.font = "24px Ubuntu";
  ctx.textAlign = "left";
  ctx.textBaseline = "top";
  ctx.fillText("Kitties caught : " + kittyCaught, 32, 32);
  ctx.fillText("Lives : " + lives, 365, 32);
  ctx.fillText("Timer : " + parseInt(countDown / 100), 32, 64);
};

var gameOver = function () {
  document.write("Game Over. Kitties only have nine lives.");
};

var main = function () {
  now = Date.now();
  var delta = now - then;

  var nowSwitch = Date.now();
  countDown = nowSwitch - thenSwitch;

  update(delta / 1000);
  if (countDown >= 1300) {
    lives--;
    if (lives ==  0) {
      gameOver();
    }
    thenSwitch = nowSwitch;
    reset();
  }
  render();

  then = now;

  requestAnimationFrame(main);
};

var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;

// Initalized Variables
var then, thenSwitch, nowSwitch;
var countDown = 0;
var lives = 9;

var start = function() {
  then = thenSwitch = nowSwitch = Date.now();
  reset();
  //hero.x = (canvas.width / 2) - 16;
  //hero.y = (canvas.height / 2) - 16;
  main();
}

start();
<commit_msg>Update canvas2.js<commit_after>// Get Canvas
var canvas = document.getElementById("canvas"),
  ctx = canvas.getContext("2d"),
  width = 512,
  height = 480;

canvas.tabIndex = 1;
canvas.width = width;
canvas.height = height;

// Background Image
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
  bgReady = true;
};
bgImage.src = "http://placekitten.com/512/480";
// Hero Image
var heroReady = false;
var heroImage = new Image();
heroImage.onload = function () {
  heroReady = true;
};
heroImage.src = "http://placekitten.com/32/32";

// Kitty Image
var kittyReady = false;
var kittyImage = new Image();
kittyImage.onload = function () {
  kittyReady = true;
};
kittyImage.src = "http://placekitten.com/30/32";

// Game objects
var hero = {
  speed: 256,
  x: 0,
  y: 0
};

var kitty = {
  x: 0,
  y: 0
};
var kittyCaught = 0;

// Handle keyboard controls
var keysDown = {};

addEventListener("keydown", function (e) {
  keysDown[e.keyCode] = true;
  e.preventDefault();
}, false);

addEventListener("keyup", function (e) {
  delete keysDown[e.keyCode];
}, false);

var reset = function () {
  hero.x = (canvas.width / 2) - 16;
  hero.y = (canvas.height / 2) - 16;

  kitty.x = 32 + (Math.random() * (canvas.width - 64));
  kitty.y = 32 + (Math.random() * (canvas.height - 64));
};

// Update game objects
var update = function (modifier) {
  if (38 in keysDown) {
    hero.y -= hero.speed * modifier;
  }
  if (40 in keysDown) {
    hero.y += hero.speed * modifier;
  }
  if (37 in keysDown) {
    hero.x -= hero.speed * modifier;
  }
  if (39 in keysDown) {
    hero.x += hero.speed * modifier;
  }

  // Stop from going off the page
  if (hero.x >= canvas.width - 32) {
    hero.x = canvas.width - 32;
  } else if (hero.x <= 0) {
    hero.x = 0;
  }

  if (hero.y >= canvas.height - 32) {
    hero.y = canvas.height - 32;
  } else if (hero.y <= 0) {
    hero.y = 0;
  }

  // Collision
  if (hero.x <= (kitty.x + 32) && kitty.x <= (hero.x + 32) && hero.y <= (kitty.y + 32) && kitty.y <= (hero.y + 32)) {
    ++kittyCaught;
    nowSwitch = thenSwitch;
    reset();
  }
};

// Render
var render = function () {
  if (bgReady) {
    ctx.drawImage(bgImage, 0, 0);
  }

  if (heroReady) {
    ctx.drawImage(heroImage, hero.x, hero.y);
  }

  if (kittyReady) {
    ctx.drawImage(kittyImage, kitty.x, kitty.y);
  }

  ctx.fillStyle = "#EEE";
  ctx.font = "24px Ubuntu";
  ctx.textAlign = "left";
  ctx.textBaseline = "top";
  ctx.fillText("Kitties caught : " + kittyCaught, 32, 32);
  ctx.fillText("Lives : " + lives, 365, 32);
  ctx.fillText("Timer : " + parseInt(countDown / 100), 32, 64);
};

var gameOver = function () {
  document.write("Game Over. Kitties only have nine lives.");
};

var main = function () {
  now = Date.now();
  var delta = now - then;

  var nowSwitch = Date.now();
  countDown = nowSwitch - thenSwitch;

  update(delta / 1000);
  if (countDown >= 1300) {
    lives--;
    if (lives ==  0) {
      gameOver();
    }
    thenSwitch = nowSwitch;
    reset();
  }
  render();

  then = now;

  requestAnimationFrame(main);
};

var w = window;
requestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame;

// Initalized Variables
var then, thenSwitch, nowSwitch;
var countDown;
var lives;

var start = function() {
  then = thenSwitch = nowSwitch = Date.now();
  reset();
  countDown = 0;
  lives = 9;
  //hero.x = (canvas.width / 2) - 16;
  //hero.y = (canvas.height / 2) - 16;
  main();
}

start();
<|endoftext|>


<commit_before>const template = require('lodash/template')
const fs = require('fs')
const info = require('../info')
const zh = require('../../public/locales/zh/translations')
const en = require('../../public/locales/en/translations')

function translate (thing, language) {
  function translateAny (any) {
    if (Array.isArray(any)) return translateArray(any)
    if (typeof any === 'object') return translateObject(any)
    if (typeof any === 'string') return translateString(any)
    return any
  }

  function translateArray (array) {
    return array
      .map(item => translateAny(item))
  }

  function translateObject (object) {
    return Object.keys(object)
      .map(key => ({ [key]: translateAny(object[key]) }))
      .reduce((collection, item) => Object.assign({}, collection, item), {})
  }

  function translateString (string) {
    if (language === 'zh' && zh[string] !== undefined) return zh[string]
    if (language === 'en' && en[string] !== undefined) return en[string]
    return string
  }

  return translateAny(thing)
}

function main () {
  const language = 'zh'

  const translatedInfo = translate(info, language)

  const templatePath = `./src/readme/readme-template.${language}.md`
  const readmePath = './README.md'

  const templateString = fs.readFileSync(templatePath, 'utf8')

  if (fs.existsSync(readmePath)) fs.unlinkSync(readmePath)

  fs.writeFileSync(readmePath, template(templateString)(translatedInfo))
}

main()
<commit_msg>Fix makeReadme<commit_after>const fs = require('fs')
const template = require('lodash/template')
const git = require('simple-git')
const info = require('../info')
const zh = require('../../public/locales/zh/translations')
const en = require('../../public/locales/en/translations')

function translate (thing, language) {
  function translateAny (any) {
    if (Array.isArray(any)) return translateArray(any)
    if (typeof any === 'object') return translateObject(any)
    if (typeof any === 'string') return translateString(any)
    return any
  }

  function translateArray (array) {
    return array
      .map(item => translateAny(item))
  }

  function translateObject (object) {
    return Object.keys(object)
      .map(key => ({ [key]: translateAny(object[key]) }))
      .reduce((collection, item) => Object.assign({}, collection, item), {})
  }

  function translateString (string) {
    if (language === 'zh' && zh[string] !== undefined) return zh[string]
    if (language === 'en' && en[string] !== undefined) return en[string]
    return string
  }

  return translateAny(thing)
}

function commit () {
  git()
    .add('README.md')
    .commit('Update README.md')
}

function main () {
  const language = 'zh'

  const translatedInfo = translate(info, language)

  const templatePath = `./src/readme/readme-template.${language}.md`
  const readmePath = './README.md'

  const templateString = fs.readFileSync(templatePath, 'utf8')

  if (fs.existsSync(readmePath)) fs.unlinkSync(readmePath)

  fs.writeFileSync(readmePath, template(templateString)(translatedInfo))

  commit()
}

main()
<|endoftext|>


<commit_before>/**
 * Output profile module.
 * Profile defines how XHTML output data should look like
 * @param {Function} require
 * @param {Underscore} _
 */
zen_coding.define('profile', function(require, _) {
	var profiles = {};

	var defaultProfile = {
		tag_case: 'lower',
		attr_case: 'lower',
		attr_quotes: 'double',

		// each tag on new line
		tag_nl: 'decide',

		place_cursor: true,

		// indent tags
		indent: true,

		// how many inline elements should be to force line break
		// (set to 0 to disable)
		inline_break: 3,

		// use self-closing style for writing empty elements, e.g.
 or

		self_closing_tag: 'xhtml',

		// Profile-level output filters, re-defines syntax filters
		filters: ''
	};

	/**
	 * Creates new output profile
	 * @param {String} name Profile name
	 * @param {Object} options Profile options
	 */
	function createProfile(name, options) {
		return profiles[name.toLowerCase()] = _.defaults(options || {}, defaultProfile);
	}

	// create default profiles
	createProfile('xhtml');
	createProfile('html', {self_closing_tag: false});
	createProfile('xml', {self_closing_tag: true, tag_nl: true});
	createProfile('plain', {tag_nl: false, indent: false, place_cursor: false});

	return  {
		/**
		 * Creates new output profile and adds it into internal dictionary
		 * @param {String} name Profile name
		 * @param {Object} options Profile options
		 * @memberOf zen_coding.profile
		 * @returns {Object} New profile
		 */
		create: function(name, options) {
			return createProfile(name, options);
		},

		/**
		 * Returns profile by its name. If profile wasn't found, returns
		 * 'plain' profile
		 * @param {String} name Profile name. Might be profile itself
		 * @param {String} syntax. Optional. Current editor syntax. If defined,
		 * profile is searched in resources first, then in predefined profiles
		 * @returns {Object}
		 */
		get: function(name, syntax) {
			if (syntax && _.isString(name)) {
				// search in user resources first
				var profile = require('resources').getSubset(syntax, 'profile');
				if (profile) {
					name = profile;
				}
			}

			if (_.isString(name) && name.toLowerCase() in profiles)
				return profiles[name.toLowerCase()];

			return name && 'tag_case' in name ? name : profiles['plain'];
		},

		/**
		 * Deletes profile with specified name
		 * @param {String} name Profile name
		 */
		remove: function(name) {
			name = (name || '').toLowerCase();
			if (name in profiles)
				delete profiles[name];
		},

		/**
		 * Helper function that converts string case depending on
		 * caseValue
		 * @param {String} str String to transform
		 * @param {String} caseValue Case value: can be lower,
		 * upper and leave
		 * @returns {String}
		 */
		stringCase: function(str, caseValue) {
			switch (String(caseValue || '').toLowerCase()) {
				case 'lower':
					return str.toLowerCase();
				case 'upper':
					return str.toUpperCase();
			}

			return str;
		},

		/**
		 * Returns quote character based on profile parameter
		 * @param {String} param Quote parameter, can be single or
		 * double
		 * @returns {String}
		 */
		quote: function(param) {
			return param == 'single' ? "'" : '"';
		},

		/**
		 * Returns self-closing tag symbol, based on passed parameter
		 * @param {String} param
		 * @returns {String}
		 */
		selfClosing: function(param) {
			if (param == 'xhtml')
				return ' /';

			if (param === true)
				return '/';

			return '';
		}
	};
});<commit_msg>Better syntax profile handling<commit_after>/**
 * Output profile module.
 * Profile defines how XHTML output data should look like
 * @param {Function} require
 * @param {Underscore} _
 */
zen_coding.define('profile', function(require, _) {
	var profiles = {};

	var defaultProfile = {
		tag_case: 'lower',
		attr_case: 'lower',
		attr_quotes: 'double',

		// each tag on new line
		tag_nl: 'decide',

		place_cursor: true,

		// indent tags
		indent: true,

		// how many inline elements should be to force line break
		// (set to 0 to disable)
		inline_break: 3,

		// use self-closing style for writing empty elements, e.g.
 or

		self_closing_tag: 'xhtml',

		// Profile-level output filters, re-defines syntax filters
		filters: ''
	};

	/**
	 * Creates new output profile
	 * @param {String} name Profile name
	 * @param {Object} options Profile options
	 */
	function createProfile(name, options) {
		return profiles[name.toLowerCase()] = _.defaults(options || {}, defaultProfile);
	}

	// create default profiles
	createProfile('xhtml');
	createProfile('html', {self_closing_tag: false});
	createProfile('xml', {self_closing_tag: true, tag_nl: true});
	createProfile('plain', {tag_nl: false, indent: false, place_cursor: false});

	return  {
		/**
		 * Creates new output profile and adds it into internal dictionary
		 * @param {String} name Profile name
		 * @param {Object} options Profile options
		 * @memberOf zen_coding.profile
		 * @returns {Object} New profile
		 */
		create: function(name, options) {
			if (arguments.length == 2)
				return createProfile(name, options);
			else
				// create profile object only
				return _.defaults(name || {}, defaultProfile);
		},

		/**
		 * Returns profile by its name. If profile wasn't found, returns
		 * 'plain' profile
		 * @param {String} name Profile name. Might be profile itself
		 * @param {String} syntax. Optional. Current editor syntax. If defined,
		 * profile is searched in resources first, then in predefined profiles
		 * @returns {Object}
		 */
		get: function(name, syntax) {
			if (syntax && _.isString(name)) {
				// search in user resources first
				var profile = require('resources').getSubset(syntax, 'profile');
				if (profile) {
					name = profile;
				}
			}

			if (_.isString(name) && name.toLowerCase() in profiles)
				return profiles[name.toLowerCase()];

			return name && 'tag_case' in name ? this.create(name) : profiles['plain'];
		},

		/**
		 * Deletes profile with specified name
		 * @param {String} name Profile name
		 */
		remove: function(name) {
			name = (name || '').toLowerCase();
			if (name in profiles)
				delete profiles[name];
		},

		/**
		 * Helper function that converts string case depending on
		 * caseValue
		 * @param {String} str String to transform
		 * @param {String} caseValue Case value: can be lower,
		 * upper and leave
		 * @returns {String}
		 */
		stringCase: function(str, caseValue) {
			switch (String(caseValue || '').toLowerCase()) {
				case 'lower':
					return str.toLowerCase();
				case 'upper':
					return str.toUpperCase();
			}

			return str;
		},

		/**
		 * Returns quote character based on profile parameter
		 * @param {String} param Quote parameter, can be single or
		 * double
		 * @returns {String}
		 */
		quote: function(param) {
			return param == 'single' ? "'" : '"';
		},

		/**
		 * Returns self-closing tag symbol, based on passed parameter
		 * @param {String} param
		 * @returns {String}
		 */
		selfClosing: function(param) {
			if (param == 'xhtml')
				return ' /';

			if (param === true)
				return '/';

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