<commit_before>import _ from 'lodash';

module.exports = () => {
  return {
    restrict: 'E',
    template: require('./template.html'),
    controller: ['$scope', 'tasksStore', ($scope, tasksStore) => {
      $scope.$watch('task.text', (newValue, oldValue) => {
        const isEditing = !!newValue,
              estimate = extractEstimate(newValue),
              tags = extractTags(newValue);

        console.log({newValue, oldValue, estimate, tags});

        if (estimate) {
          const {components} = estimate;

          $scope.estimate = _.map(components, component => `${component.magnitude} ${unitMap[component.unit]}`)
                             .join(' ');
        }
        else $scope.estimate = '';

        if (!$scope.task) {
          $scope.task = tasksStore.addTask();
        }

        $scope.tags = tags;
        $scope.isEditing = isEditing;
      });

      $scope.taskKeypress = $event => {
        const {keyCode} = $event;

        console.log({keyCode, task: $scope.task});

        if (keyCode === 13) {
          const {task: text, estimate, tags} = $scope;

          tasksStore.addTask({
            text,
            estimate,
            tags
          });
        }
      };

      function addTask() {

      }
    }]
  };
};

const unitPatterns = {
  'seconds': 'seconds|second|sec|s',
  'minutes': 'minutes|minute|mins|min|mn|m',
  'hours':   'hours|hour|hrs|hr|h',
  'days':    'days|day|d',
  'weeks':   'weeks|week|wks|wk|w',
  'months':  'months|month|mths|mth|mos|mo|M',
  'year':    'years|year|yr|y',
  'decade':  'decades|decade',
  'century': 'centuries|century',
  'eon':     'eons|eon'
};

const units = _.map(unitPatterns, (unitPattern, unit) => unitPattern + '').join('|');

const unitMap = _.reduce(unitPatterns, (map, unitPattern, unit) => {
  const parts = unitPattern.split('|');
  _.each(parts, part => map[part] = unit);
  return map;
}, {});

const pattern = new RegExp(`(\\d+)\\s*(${units})[^a-zA-Z]?`, 'g');

const tree = buildTree(unitPatterns);

console.log({tree});

function e(tree, text) {
  const {length} = text,
        stack = [tree];

  let [node] = stack;

  for (let i = 0; i < length; i++) {
    const character = text.charAt(i),
          candidate = node[character];

    if (candidate) {
      node = candidate;
      stack.push(node);
    }
    else {

    }
  }
}

function check(text, node, start, length) {
  const stack = [node];

  for (let i = start; i < length; i++) {
    const character = text.charAt(i),
          candidate = node[character];

    if (candidate) {
      return candidate;
    }
    else {

    }
  }
}

function buildTree(patterns) {
  const tree = {};
  _.each(patterns, (pattern, unit) => {
    _.each(pattern.split('|'), word => {
      insertKey(tree, word, unit);
    });
  });
  return tree;
}

function insertKey(tree, key, word) {
  const {length} = key;

  let node = tree;

  for (let i = 0; i < length; i++) {
    const character = key.charAt(i),
          matchingNode = node[character];

    if (matchingNode) {
      node = matchingNode;
    }
    else {
      //insert
      const newNode = {};
      node[character] = newNode;
      node = newNode;
    }
  }

  node.value = word;
}

function extractEstimate(text = '') {
  const matches = text.match(pattern);
  if (matches) {
    const components = matches.map(match => {
                        const [
                          x,
                          magnitude,
                          unit
                        ] = match.match(pattern.source);

                        return {magnitude, unit};
                      }),
          total = components.reduce((sum, component) => sum + inMilliseconds(component), 0);

    return {
      total,
      components
    };
  }
}

function extractTags(text = '') {
  return text.match(/#([\w\d]+)/g);
}

const toMilliseconds = {
  'seconds': s => s * 1000,
  'minutes': m => m * 1000 * 60,
  'hours':   h => h * 1000 * 60 * 60,
  'days':    d => d * 1000 * 60 * 60 * 24,
  'weeks':   w => w * 1000 * 60 * 60 * 24 * 7,
  'months':  m => m * 1000 * 60 * 60 * 24 * (365.25 / 12),
  'year':    y => y * 1000 * 60 * 60 * 24 * 365.25,
  'decade':  d => d * 1000 * 60 * 60 * 24 * 365.25 * 10
};

function inMilliseconds(component) {
  const {magnitude, unit} = component;

  return toMilliseconds[unitMap[unit]](magnitude);
}<commit_msg>Should have been two commits...<commit_after>import _ from 'lodash';

module.exports = () => {
  return {
    restrict: 'E',
    template: require('./template.html'),
    controller: ['$scope', 'tasksStore', ($scope, tasksStore) => {
      $scope.$watch('task.text', (newValue, oldValue) => {
        const isEditing = !!newValue,
              estimate = extractEstimate(newValue),
              tags = extractTags(newValue);

        console.log({newValue, oldValue, estimate, tags});

        if (estimate) {
          const {components} = estimate;

          $scope.estimate = _.map(components, component => `${component.magnitude} ${unitMap[component.unit]}`)
                             .join(' ');
        }
        else $scope.estimate = '';

        if (!$scope.task) {
          $scope.task = tasksStore.addTask();
        }

        $scope.tags = tags;
        $scope.isEditing = isEditing;
      });

      $scope.taskKeypress = $event => {
        const {keyCode} = $event;

        console.log({keyCode, task: $scope.task});

        if (keyCode === 13) {
          const {task: text, estimate, tags} = $scope;

          const task = addTask({text, estimate, tags});
        }
      };

      function addTask(task) {
        return tasksStore.addTask(task);
      }
    }]
  };
};

const unitPatterns = {
  'seconds': 'seconds|second|sec|s',
  'minutes': 'minutes|minute|mins|min|mn|m',
  'hours':   'hours|hour|hrs|hr|h',
  'days':    'days|day|d',
  'weeks':   'weeks|week|wks|wk|w',
  'months':  'months|month|mths|mth|mos|mo|M',
  'year':    'years|year|yr|y',
  'decade':  'decades|decade',
  'century': 'centuries|century',
  'eon':     'eons|eon'
};

const units = _.map(unitPatterns, (unitPattern, unit) => unitPattern + '').join('|');

const unitMap = _.reduce(unitPatterns, (map, unitPattern, unit) => {
  const parts = unitPattern.split('|');
  _.each(parts, part => map[part] = unit);
  return map;
}, {});

const pattern = new RegExp(`(\\d+)\\s*(${units})[^a-zA-Z]?`, 'g');

const tree = buildTree(unitPatterns);

console.log({tree});

function e(tree, text) {
  const {length} = text,
        stack = [tree];

  let [node] = stack;

  for (let i = 0; i < length; i++) {
    const character = text.charAt(i),
          candidate = node[character];

    if (candidate) {
      node = candidate;
      stack.push(node);
    }
    else {

    }
  }
}

function check(text, node, start, length) {
  const stack = [node];

  for (let i = start; i < length; i++) {
    const character = text.charAt(i),
          candidate = node[character];

    if (candidate) {
      return candidate;
    }
    else {

    }
  }
}

function buildTree(patterns) {
  const tree = {};
  _.each(patterns, (pattern, unit) => {
    _.each(pattern.split('|'), word => {
      insertKey(tree, word, unit);
    });
  });
  return tree;
}

function insertKey(tree, key, word) {
  const {length} = key;

  let node = tree;

  for (let i = 0; i < length; i++) {
    const character = key.charAt(i),
          matchingNode = node[character];

    if (matchingNode) {
      node = matchingNode;
    }
    else {
      //insert
      const newNode = {};
      node[character] = newNode;
      node = newNode;
    }
  }

  node.value = word;
}

function extractEstimate(text = '') {
  const matches = text.match(pattern);
  if (matches) {
    const components = matches.map(match => ((([_, magnitude, unit]) => ({magnitude, unit}))(match.match(pattern.source)))),
          total = _.sum(components, inMilliseconds);

    return {
      total,
      components
    };
  }
}

function extractTags(text = '') {
  return text.match(/#([\w\d]+)/g);
}

const toMilliseconds = {
  'seconds': s => s * 1000,
  'minutes': m => m * 1000 * 60,
  'hours':   h => h * 1000 * 60 * 60,
  'days':    d => d * 1000 * 60 * 60 * 24,
  'weeks':   w => w * 1000 * 60 * 60 * 24 * 7,
  'months':  m => m * 1000 * 60 * 60 * 24 * (365.25 / 12),
  'year':    y => y * 1000 * 60 * 60 * 24 * 365.25,
  'decade':  d => d * 1000 * 60 * 60 * 24 * 365.25 * 10
};

function inMilliseconds(component) {
  const {magnitude, unit} = component;

  return toMilliseconds[unitMap[unit]](magnitude);
}<|endoftext|>


<commit_before>// @flow
/**
 * search for dom elements on your page
 * @module holmes
 */
(function(root, factory) {
  'use strict';

  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], function() {
      return (root.holmes = factory(document));
    });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(document);
  } else {
    // Browser globals
    root.holmes = factory(document);
  }
})(this, function(document) {
  // UMD Definition above, do not remove this line

  // To get to know more about the Universal Module Definition
  // visit: https://github.com/umdjs/umd

  'use strict';

  /**
   * search for dom elements on your page
   * @alias module:holmes
   * @param {string} [options.input='input[type=search]']
   *   A querySelector to find the input
   * @param {string} options.find
   *   A querySelectorAll rule to find each of the find terms
   * @param {string=} options.placeholder
   *   Text to show when there are no results (innerHTML)
   * @param {string} [options.class.visible=false]
   *   class to add to matched items
   * @param {string} [options.class.hidden='hidden']
   *   class to add to non-matched items
   * @param {boolean} [options.dynamic=false]
   *   Whether to query for the content of the elements on every input.
   *   If this is false, then only when initializing the script will
   *   fetch the content of the elements to search in. If this is true
   *   then it will refresh on every input event.
   * @param {boolean} [options.contenteditable=false]
   *   DEPRECATED (now handled automatically) whether the input is a contenteditable or
   *   not. By default it's assumed that it's <input>, true here
   *   will use <div contenteditable>
   * @param {boolean} [options.instant=false]
   *   By default Holmes waits for the DOMContentLoaded event to fire
   *   before listening. This is to make sure that all content is available. However
   *   if you exactly know when all your content is available (ajax, your own event or
   *   other situations), you can put this option on true.
   * @param {number} [minCharacters=0] The minimum amount of characters to be typed before
   *   Holmes starts searching. Beware that this also counts when backspacing.
   * @param {onChange} [options.onHidden]
   *   Callback for when an item is hidden.
   * @param {onChange} [options.onVisible]
   *   Callback for when an item is visible again.
   * @param {onChange} [options.onEmpty]
   *   Callback for when no items were found.
   * @param {onChange} [options.onFound]
   *   Callback for when items are found after being empty.
   */
  function holmes(options) {

    var empty = false;

    if (typeof options != 'object') {
      throw new Error('The options need to be given inside an object like this:\nholmes({\n\tfind:".result",\n\tdynamic:false\n});\n see also https://haroen.me/holmes/doc/module-holmes.html');
    }

    /**
     * Options
     * @type {Object}
     */
    holmes.prototype.options = options;

    // if holmes.prototype.options.find is missing, the searching won't work so we'll thrown an exceptions
    if (typeof holmes.prototype.options.find == 'undefined') {
      throw new Error('A find argument is needed. That should be a querySelectorAll for each of the items you want to match individually. You should have something like: \nholmes({\n\tfind:".result"\n});\nsee also https://haroen.me/holmes/doc/module-holmes.html');
    }

    /**
     * Start an event listener with the specified options
     */
    holmes.prototype.start = function() {

      // setting default values
      if (typeof holmes.prototype.options.input == 'undefined') {
        holmes.prototype.options.input = 'input[type=search]';
      }
      if (typeof holmes.prototype.options.placeholder == 'undefined') {
        holmes.prototype.options.placeholder = false;
      }
      if (typeof holmes.prototype.options.class == 'undefined') {
        holmes.prototype.options.class = {};
      }
      if (typeof holmes.prototype.options.class.visible == 'undefined') {
        holmes.prototype.options.class.visible = false;
      }
      if (typeof holmes.prototype.options.class.hidden == 'undefined') {
        holmes.prototype.options.class.hidden = 'hidden';
      }
      if (typeof holmes.prototype.options.dynamic == 'undefined') {
        holmes.prototype.options.dynamic = false;
      }
      if (typeof holmes.prototype.options.minCharacters == 'undefined') {
        holmes.prototype.options.minCharacters = 0;
      }

      /**
       * The input element
       * @type {NodeList}
       */
      holmes.prototype.input = document.querySelector(holmes.prototype.options.input);
      /**
       * All of the elements that are searched
       * @type {NodeList}
       */
      holmes.prototype.elements = document.querySelectorAll(holmes.prototype.options.find);
      /**
       * amount of elements to search
       * @type {Number}
       */
      holmes.prototype.elementsLength = holmes.prototype.elements.length;

      /**
       * The amount of elements that are hidden
       * @type {Number}
       */
      holmes.prototype.hidden = 0;

      // create a container for a placeholder
      if (holmes.prototype.options.placeholder) {
        /**
         * Placeholder element
         * @type {Element}
         */
        holmes.prototype.placeholder = document.createElement('div');
        holmes.prototype.placeholder.id = "holmes-placeholder";
        holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        holmes.prototype.placeholder.innerHTML = holmes.prototype.options.placeholder;
        holmes.prototype.elements[0].parentNode.appendChild(holmes.prototype.placeholder);
      }

      // if a visible class is given, give it to everything
      if (holmes.prototype.options.class.visible) {
        var i;
        for (i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
        }
      }

      // listen for input
      holmes.prototype.input.addEventListener('input', inputHandler);
    };

    /**
     * input event handler
     */
    function inputHandler() {

      // by default the value isn't found
      var found = false;

      // if a minimum of characters is required
      // check if that limit has been reached
      if (holmes.prototype.options.minCharacters) {
        if (holmes.prototype.options.minCharacters > holmes.prototype.input.value.length && holmes.prototype.input.value.length !== 0) {
          return;
        }
      }

      // search in lowercase
      /**
       * Lowercase string holmes searces for
       * @type {string}
       */
      holmes.prototype.searchString;
      if (holmes.prototype.input instanceof HTMLInputElement) {
        holmes.prototype.searchString = holmes.prototype.input.value.toLowerCase();
      } else if (holmes.prototype.input.contentEditable) {
        holmes.prototype.searchString = holmes.prototype.input.textContent.toLowerCase();
      } else {
        throw new Error("The Holmes input was no <input> or contenteditable.");
      }

      // if the dynamic option is enabled, then we should query
      // for the contents of `elements` on every input
      if (holmes.prototype.options.dynamic) {
        holmes.prototype.elements = document.querySelectorAll(holmes.prototype.options.find);
        holmes.prototype.elementsLength = holmes.prototype.elements.length;
      }

      // loop over all the elements
      // in case this should become dynamic, query for the elements here
      var i;
      for (i = 0; i < holmes.prototype.elementsLength; i++) {

        // if the current element doesn't contain the search string
        // add the hidden class and remove the visbible class
        if (holmes.prototype.elements[i].textContent.toLowerCase().indexOf(holmes.prototype.searchString) === -1) {
          if (holmes.prototype.options.class.visible) {
            holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.visible);
          }
          if (!holmes.prototype.elements[i].classList.contains(holmes.prototype.options.class.hidden)) {
            holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.hidden);
            holmes.prototype.hidden++;

            if (typeof holmes.prototype.options.onHidden === 'function') {
              holmes.prototype.options.onHidden(holmes.prototype.elements[i]);
            }
          }
          // else
          // remove the hidden class and add the visible
        } else {
          if (holmes.prototype.options.class.visible) {
            holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
          }
          if (holmes.prototype.elements[i].classList.contains(holmes.prototype.options.class.hidden)) {
            holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
            holmes.prototype.hidden--;

            if (empty && typeof holmes.prototype.options.onFound === 'function') {
              holmes.prototype.options.onFound(placeholder);
            }
            if (typeof holmes.prototype.options.onVisible === 'function') {
              holmes.prototype.options.onVisible(holmes.prototype.elements[i]);
            }
            empty = false;
          }

          // the element is now found at least once
          found = true;
        }
      };

      // No results were found and last time we checked it wasn't empty
      if (!found && !empty) {
        empty = true;

        if (holmes.prototype.options.placeholder) {
          holmes.prototype.placeholder.classList.remove(holmes.prototype.options.class.hidden);
        }
        if (typeof holmes.prototype.options.onEmpty === 'function') {
          holmes.prototype.options.onEmpty(holmes.prototype.placeholder);
        }
      } else if (!empty) {
        if (holmes.prototype.options.placeholder) {
          holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        }
      }
    }

    // whether to start immediately or wait on the load of DOMContent
    if (typeof holmes.prototype.options.instant == 'undefined') {
      holmes.prototype.options.instant = false;
    }

    if (holmes.prototype.options.instant) {
      holmes.prototype.start();
    } else {
      window.addEventListener('DOMContentLoaded', holmes.prototype.start);
    }

    /**
     * remove the current event listener
     * @see holmes.prototype.start
     * @return {Promise} resolves when the event is removed
     */
    holmes.prototype.stop = function() {
      return new Promise(function(resolve, reject) {
        holmes.prototype.input.removeEventListener('input', inputHandler);
        holmes.prototype.placeholder.parentNode.removeChild(holmes.prototype.placeholder);
        resolve();
      });
    };

    /**
     * empty the search string programmatically.
     * This avoids having to send a new `input` event
     */
    holmes.prototype.clear = function() {
      console.log(holmes.prototype.input);
      if (holmes.prototype.input instanceof HTMLInputElement) {
        holmes.prototype.input.value = '';
      } else if (holmes.prototype.input.contentEditable) {
        holmes.prototype.input.textContent = '';
      } else {
        throw new Error("The Holmes input was no <input> or contenteditable.");
      }
      // if a visible class is given, give it to everything
      if (holmes.prototype.options.class.visible) {
        for (var i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
          holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
        }
      } else {
        for (var i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
        }
      }
      if (holmes.prototype.options.placeholder) {
        holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        if (holmes.prototype.options.class.visible) {
          holmes.prototype.placeholder.classList.remove(holmes.prototype.options.class.visible);
        }
      }

      holmes.prototype.hidden = 0;
    };

    /**
     * Show the amount of elements, and those hidden and visible
     * @return {object} all matching elements, the amount of hidden and the amount of visible elements
     */
    holmes.prototype.count = function() {
      return {
        all: holmes.prototype.elementsLength,
        hidden: holmes.prototype.hidden,
        visible: holmes.prototype.elementsLength - holmes.prototype.hidden
      };
    }

  };

  /**
   * Callback used for changes in item en list states.
   * @callback onChange
   * @param {object} [element]
   *   Element affected by the event. This is the item found by
   *   onVisible and onHidden and the placeholder
   *   (or undefined) for onEmpty and
   *   onFound.
   */

  return holmes;

});
<commit_msg>fix onFound<commit_after>// @flow
/**
 * search for dom elements on your page
 * @module holmes
 */
(function(root, factory) {
  'use strict';

  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], function() {
      return (root.holmes = factory(document));
    });
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but
    // only CommonJS-like environments that support module.exports,
    // like Node.
    module.exports = factory(document);
  } else {
    // Browser globals
    root.holmes = factory(document);
  }
})(this, function(document) {
  // UMD Definition above, do not remove this line

  // To get to know more about the Universal Module Definition
  // visit: https://github.com/umdjs/umd

  'use strict';

  /**
   * search for dom elements on your page
   * @alias module:holmes
   * @param {string} [options.input='input[type=search]']
   *   A querySelector to find the input
   * @param {string} options.find
   *   A querySelectorAll rule to find each of the find terms
   * @param {string=} options.placeholder
   *   Text to show when there are no results (innerHTML)
   * @param {string} [options.class.visible=false]
   *   class to add to matched items
   * @param {string} [options.class.hidden='hidden']
   *   class to add to non-matched items
   * @param {boolean} [options.dynamic=false]
   *   Whether to query for the content of the elements on every input.
   *   If this is false, then only when initializing the script will
   *   fetch the content of the elements to search in. If this is true
   *   then it will refresh on every input event.
   * @param {boolean} [options.contenteditable=false]
   *   DEPRECATED (now handled automatically) whether the input is a contenteditable or
   *   not. By default it's assumed that it's <input>, true here
   *   will use <div contenteditable>
   * @param {boolean} [options.instant=false]
   *   By default Holmes waits for the DOMContentLoaded event to fire
   *   before listening. This is to make sure that all content is available. However
   *   if you exactly know when all your content is available (ajax, your own event or
   *   other situations), you can put this option on true.
   * @param {number} [minCharacters=0] The minimum amount of characters to be typed before
   *   Holmes starts searching. Beware that this also counts when backspacing.
   * @param {onChange} [options.onHidden]
   *   Callback for when an item is hidden.
   * @param {onChange} [options.onVisible]
   *   Callback for when an item is visible again.
   * @param {onChange} [options.onEmpty]
   *   Callback for when no items were found.
   * @param {onChange} [options.onFound]
   *   Callback for when items are found after being empty.
   */
  function holmes(options) {

    var empty = false;

    if (typeof options != 'object') {
      throw new Error('The options need to be given inside an object like this:\nholmes({\n\tfind:".result",\n\tdynamic:false\n});\n see also https://haroen.me/holmes/doc/module-holmes.html');
    }

    /**
     * Options
     * @type {Object}
     */
    holmes.prototype.options = options;

    // if holmes.prototype.options.find is missing, the searching won't work so we'll thrown an exceptions
    if (typeof holmes.prototype.options.find == 'undefined') {
      throw new Error('A find argument is needed. That should be a querySelectorAll for each of the items you want to match individually. You should have something like: \nholmes({\n\tfind:".result"\n});\nsee also https://haroen.me/holmes/doc/module-holmes.html');
    }

    /**
     * Start an event listener with the specified options
     */
    holmes.prototype.start = function() {

      // setting default values
      if (typeof holmes.prototype.options.input == 'undefined') {
        holmes.prototype.options.input = 'input[type=search]';
      }
      if (typeof holmes.prototype.options.placeholder == 'undefined') {
        holmes.prototype.options.placeholder = false;
      }
      if (typeof holmes.prototype.options.class == 'undefined') {
        holmes.prototype.options.class = {};
      }
      if (typeof holmes.prototype.options.class.visible == 'undefined') {
        holmes.prototype.options.class.visible = false;
      }
      if (typeof holmes.prototype.options.class.hidden == 'undefined') {
        holmes.prototype.options.class.hidden = 'hidden';
      }
      if (typeof holmes.prototype.options.dynamic == 'undefined') {
        holmes.prototype.options.dynamic = false;
      }
      if (typeof holmes.prototype.options.minCharacters == 'undefined') {
        holmes.prototype.options.minCharacters = 0;
      }

      /**
       * The input element
       * @type {NodeList}
       */
      holmes.prototype.input = document.querySelector(holmes.prototype.options.input);
      /**
       * All of the elements that are searched
       * @type {NodeList}
       */
      holmes.prototype.elements = document.querySelectorAll(holmes.prototype.options.find);
      /**
       * amount of elements to search
       * @type {Number}
       */
      holmes.prototype.elementsLength = holmes.prototype.elements.length;

      /**
       * The amount of elements that are hidden
       * @type {Number}
       */
      holmes.prototype.hidden = 0;

      // create a container for a placeholder
      if (holmes.prototype.options.placeholder) {
        /**
         * Placeholder element
         * @type {Element}
         */
        holmes.prototype.placeholder = document.createElement('div');
        holmes.prototype.placeholder.id = "holmes-placeholder";
        holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        holmes.prototype.placeholder.innerHTML = holmes.prototype.options.placeholder;
        holmes.prototype.elements[0].parentNode.appendChild(holmes.prototype.placeholder);
      }

      // if a visible class is given, give it to everything
      if (holmes.prototype.options.class.visible) {
        var i;
        for (i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
        }
      }

      // listen for input
      holmes.prototype.input.addEventListener('input', inputHandler);
    };

    /**
     * input event handler
     */
    function inputHandler() {

      // by default the value isn't found
      var found = false;

      // if a minimum of characters is required
      // check if that limit has been reached
      if (holmes.prototype.options.minCharacters) {
        if (holmes.prototype.options.minCharacters > holmes.prototype.input.value.length && holmes.prototype.input.value.length !== 0) {
          return;
        }
      }

      // search in lowercase
      /**
       * Lowercase string holmes searces for
       * @type {string}
       */
      holmes.prototype.searchString;
      if (holmes.prototype.input instanceof HTMLInputElement) {
        holmes.prototype.searchString = holmes.prototype.input.value.toLowerCase();
      } else if (holmes.prototype.input.contentEditable) {
        holmes.prototype.searchString = holmes.prototype.input.textContent.toLowerCase();
      } else {
        throw new Error("The Holmes input was no <input> or contenteditable.");
      }

      // if the dynamic option is enabled, then we should query
      // for the contents of `elements` on every input
      if (holmes.prototype.options.dynamic) {
        holmes.prototype.elements = document.querySelectorAll(holmes.prototype.options.find);
        holmes.prototype.elementsLength = holmes.prototype.elements.length;
      }

      // loop over all the elements
      // in case this should become dynamic, query for the elements here
      var i;
      for (i = 0; i < holmes.prototype.elementsLength; i++) {

        // if the current element doesn't contain the search string
        // add the hidden class and remove the visbible class
        if (holmes.prototype.elements[i].textContent.toLowerCase().indexOf(holmes.prototype.searchString) === -1) {
          if (holmes.prototype.options.class.visible) {
            holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.visible);
          }
          if (!holmes.prototype.elements[i].classList.contains(holmes.prototype.options.class.hidden)) {
            holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.hidden);
            holmes.prototype.hidden++;

            if (typeof holmes.prototype.options.onHidden === 'function') {
              holmes.prototype.options.onHidden(holmes.prototype.elements[i]);
            }
          }
          // else
          // remove the hidden class and add the visible
        } else {
          if (holmes.prototype.options.class.visible) {
            holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
          }
          if (holmes.prototype.elements[i].classList.contains(holmes.prototype.options.class.hidden)) {
            holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
            holmes.prototype.hidden--;

            if (empty && typeof holmes.prototype.options.onFound === 'function') {
              holmes.prototype.options.onFound(holmes.prototype.placeholder);
            }
            if (typeof holmes.prototype.options.onVisible === 'function') {
              holmes.prototype.options.onVisible(holmes.prototype.elements[i]);
            }
            empty = false;
          }

          // the element is now found at least once
          found = true;
        }
      };

      // No results were found and last time we checked it wasn't empty
      if (!found && !empty) {
        empty = true;

        if (holmes.prototype.options.placeholder) {
          holmes.prototype.placeholder.classList.remove(holmes.prototype.options.class.hidden);
        }
        if (typeof holmes.prototype.options.onEmpty === 'function') {
          holmes.prototype.options.onEmpty(holmes.prototype.placeholder);
        }
      } else if (!empty) {
        if (holmes.prototype.options.placeholder) {
          holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        }
      }
    }

    // whether to start immediately or wait on the load of DOMContent
    if (typeof holmes.prototype.options.instant == 'undefined') {
      holmes.prototype.options.instant = false;
    }

    if (holmes.prototype.options.instant) {
      holmes.prototype.start();
    } else {
      window.addEventListener('DOMContentLoaded', holmes.prototype.start);
    }

    /**
     * remove the current event listener
     * @see holmes.prototype.start
     * @return {Promise} resolves when the event is removed
     */
    holmes.prototype.stop = function() {
      return new Promise(function(resolve, reject) {
        holmes.prototype.input.removeEventListener('input', inputHandler);
        holmes.prototype.placeholder.parentNode.removeChild(holmes.prototype.placeholder);
        resolve();
      });
    };

    /**
     * empty the search string programmatically.
     * This avoids having to send a new `input` event
     */
    holmes.prototype.clear = function() {
      console.log(holmes.prototype.input);
      if (holmes.prototype.input instanceof HTMLInputElement) {
        holmes.prototype.input.value = '';
      } else if (holmes.prototype.input.contentEditable) {
        holmes.prototype.input.textContent = '';
      } else {
        throw new Error("The Holmes input was no <input> or contenteditable.");
      }
      // if a visible class is given, give it to everything
      if (holmes.prototype.options.class.visible) {
        for (var i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
          holmes.prototype.elements[i].classList.add(holmes.prototype.options.class.visible);
        }
      } else {
        for (var i = 0; i < holmes.prototype.elementsLength; i++) {
          holmes.prototype.elements[i].classList.remove(holmes.prototype.options.class.hidden);
        }
      }
      if (holmes.prototype.options.placeholder) {
        holmes.prototype.placeholder.classList.add(holmes.prototype.options.class.hidden);
        if (holmes.prototype.options.class.visible) {
          holmes.prototype.placeholder.classList.remove(holmes.prototype.options.class.visible);
        }
      }

      holmes.prototype.hidden = 0;
    };

    /**
     * Show the amount of elements, and those hidden and visible
     * @return {object} all matching elements, the amount of hidden and the amount of visible elements
     */
    holmes.prototype.count = function() {
      return {
        all: holmes.prototype.elementsLength,
        hidden: holmes.prototype.hidden,
        visible: holmes.prototype.elementsLength - holmes.prototype.hidden
      };
    }

  };

  /**
   * Callback used for changes in item en list states.
   * @callback onChange
   * @param {object} [element]
   *   Element affected by the event. This is the item found by
   *   onVisible and onHidden and the placeholder
   *   (or undefined) for onEmpty and
   *   onFound.
   */

  return holmes;

});
<|endoftext|>


<commit_before>import BABYLON from 'babylonjs';
import {EventSubscriptionContext} from '../../event-util';
import {Buttons} from '../input';
import testPower from './powers/testPower';
import testPower2 from './powers/testPower2';
import testPower3 from './powers/testPower3';

const zeroVector2 = new BABYLON.Vector2(0, 0);
const maxMana = 5000000;

export default class Hero {
  constructor(
    game, name, meshFileName='omi', speed=30, airSpeed=10, jumpStrength=250,
    attack1=testPower, attack2=testPower2, attack3=testPower3, attack4=testPower,
    defense1=testPower, defense2=testPower, defense3=testPower, defense4=testPower){
    this.game = game;
    this.name = name;
      this._mana = maxMana;
      this._joyTarget = this;

    // Create collision mask
    this.mask = this.initCapsule(2,4);
    this.mask.isVisible = false;

    require(`../../../models/heroes/${meshFileName}.blend`).ImportMesh(BABYLON.SceneLoader, null, this.game.scene, loadedMeshes => {
        // Add the mesh
        this.mesh = loadedMeshes[0];//.clone(this.name); // 2 is the index of the player mesh
        console.log("the player mesh", this.mesh);
        this.mesh.isVisible = true;
        this.mesh.id = this.name;
        this.mesh.parent = this.mask;
        this.mesh.position.y = -3;
        // Add the player mesh to the shadowGenerator
        this.game.shadowGenerator.getShadowMap().renderList.push(this.mesh);
        this.mesh.receiveShadows = true;
        // Add material for debug
        var material = new BABYLON.StandardMaterial("blue_material", game.scene);
        material.diffuseColor = BABYLON.Color3.Blue();
        this.mesh.material = material;

        this.initAnimations();
    });

    // Create the physics body using mask TODO: Make the Impostor a capsule
    this.body = this.mask.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, {mass:10, friction:0.05, restitution:0.5});

    this.updateMassProperties();

    this.initGroundCheck();

    // Movement variables
    this.onGround = false;
    this.jumpStrength = jumpStrength;
    this.jumpTimerStart = 20
    this.jumpTimer = this.jumpTimerStart;
    this.speed = speed;
    this.airSpeed = airSpeed;
    this.moveBool = true;

    // Input
    this.Input = {
      AXIS_X : 0,
      AXIS_Y : 0,
      JUMP : false,
    };

    // InitializePowers
    this.attack1 = new attack1(game, this);
    this.attack2 = new attack2(game, this);
    this.attack3 = new attack3(game, this);
    this.attack4 = new attack4(game, this);

    this.defense1 = new defense1(game, this);
    this.defense2 = new defense2(game, this);
    this.defense3 = new defense3(game, this);
    this.defense4 = new defense4(game, this);

    // Add update loop to Babylon
    this.mesh.registerBeforeRender(() => {
        this.update();
    });
  }

  initAnimations () {
      console.log('animation range', this.mesh.skeleton.getAnimationRange('run'));
      this.walkAnimation = this.mesh.skeleton.getAnimationRange('walk');
      this.runAnimation = this.mesh.skeleton.getAnimationRange('run');
      this.jumpAnimation = this.mesh.skeleton.getAnimationRange('jump');
      this.powerAnimation = this.mesh.skeleton.getAnimationRange('power');
      const animatable = this.game.scene.beginAnimation(this.mesh.skeleton, 0, 120, true, 2);
      setTimeout(() => {
          animatable.speedRatio /= 8;
      }, 4000);

      this.currentAnimation = null;
      this.currentAnimatable = null;
      /**
      this.walk = new BABYLON.Animation(game.scene.meshes[2])
      this.run = **/
  }

  startAnimationNew(animation) {
      if (this.currentAnimation != animation) {
          this.startAnimation(animation);
      }
  }

  startAnimation (animation) {
      this.currentAnimation = animation;
      this.currentAnimatable = this.game.scene.beginAnimation(this.mesh.skeleton, animation.from+1, animation.to, true, 1);
  }

  animations () {
      // walk animation
      var magnitude = this.body.velocity.length();
      console.log("magnitude:", magnitude);
      if (magnitude < .08 && magnitude < .0999) {
          console.log("surprise");
      }
      if (magnitude < 5) {
          this.startAnimationNew(this.walkAnimation);
          this.currentAnimatable.speedRatio = magnitude/2;
      } else if (magnitude > 5) {
          this.startAnimationNew(this.runAnimation);
          this.currentAnimatable.speedRatio = magnitude/50;
      }
  }

  initCapsule (width, height) {
    // Merges three spheres to create a capsule
    var m0 = BABYLON.Mesh.CreateSphere("m0", width, width, this.game.scene);
    var m1 = BABYLON.MeshBuilder.CreateCylinder("m1", {height: height, diameter: width, tessellation: 20},this.game.scene);
    var m2 = BABYLON.Mesh.CreateSphere("m2", width, width, this.game.scene);
    m0.position.y -= height * 0.5;
    m2.position.y += height * 0.5;
    m0.computeWorldMatrix(true);
	  m1.computeWorldMatrix(true);
	  m2.computeWorldMatrix(true);
    return BABYLON.Mesh.MergeMeshes([m0,m1,m2], true);
  }

  updateMassProperties() {
    this.body.linearDamping = .8;
    this.body.fixedRotation = true;
    this.body.sleepSpeedLimit = 20;
    this.body.updateMassProperties();
  }

  initGroundCheck() {
    // Create mesh for onGround collision check
    this.groundCheck = BABYLON.Mesh.CreateBox("mask", 2.5, this.game.scene);
    this.groundCheck.isVisible = false;
    this.groundCheck.parent = this.mask;
    this.groundCheck.position.y = -3;
    this.groundCheck.scaling.y = 0.2;
  }

  checkGroundCheck() {
    //TODO: http://schteppe.github.io/cannon.js/examples/threejs_voxel_fps.html use this jump check logic
    // Check for ground
    var jumpableMeshes = this.game.scene.getMeshesByTags("checkJump")
    this.onGround = false;
    for (var i in jumpableMeshes) {
      if (this.groundCheck.intersectsMesh(jumpableMeshes[i], true)){
        this.mesh.material.diffuseColor = new BABYLON.Color3.Red();
        this.onGround = true;
      }
    }
  }

  update () {
    this.checkGroundCheck();

    this.animations();

    if (this.moveBool) {
        this.move();
    }

    this._manageMana();
  }

  // use this to make xbox controller movement is smoove and doesn't go over the speed limit
  getScaleSpeed (movementVector, speed) {
      //console.log('movementvector strength:', movementVector.length());
      return speed * Math.min(1, movementVector.length());
  }

  move () {
    // get normalized vector
    var movementVector = new BABYLON.Vector3(this.Input.AXIS_X,0,this.Input.AXIS_Y);
      //console.log('xbox move:', this.Input.AXIS_X, ', ', this.Input.AXIS_Y, ', scaleSpeed:', Math.min(1, movementVector.length()));
    var normalizedMovementVector = movementVector.clone().normalize();
    //console.log('scale speed:', this.getScaleSpeed(movementVector, this.speed));
    if (this.onGround) {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.speed));
    } else {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.airSpeed));
    }

    // Jump
    if (this.onGround && this.Input.JUMP && this.jumpTimer == 0) {
        //console.log("jump!");
        movementVector = movementVector.add(new BABYLON.Vector3(0,this.jumpStrength,0));
        this.mesh.material.diffuseColor = BABYLON.Color3.Blue();
        this.jumpTimer = this.jumpTimerStart;
    }else if (this.jumpTimer > 0) {
      this.jumpTimer -= 1;
    }
    // apply movement at the very end.
    //console.log('ONGROUND:', this.onGround);
    this.mask.applyImpulse(movementVector, this.mask.position);

    if (this.body.velocity.length() > 1 && (this.Input.AXIS_X || this.Input.AXIS_Y) ) {
        this.setRotation();
    }
  }

  setRotation () {
    // Player rotation
    this.mask.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(Math.atan2(this.body.velocity.x, this.body.velocity.z), 0, 0);
  }

  setPlayer(player) {
    (this._inputSubscriptions || {destroy: () => {}}).destroy();
    if (!player) {
      return;
    }
    this._inputSubscriptions = new EventSubscriptionContext(player.input)
      .on('end', () => this.setPlayer())
      .on('joychanged', joyVector => this.handleJoyChanged(joyVector))
      .on('buttondown', button => this.handleButtonDown(button))
      .on('buttonup', button => this.handleButtonUp(button))
    ;
  }

  handleJoyChanged(joyVector) {
      this._joyTarget.joyChanged(joyVector);
  }

    /**
     * Allow the hero to act as a joy target. When this gets
     * called, that means that the hero itself should respond
     * to joy and, e.g., move.
     */
    joyChanged(joyVector) {
        this.Input.AXIS_Y = joyVector.y;
        this.Input.AXIS_X = joyVector.x;
    }

  _handleButton(button, pressed) {
    switch (button) {
        case Buttons.RB: this.Input.JUMP = pressed; break;
    }
  }

  handleButtonDown(button) {
    this._handleButton(button, true);
    switch (button) {
        case Buttons.A: this.attack1.buttonDown(0); break;
        case Buttons.B: this.attack2.buttonDown(0); break;
        case Buttons.X: this.attack3.buttonDown(0); break;
        case Buttons.Y: this.attack4.buttonDown(0); break;
    }
  }

  handleButtonUp(button) {
    this._handleButton(button, false);
    switch (button) {
        case Buttons.A: this.attack1.buttonUp(0); break;
        case Buttons.B: this.attack2.buttonUp(0); break;
        case Buttons.X: this.attack3.buttonUp(0); break;
        case Buttons.Y: this.attack4.buttonUp(0); break;
    }
  }

    _manageMana() {
        if (this._mana < maxMana) {
            this._mana = Math.min(maxMana, this._mana + 1);
        }
    }

    /**
     * Returns false if there is insufficient mana.
     */
    consumeMana(amount) {
        if (this._mana < amount) {
            return false;
        }
        this._mana -= amount;
        return true;
    }

    /**
     * Sets the joy target. The joy target must have a joyChanged
     * function accepting a Vector2. If null the hero will start
     * responding to joy again.
     */
    setJoyTarget(target) {
        target = target || this;
        // Send 0 to original target to set it to rest or whatever
        // instead of leaving it stuck at other value. For existing,
        // will stop movement in the hero.
        this.handleJoyChanged(zeroVector2);
        this._joyTarget = target;
        // Emit 0 to help target with preinitializing itself.
        this.handleJoyChanged(zeroVector2);
    }
}
<commit_msg>animation blending<commit_after>import BABYLON from 'babylonjs';
import {EventSubscriptionContext} from '../../event-util';
import {Buttons} from '../input';
import testPower from './powers/testPower';
import testPower2 from './powers/testPower2';
import testPower3 from './powers/testPower3';

const zeroVector2 = new BABYLON.Vector2(0, 0);
const maxMana = 5000000;

export default class Hero {
  constructor(
    game, name, meshFileName='omi', speed=30, airSpeed=10, jumpStrength=250,
    attack1=testPower, attack2=testPower2, attack3=testPower3, attack4=testPower,
    defense1=testPower, defense2=testPower, defense3=testPower, defense4=testPower){
    this.game = game;
    this.name = name;
      this._mana = maxMana;
      this._joyTarget = this;

    // Create collision mask
    this.mask = this.initCapsule(2,4);
    this.mask.isVisible = false;

    require(`../../../models/heroes/${meshFileName}.blend`).ImportMesh(BABYLON.SceneLoader, null, this.game.scene, loadedMeshes => {
        // Add the mesh
        this.mesh = loadedMeshes[0];//.clone(this.name); // 2 is the index of the player mesh
        // console.log("the player mesh", this.mesh);
        this.mesh.isVisible = true;
        this.mesh.id = this.name;
        this.mesh.parent = this.mask;
        this.mesh.position.y = -3;
        // Add the player mesh to the shadowGenerator
        this.game.shadowGenerator.getShadowMap().renderList.push(this.mesh);
        this.mesh.receiveShadows = true;
        // Add material for debug
        var material = new BABYLON.StandardMaterial("blue_material", game.scene);
        material.diffuseColor = BABYLON.Color3.Blue();
        this.mesh.material = material;

        this.initAnimations();
    });

    // Create the physics body using mask TODO: Make the Impostor a capsule
    this.body = this.mask.setPhysicsState(BABYLON.PhysicsEngine.BoxImpostor, {mass:10, friction:0.05, restitution:0.5});

    this.updateMassProperties();

    this.initGroundCheck();

    // Movement variables
    this.onGround = false;
    this.jumpStrength = jumpStrength;
    this.jumpTimerStart = 20
    this.jumpTimer = this.jumpTimerStart;
    this.speed = speed;
    this.airSpeed = airSpeed;
    this.moveBool = true;

    // Input
    this.Input = {
      AXIS_X : 0,
      AXIS_Y : 0,
      JUMP : false,
    };

    // InitializePowers
    this.attack1 = new attack1(game, this);
    this.attack2 = new attack2(game, this);
    this.attack3 = new attack3(game, this);
    this.attack4 = new attack4(game, this);

    this.defense1 = new defense1(game, this);
    this.defense2 = new defense2(game, this);
    this.defense3 = new defense3(game, this);
    this.defense4 = new defense4(game, this);

    // Add update loop to Babylon
    this.mesh.registerBeforeRender(() => {
        this.update();
    });
  }

  initAnimations () {
      //console.log('animation range', this.mesh.skeleton.getAnimationRange('run'));
      this.walkAnimation = this.mesh.skeleton.getAnimationRange('walk');
      this.runAnimation = this.mesh.skeleton.getAnimationRange('run');
      this.jumpAnimation = this.mesh.skeleton.getAnimationRange('jump');
      this.powerAnimation = this.mesh.skeleton.getAnimationRange('power');
      const animatable = this.game.scene.beginAnimation(this.mesh.skeleton, 0, 120, true, 2);
      setTimeout(() => {
          animatable.speedRatio /= 8;
      }, 4000);

      this.currentAnimation = null;
      this.currentAnimatable = null;
      /**
      this.walk = new BABYLON.Animation(game.scene.meshes[2])
      this.run = **/
  }

  startAnimationNew(animation) {
      if (this.currentAnimation != animation) {
          this.startAnimation(animation);
      }
  }

  startAnimation (animation) {
      this.currentAnimation = animation;
      this.currentAnimatable = this.game.scene.beginAnimation(this.mesh.skeleton, animation.from+1, animation.to, true, 1);
      this.currentAnimatable.enableBlending(.1);
  }

  animations () {
      // walk animation
      var magnitude = this.body.velocity.length();
      if (magnitude < 5) {
          this.startAnimationNew(this.walkAnimation);
          this.currentAnimatable.speedRatio = magnitude/2;
      } else if (magnitude > 5) {
          this.startAnimationNew(this.runAnimation);
          this.currentAnimatable.speedRatio = magnitude/50;
      }
  }

  initCapsule (width, height) {
    // Merges three spheres to create a capsule
    var m0 = BABYLON.Mesh.CreateSphere("m0", width, width, this.game.scene);
    var m1 = BABYLON.MeshBuilder.CreateCylinder("m1", {height: height, diameter: width, tessellation: 20},this.game.scene);
    var m2 = BABYLON.Mesh.CreateSphere("m2", width, width, this.game.scene);
    m0.position.y -= height * 0.5;
    m2.position.y += height * 0.5;
    m0.computeWorldMatrix(true);
	  m1.computeWorldMatrix(true);
	  m2.computeWorldMatrix(true);
    return BABYLON.Mesh.MergeMeshes([m0,m1,m2], true);
  }

  updateMassProperties() {
    this.body.linearDamping = .8;
    this.body.fixedRotation = true;
    this.body.sleepSpeedLimit = 20;
    this.body.updateMassProperties();
  }

  initGroundCheck() {
    // Create mesh for onGround collision check
    this.groundCheck = BABYLON.Mesh.CreateBox("mask", 2.5, this.game.scene);
    this.groundCheck.isVisible = false;
    this.groundCheck.parent = this.mask;
    this.groundCheck.position.y = -3;
    this.groundCheck.scaling.y = 0.2;
  }

  checkGroundCheck() {
    //TODO: http://schteppe.github.io/cannon.js/examples/threejs_voxel_fps.html use this jump check logic
    // Check for ground
    var jumpableMeshes = this.game.scene.getMeshesByTags("checkJump")
    this.onGround = false;
    for (var i in jumpableMeshes) {
      if (this.groundCheck.intersectsMesh(jumpableMeshes[i], true)){
        this.mesh.material.diffuseColor = new BABYLON.Color3.Red();
        this.onGround = true;
      }
    }
  }

  update () {
    this.checkGroundCheck();

    if (this.moveBool) {
        this.move();
    }

    this.animations();

    this._manageMana();
  }

  // use this to make xbox controller movement is smoove and doesn't go over the speed limit
  getScaleSpeed (movementVector, speed) {
      //console.log('movementvector strength:', movementVector.length());
      return speed * Math.min(1, movementVector.length());
  }

  move () {
    // get normalized vector
    var movementVector = new BABYLON.Vector3(this.Input.AXIS_X,0,this.Input.AXIS_Y);
      //console.log('xbox move:', this.Input.AXIS_X, ', ', this.Input.AXIS_Y, ', scaleSpeed:', Math.min(1, movementVector.length()));
    var normalizedMovementVector = movementVector.clone().normalize();
    //console.log('scale speed:', this.getScaleSpeed(movementVector, this.speed));
    if (this.onGround) {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.speed));
    } else {
        movementVector = normalizedMovementVector.scale(this.getScaleSpeed(movementVector, this.airSpeed));
    }

    // Jump
    if (this.onGround && this.Input.JUMP && this.jumpTimer == 0) {
        //console.log("jump!");
        movementVector = movementVector.add(new BABYLON.Vector3(0,this.jumpStrength,0));
        this.mesh.material.diffuseColor = BABYLON.Color3.Blue();
        this.jumpTimer = this.jumpTimerStart;
    }else if (this.jumpTimer > 0) {
      this.jumpTimer -= 1;
    }
    // apply movement at the very end.
    //console.log('ONGROUND:', this.onGround);
    this.mask.applyImpulse(movementVector, this.mask.position);

    if (this.body.velocity.length() > 1 && (this.Input.AXIS_X || this.Input.AXIS_Y) ) {
        this.setRotation();
    }
  }

  setRotation () {
    // Player rotation
    this.mask.rotationQuaternion = BABYLON.Quaternion.RotationYawPitchRoll(Math.atan2(this.body.velocity.x, this.body.velocity.z), 0, 0);
  }

  setPlayer(player) {
    (this._inputSubscriptions || {destroy: () => {}}).destroy();
    if (!player) {
      return;
    }
    this._inputSubscriptions = new EventSubscriptionContext(player.input)
      .on('end', () => this.setPlayer())
      .on('joychanged', joyVector => this.handleJoyChanged(joyVector))
      .on('buttondown', button => this.handleButtonDown(button))
      .on('buttonup', button => this.handleButtonUp(button))
    ;
  }

  handleJoyChanged(joyVector) {
      this._joyTarget.joyChanged(joyVector);
  }

    /**
     * Allow the hero to act as a joy target. When this gets
     * called, that means that the hero itself should respond
     * to joy and, e.g., move.
     */
    joyChanged(joyVector) {
        this.Input.AXIS_Y = joyVector.y;
        this.Input.AXIS_X = joyVector.x;
    }

  _handleButton(button, pressed) {
    switch (button) {
        case Buttons.RB: this.Input.JUMP = pressed; break;
    }
  }

  handleButtonDown(button) {
    this._handleButton(button, true);
    switch (button) {
        case Buttons.A: this.attack1.buttonDown(0); break;
        case Buttons.B: this.attack2.buttonDown(0); break;
        case Buttons.X: this.attack3.buttonDown(0); break;
        case Buttons.Y: this.attack4.buttonDown(0); break;
    }
  }

  handleButtonUp(button) {
    this._handleButton(button, false);
    switch (button) {
        case Buttons.A: this.attack1.buttonUp(0); break;
        case Buttons.B: this.attack2.buttonUp(0); break;
        case Buttons.X: this.attack3.buttonUp(0); break;
        case Buttons.Y: this.attack4.buttonUp(0); break;
    }
  }

    _manageMana() {
        if (this._mana < maxMana) {
            this._mana = Math.min(maxMana, this._mana + 1);
        }
    }

    /**
     * Returns false if there is insufficient mana.
     */
    consumeMana(amount) {
        if (this._mana < amount) {
            return false;
        }
        this._mana -= amount;
        return true;
    }

    /**
     * Sets the joy target. The joy target must have a joyChanged
     * function accepting a Vector2. If null the hero will start
     * responding to joy again.
     */
    setJoyTarget(target) {
        target = target || this;
        // Send 0 to original target to set it to rest or whatever
        // instead of leaving it stuck at other value. For existing,
        // will stop movement in the hero.
        this.handleJoyChanged(zeroVector2);
        this._joyTarget = target;
        // Emit 0 to help target with preinitializing itself.
        this.handleJoyChanged(zeroVector2);
    }
}
<|endoftext|>


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

var igvxhr = (function (igvxhr) {

    // Compression types
    const NONE = 0;
    const GZIP = 1;
    const BGZF = 2;

    igvxhr.isReachable = function (url, continuation) {

        var request = new XMLHttpRequest();

        request.open("HEAD", url, true);

        request.onload = function (event) {

            if (0 === request.status) {
                console.log("igvxhr.isReachable - onload - failure - status " + request.status);
                continuation(false, request.status);
            }
            else if (request.status >= 200 && request.status <= 300) {
                console.log("igvxhr.isReachable - onload - success - status " + request.status);
                continuation(true, request.status);
            }
            else {
                console.log("igvxhr.isReachable - onload - failure - status " + request.status);
                continuation(false, request.status);
            }

        };

        request.onerror = function (event) {
            console.log("igvxhr.isReachable - onerror - status " + request.status);
            continuation(false, request.status);
        };

        request.ontimeout = function (event) {
            console.log("igvxhr.isReachable - ontimeout - status " + request.status);
            continuation(false, request.status);
        };

        request.onabort = function (event) {
            console.log("igvxhr.isReachable - onabort - status " + request.status);
            continuation(false, request.status);
        };

        console.log("igvxhr.isReachable - send - before");
        request.send(null);
        console.log("igvxhr.isReachable - send - after");

    };

    igvxhr.loadArrayBuffer = function (url, options) {
        options.responseType = "arraybuffer";
        igvxhr.load(url, options);
    }

    igvxhr.loadJson = function (url, options) {

        var success = options.success;

        options.contentType = "application/json";
        options.success = function (result) {
            if (result) {
                success(JSON.parse(result));
            }
            else {
                success(null);
            }
        };

        igvxhr.load(url, options);

    }

    /**
     * Load a "raw" string.
     */
    igvxhr.loadString = function (url, options) {

        var success = options.success,
            compression, result;

        if (options.bgz) {
            compression = BGZF;
        }
        else if (url.endsWith(".gz")) {

            compression = GZIP;
        }
        else {
            compression = NONE;
        }

        if (compression === NONE) {

            options.mimeType = 'text/plain; charset=x-user-defined';
            igvxhr.load(url, options);
        }
        else {
            options.responseType = "arraybuffer";
            options.success = function (data) {
                var result = igv.arrayBufferToString(data, compression);
                success(result);
            };
            igvxhr.load(url, options);

        }

    }

    igvxhr.load = function (url, options) {

        var xhr = new XMLHttpRequest(),
            sendData = options.sendData,
            method = options.method || (sendData ? "POST" : "GET"),
            success = options.success,
            error = options.error || success,
            abort = options.abort || error,
            timeout = options.timeout || error,
            task = options.task,
            range = options.range,
            responseType = options.responseType,
            contentType = options.contentType,
            mimeType = options.mimeType,
            headers = options.headers,
            header_keys, key, value, i;

        if (task) task.xhrRequest = xhr;

        xhr.open(method, url);

        if (range) {
            var rangeEnd = range.start + range.size - 1;
            xhr.setRequestHeader("Range", "bytes=" + range.start + "-" + rangeEnd);
            //xhr.setRequestHeader("If-None-Match", Math.random().toString(36));  // For nasty safari bug https://bugs.webkit.org/show_bug.cgi?id=82672
        }
        if (contentType) {
            xhr.setRequestHeader("Content-Type", contentType);
        }
        if (mimeType) {
            xhr.overrideMimeType(mimeType);
        }
        if (responseType) {
            xhr.responseType = responseType;
        }
        if (headers) {
            header_keys = Object.keys(headers);
            for (i = 0; i < header_keys.length; i++) {
                key = header_keys[i];
                value = headers[key];
                console.log("Adding to header: " + key + "=" + value);
                xhr.setRequestHeader(key, value);
            }
        }

        xhr.onload = function (event) {
            // when the url points to a local file, the status is 0 but that is no error
            if (xhr.status == 0 || (xhr.status >= 200 && xhr.status <= 300)) {
                success(xhr.response, xhr);
            }
            else {
                error(null, xhr);
            }

        };

        xhr.onerror = function (event) {

            if (isCrossDomain(url) && url) {
                // Try the proxy, if it exists.  Presumably this is a php file
                if (igv.browser.crossDomainProxy && url != igv.browser.crossDomainProxy) {

                    options.sendData = "url=" + url;

                    igvxhr.load(igv.browser.crossDomainProxy, options);
                    return;
                }
            }
            error(null, xhr);
        };

        xhr.ontimeout = function (event) {
            console.log("Aborted");
            timeout(null, xhr);
        };

        xhr.onabort = function (event) {
            console.log("Aborted");
            abort(null, xhr);
        };

        xhr.send(sendData);

    };

    igvxhr.loadHeader = function (url, options) {

        var xhr = new XMLHttpRequest(),
            method = "HEAD",
            success = options.success,
            error = options.error || success,
            timeout = options.timeout || error,
            headers = options.headers,
            header_keys,
            key,
            value,
            i;

        if (headers) {
            header_keys = Object.keys(headers);
            for (i = 0; i < header_keys.length; i++) {
                key = header_keys[i];
                value = headers[key];
                console.log("Adding to header: " + key + "=" + value);
                xhr.setRequestHeader(key, value);
            }
        }

        xhr.open(method, url);

        xhr.onload = function (event) {

            var headerStr = xhr.getAllResponseHeaders();
            var headerDictionary = parseResponseHeaders(headerStr);
            success(headerDictionary);
        }

        xhr.onerror = function (event) {
            error(null, xhr);
        }

        xhr.ontimeout = function (event) {
            timeout(null);
        }

        xhr.send();

        /**
         * XmlHttpRequest's getAllResponseHeaders() method returns a string of response
         * headers according to the format described here:
         * http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
         * This method parses that string into a user-friendly key/value pair object.
         */
        function parseResponseHeaders(headerStr) {
            var headers = {};
            if (!headerStr) {
                return headers;
            }
            var headerPairs = headerStr.split('\u000d\u000a');
            for (var i = 0, len = headerPairs.length; i < len; i++) {
                var headerPair = headerPairs[i];
                var index = headerPair.indexOf('\u003a\u0020');
                if (index > 0) {
                    var key = headerPair.substring(0, index);
                    var val = headerPair.substring(index + 2);
                    headers[key] = val;
                }
            }
            return headers;
        }

    }

    igvxhr.getContentLength = function (url, options) {

        var continuation = options.success;

        if (!options.error) {
            options.error = function () {
                continuation(-1);
            }
        }

        options.success = function (header) {
            var contentLengthString = header ? header["Content-Length"] : null;
            if (contentLengthString) {
                continuation(parseInt(contentLengthString));
            }
            else {
                continuation(Math.MAX_VALUE);    // Don't know the content length
            }

        }

        igvxhr.loadHeader(url, options);
    }

    igvxhr.loadStringFromFile = function (localfile, options) {

        var fileReader = new FileReader(),
            success = options.success,
            error = options.error || options.success,
            abort = options.abort || options.error,
            timeout = options.timeout || options.error,
            range = options.range;

        fileReader.onload = function (e) {

            var compression, result;

            if (options.bgz) {
                compression = BGZF;
            }
            else if (localfile.name.endsWith(".gz")) {

                compression = GZIP;
            }
            else {
                compression = NONE;
            }

            result = igv.arrayBufferToString(fileReader.result, compression);

            success(result, localfile);

        };

        fileReader.onerror = function (e) {
            console.log("error uploading local file " + localfile.name);
            error(null, fileReader);
        };

        fileReader.readAsArrayBuffer(localfile);

    }

    function isCrossDomain(url) {

        var origin = window.location.origin;

        return !url.startsWith(origin);

    }

    igv.arrayBufferToString = function (arraybuffer, compression) {

        var plain, inflate;

        if (compression === GZIP) {
            inflate = new Zlib.Gunzip(new Uint8Array(arraybuffer));
            plain = inflate.decompress();
        }
        else if (compression === BGZF) {
            plain = new Uint8Array(igv.unbgzf(arraybuffer));
        }
        else {
            plain = new Uint8Array(arraybuffer);
        }

        var result = "";
        for (var i = 0, len = plain.length; i < len; i++) {
            result = result + String.fromCharCode(plain[i]);
        }
        return result;
    }

    return igvxhr;

})(igvxhr || {});

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

var igvxhr = (function (igvxhr) {

    // Compression types
    const NONE = 0;
    const GZIP = 1;
    const BGZF = 2;

    igvxhr.isReachable = function (url, continuation) {

        var request = new XMLHttpRequest();

        request.open("HEAD", url, true);

        request.onload = function (event) {

            if (0 === request.status) {
                console.log("igvxhr.isReachable - onload - failure - status " + request.status);
                continuation(false, request.status);
            }
            else if (request.status >= 200 && request.status <= 300) {
                console.log("igvxhr.isReachable - onload - success - status " + request.status);
                continuation(true, request.status);
            }
            else {
                console.log("igvxhr.isReachable - onload - failure - status " + request.status);
                continuation(false, request.status);
            }

        };

        request.onerror = function (event) {
            console.log("igvxhr.isReachable - onerror - status " + request.status);
            continuation(false, request.status);
        };

        request.ontimeout = function (event) {
            console.log("igvxhr.isReachable - ontimeout - status " + request.status);
            continuation(false, request.status);
        };

        request.onabort = function (event) {
            console.log("igvxhr.isReachable - onabort - status " + request.status);
            continuation(false, request.status);
        };

        console.log("igvxhr.isReachable - send - before");
        request.send(null);
        console.log("igvxhr.isReachable - send - after");

    };

    igvxhr.loadArrayBuffer = function (url, options) {
        options.responseType = "arraybuffer";
        igvxhr.load(url, options);
    }

    igvxhr.loadJson = function (url, options) {

        var success = options.success;

        options.contentType = "application/json";
        options.success = function (result) {
            if (result) {
                success(JSON.parse(result));
            }
            else {
                success(null);
            }
        };

        igvxhr.load(url, options);

    }

    /**
     * Load a "raw" string.
     */
    igvxhr.loadString = function (url, options) {

        var success = options.success,
            compression, result;

        if (options.bgz) {
            compression = BGZF;
        }
        else if (url.endsWith(".gz")) {

            compression = GZIP;
        }
        else {
            compression = NONE;
        }

        if (compression === NONE) {

            options.mimeType = 'text/plain; charset=x-user-defined';
            igvxhr.load(url, options);
        }
        else {
            options.responseType = "arraybuffer";
            options.success = function (data) {
                var result = igv.arrayBufferToString(data, compression);
                success(result);
            };
            igvxhr.load(url, options);

        }

    }

    igvxhr.load = function (url, options) {

        var xhr = new XMLHttpRequest(),
            sendData = options.sendData,
            method = options.method || (sendData ? "POST" : "GET"),
            success = options.success,
            error = options.error || success,
            abort = options.abort || error,
            timeout = options.timeout || error,
            task = options.task,
            range = options.range,
            responseType = options.responseType,
            contentType = options.contentType,
            mimeType = options.mimeType,
            headers = options.headers,
            header_keys, key, value, i;

        if (task) task.xhrRequest = xhr;

        if(range) {
            // Add random seed. For nasty safari bug https://bugs.webkit.org/show_bug.cgi?id=82672
            // TODO -- add some "isSafari" test?
            url += url.contains("?") ? "&" : "?";
            url += "someRandomSeed=" + Math.random().toString(36);
        }

        xhr.open(method, url);

        if (range) {
            var rangeEnd = range.start + range.size - 1;
            xhr.setRequestHeader("Range", "bytes=" + range.start + "-" + rangeEnd);
            //xhr.setRequestHeader("If-None-Match", Math.random().toString(36));  // For nasty safari bug https://bugs.webkit.org/show_bug.cgi?id=82672
        }
        if (contentType) {
            xhr.setRequestHeader("Content-Type", contentType);
        }
        if (mimeType) {
            xhr.overrideMimeType(mimeType);
        }
        if (responseType) {
            xhr.responseType = responseType;
        }
        if (headers) {
            header_keys = Object.keys(headers);
            for (i = 0; i < header_keys.length; i++) {
                key = header_keys[i];
                value = headers[key];
                console.log("Adding to header: " + key + "=" + value);
                xhr.setRequestHeader(key, value);
            }
        }

        xhr.onload = function (event) {
            // when the url points to a local file, the status is 0 but that is no error
            if (xhr.status == 0 || (xhr.status >= 200 && xhr.status <= 300)) {
                success(xhr.response, xhr);
            }
            else {
                error(null, xhr);
            }

        };

        xhr.onerror = function (event) {

            if (isCrossDomain(url) && url) {
                // Try the proxy, if it exists.  Presumably this is a php file
                if (igv.browser.crossDomainProxy && url != igv.browser.crossDomainProxy) {

                    options.sendData = "url=" + url;

                    igvxhr.load(igv.browser.crossDomainProxy, options);
                    return;
                }
            }
            error(null, xhr);
        };

        xhr.ontimeout = function (event) {
            console.log("Aborted");
            timeout(null, xhr);
        };

        xhr.onabort = function (event) {
            console.log("Aborted");
            abort(null, xhr);
        };

        xhr.send(sendData);

    };

    igvxhr.loadHeader = function (url, options) {

        var xhr = new XMLHttpRequest(),
            method = "HEAD",
            success = options.success,
            error = options.error || success,
            timeout = options.timeout || error,
            headers = options.headers,
            header_keys,
            key,
            value,
            i;

        if (headers) {
            header_keys = Object.keys(headers);
            for (i = 0; i < header_keys.length; i++) {
                key = header_keys[i];
                value = headers[key];
                console.log("Adding to header: " + key + "=" + value);
                xhr.setRequestHeader(key, value);
            }
        }

        xhr.open(method, url);

        xhr.onload = function (event) {

            var headerStr = xhr.getAllResponseHeaders();
            var headerDictionary = parseResponseHeaders(headerStr);
            success(headerDictionary);
        }

        xhr.onerror = function (event) {
            error(null, xhr);
        }

        xhr.ontimeout = function (event) {
            timeout(null);
        }

        xhr.send();

        /**
         * XmlHttpRequest's getAllResponseHeaders() method returns a string of response
         * headers according to the format described here:
         * http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
         * This method parses that string into a user-friendly key/value pair object.
         */
        function parseResponseHeaders(headerStr) {
            var headers = {};
            if (!headerStr) {
                return headers;
            }
            var headerPairs = headerStr.split('\u000d\u000a');
            for (var i = 0, len = headerPairs.length; i < len; i++) {
                var headerPair = headerPairs[i];
                var index = headerPair.indexOf('\u003a\u0020');
                if (index > 0) {
                    var key = headerPair.substring(0, index);
                    var val = headerPair.substring(index + 2);
                    headers[key] = val;
                }
            }
            return headers;
        }

    }

    igvxhr.getContentLength = function (url, options) {

        var continuation = options.success;

        if (!options.error) {
            options.error = function () {
                continuation(-1);
            }
        }

        options.success = function (header) {
            var contentLengthString = header ? header["Content-Length"] : null;
            if (contentLengthString) {
                continuation(parseInt(contentLengthString));
            }
            else {
                continuation(Math.MAX_VALUE);    // Don't know the content length
            }

        }

        igvxhr.loadHeader(url, options);
    }

    igvxhr.loadStringFromFile = function (localfile, options) {

        var fileReader = new FileReader(),
            success = options.success,
            error = options.error || options.success,
            abort = options.abort || options.error,
            timeout = options.timeout || options.error,
            range = options.range;

        fileReader.onload = function (e) {

            var compression, result;

            if (options.bgz) {
                compression = BGZF;
            }
            else if (localfile.name.endsWith(".gz")) {

                compression = GZIP;
            }
            else {
                compression = NONE;
            }

            result = igv.arrayBufferToString(fileReader.result, compression);

            success(result, localfile);

        };

        fileReader.onerror = function (e) {
            console.log("error uploading local file " + localfile.name);
            error(null, fileReader);
        };

        fileReader.readAsArrayBuffer(localfile);

    }

    function isCrossDomain(url) {

        var origin = window.location.origin;

        return !url.startsWith(origin);

    }

    igv.arrayBufferToString = function (arraybuffer, compression) {

        var plain, inflate;

        if (compression === GZIP) {
            inflate = new Zlib.Gunzip(new Uint8Array(arraybuffer));
            plain = inflate.decompress();
        }
        else if (compression === BGZF) {
            plain = new Uint8Array(igv.unbgzf(arraybuffer));
        }
        else {
            plain = new Uint8Array(arraybuffer);
        }

        var result = "";
        for (var i = 0, len = plain.length; i < len; i++) {
            result = result + String.fromCharCode(plain[i]);
        }
        return result;
    }

    return igvxhr;

})(igvxhr || {});

<|endoftext|>


<commit_before>function makeData() {
  "use strict";
  return makeRandomData(20);

}

function run(svg, data, Plottable) {
  "use strict";

  var ds = new Plottable.Dataset(data);

  var xScale = new Plottable.Scales.Linear();
  var yScale = new Plottable.Scales.Linear();
  var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
  var yAxis = new Plottable.Axes.Numeric(yScale, "left");

  var plot = new Plottable.Plots.Line(xScale, yScale);
  plot.addDataset(ds);
  plot.x(function(d){ return d.y; }, xScale)
      .y(function(d){ return d.x; }, yScale)
      .autorange("x");
;

  var table = new Plottable.Components.Table([[yAxis, plot],
                                             [null, xAxis]]);
  table.renderTo(svg);

  var pzi = new Plottable.Interactions.PanZoom(null, yScale);
  pzi.attachTo(plot);

}
<commit_msg>remove stray semicolon from test<commit_after>function makeData() {
  "use strict";
  return makeRandomData(20);

}

function run(svg, data, Plottable) {
  "use strict";

  var ds = new Plottable.Dataset(data);

  var xScale = new Plottable.Scales.Linear();
  var yScale = new Plottable.Scales.Linear();
  var xAxis = new Plottable.Axes.Numeric(xScale, "bottom");
  var yAxis = new Plottable.Axes.Numeric(yScale, "left");

  var plot = new Plottable.Plots.Line(xScale, yScale);
  plot.addDataset(ds);
  plot.x(function(d){ return d.y; }, xScale)
      .y(function(d){ return d.x; }, yScale)
      .autorange("x");

  var table = new Plottable.Components.Table([[yAxis, plot],
                                             [null, xAxis]]);
  table.renderTo(svg);

  var pzi = new Plottable.Interactions.PanZoom(null, yScale);
  pzi.attachTo(plot);

}
<|endoftext|>


<commit_before>
var singleValue = ['id', 'fullName'];

var multiValue = ['email', 'phone'];

var people = Ti.Contacts.getAllPeople();

for (var i=0, ilen=people.length; i<ilen; i++){
	var person = people[i];

	if (JSON.stringify(person[multiValue[1]]) != '{}'){
		if (JSON.stringify(person[multiValue[0]]) != '{}'){
			Ti.API.info('phone:' + JSON.stringify(person[multiValue[1]]));

			var newContact = Ti.UI.createTableViewRow();

			var vista = Ti.UI.createView({
				borderColor: "#afafaf",
				borderRadius: "5",
				height: "50",
				backgroundColor:'#e7e9e7',
			});

			var nombreContacto = Ti.UI.createLabel({
				text: person[singleValue[1]],
				left:'5%',
				color: '#000'
			});

			/*
			var check = Ti.UI.createSwitch({
				type: Titanium.UI.Android.SWITCH_STYLE_CHECKBOX,
				width: "45",
				height: "45",
				right: "3%",
				borderColor: "#afafaf",
				borderRadius: "5",
				//backgroundColor: "#fff",
				//color: "#fff",
				value: "false"
			});

			/*
			 check.addEventListener('change', function(e){
				Ti.API.info(check.value);
				if(check.value == true){
					check.backgroundColor = "#fff";
					check.color = "#fff";
				} else{
					check.backgroundColor = "#0071bc";
					check.color = "#0071bc";
				}
			});

			*/
			var checkbox = createCheckbox({});

			vista.add(nombreContacto);
			//vista.add(check);
			vista.add(checkbox);
			newContact.add(vista);
			$.contactList.appendRow(newContact);
		}
	}
};

function createCheckbox (specs) {
    if(typeof specs != "object")
        specs = {};
    specs.width = specs.width || 45;
    specs.backgroundColor = specs.unCheckedColor || "white";
    specs.height = specs.height || 45;
    specs.border = specs.border || 5;
    specs.right =  specs.right || "3%";
    specs.borderColor = specs.borderColor || "silver";
    var viw = Ti.UI.createView(specs);

    function togglecheck () {
        if(!viw.checked) {
            viw.checked = true;
            viw.backgroundColor = specs.checkedColor || "#0071bc";
        }
        else {
            viw.checked = false;
            viw.backgroundColor = specs.unCheckedColor || "white";
        }
    }
    viw.addEventListener("click",togglecheck);

    return viw;
}

$.ventana.open();

<commit_msg>comentario<commit_after>
var singleValue = ['id', 'fullName'];

var multiValue = ['email', 'phone'];

var people = Ti.Contacts.getAllPeople();

for (var i=0, ilen=people.length; i<ilen; i++){
	var person = people[i];

	if (JSON.stringify(person[multiValue[1]]) != '{}'){
		if (JSON.stringify(person[multiValue[0]]) != '{}'){
			Ti.API.info('phone:' + JSON.stringify(person[multiValue[1]]));

			var newContact = Ti.UI.createTableViewRow();

			var vista = Ti.UI.createView({
				borderColor: "#afafaf",
				borderRadius: "5",
				height: "50",
				backgroundColor:'#e7e9e7',
			});

			var nombreContacto = Ti.UI.createLabel({
				text: person[singleValue[1]],
				left:'5%',
				color: '#000'
			});

			/*
			var check = Ti.UI.createSwitch({
				type: Titanium.UI.Android.SWITCH_STYLE_CHECKBOX,
				width: "45",
				height: "45",
				right: "3%",
				borderColor: "#afafaf",
				borderRadius: "5",
				//backgroundColor: "#fff",
				//color: "#fff",
				value: "false"
			});

			/*
			 check.addEventListener('change', function(e){
				Ti.API.info(check.value);
				if(check.value == true){
					check.backgroundColor = "#fff";
					check.color = "#fff";
				} else{
					check.backgroundColor = "#0071bc";
					check.color = "#0071bc";
				}
			});

			*/
			var checkbox = createCheckbox({});

			vista.add(nombreContacto);
			//vista.add(check);
			vista.add(checkbox);
			newContact.add(vista);
			$.contactList.appendRow(newContact);
		}
	}
};

function createCheckbox (specs) {
    if(typeof specs != "object")
        specs = {};
    specs.width = specs.width || 45;
    specs.backgroundColor = specs.unCheckedColor || "white";
    specs.height = specs.height || 45;
    specs.border = specs.border || 5;
    specs.right =  specs.right || "3%";
    specs.borderColor = specs.borderColor || "silver";
    var viw = Ti.UI.createView(specs);

    function togglecheck () {
        if(!viw.checked) {
            viw.checked = true;
            viw.backgroundColor = specs.checkedColor || "#0071bc";
        }
        else {
            viw.checked = false;
            viw.backgroundColor = specs.unCheckedColor || "white";
        }
    }
    viw.addEventListener("click",togglecheck);

    return viw;

    //cambiocambiocambiocambiocambiocambiocambio
}

$.ventana.open();

<|endoftext|>