<commit_before>/**
 * CoCoNote Bridge
 * Listen for tactile events in JavaScript
 *
 * Version 0.0.1
 *
 * 15/07/2014
 *
 * @preserve Copyright @ VirtualSensitive 2014 <florent.schildknecht@gmail.com>
 */

// CCNBridge Revealing Module
var CCNBridge = (function () {
  'use strict';

  // Variables
  var events,
      getEvents,
      listeners,
      getListeners,
      on,
      onClick,
      onDoubleClick,
      onHandle,
      onMove,
      onRelease,
      onDragStart,
      onDrag,
      onDragEnd,
      onDragEnter,
      onDragOver,
      onDragLeave,
      onDrop,
      onScroll,
      onRotateStart,
      onRotate,
      onRotateEnd,
      onZoom,
      off,
      offClick,
      offDoubleClick,
      offHandle,
      offMove,
      offRelease,
      offDragStart,
      offDrag,
      offDragEnd,
      offDragEnter,
      offDragOver,
      offDragLeave,
      offDrop,
      offScroll,
      offRotateStart,
      offRotate,
      offRotateEnd,
      offZoom,
      removeAllListeners,
      windowListener,
      trigger;

  events = {
    'click': 'click',
    'dblclick': 'double-click',
    'handle': 'handle',
    'move': 'move',
    'release': 'release',
    'dragstart': 'drag-start',
    'drag': 'drag',
    'dragend': 'drag-end',
    'dragenter': 'drag-enter',
    'dragover': 'drag-over',
    'dragleave': 'drag-leave',
    'drop': 'drop',
    'scroll': 'scroll',
    'rotatestart': 'rotate-start',
    'rotate': 'rotate',
    'rotateend': 'rotate-end',
    'zoom': 'zoom'
  };

  listeners = {
    'click': [],
    'double-click': [],
    'handle': [],
    'move': [],
    'release': [],
    'drag-start': [],
    'drag': [],
    'drag-end': [],
    'drag-enter': [],
    'drag-over': [],
    'drag-leave': [],
    'drop': [],
    'scroll': [],
    'rotate-start': [],
    'rotate': [],
    'rotate-end': [],
    'zoom': []
  };

  /**
   * Trigger method for JavaScript and C++ events
   *
   * Execute every callbacks registred for the given event
   */
  trigger = function (eventType, event) {
    var listenerType, listenersList, l;

    // Check if the event-type is defined by this API
    if (!(eventType in events)) {
      throw 'Impossible to trigger event : ' + eventType;
    }

    listenerType = events[eventType];
    // Get the callbacks list
    listenersList = listeners[listenerType];
    l = listenersList.length - 1;

    while (l >= 0) {
      // For each callback, execute it with the given scope
      listenersList[l].callback.apply(listenersList[l].scope, [event]);
      l = l-1;
    }
  };

  windowListener = (function (root) {
    var on,
      clickHandler,
      doubleClickHandler,
      mouseDownHandler,
      mouseMoveHandler,
      mouseUpHandler,
      touchStartHandler,
      touchMoveHandler,
      touchEndHandler,
      dragStartHandler,
      dragHandler,
      dragEndHandler,
      dragEnterHandler,
      dragOverHandler,
      dragLeaveHandler,
      dropHandler,
      scrollHandler,
      rotateStartHandler,
      rotateHandler,
      rotateEndHandler,
      zoomHandler,
      off;
    clickHandler = function (event) {
      trigger.apply(root, ['click', event]);
    };
    doubleClickHandler = function (event) {
      trigger.apply(root, ['dblclick', event]);
    };
    mouseDownHandler = function (event) {
      trigger.apply(root, ['handle', event]);
    };
    mouseMoveHandler = function (event) {
      trigger.apply(root, ['move', event]);
    };
    mouseUpHandler = function (event) {
      trigger.apply(root, ['release', event]);
    };
    touchStartHandler = function (event) {
      trigger.apply(root, ['handle', event]);
    };
    touchMoveHandler = function (event) {
      trigger.apply(root, ['move', event]);
    };
    touchEndHandler = function (event) {
      trigger.apply(root, ['release', event]);
    };
    dragStartHandler = function (event) {
      trigger.apply(root, ['dragstart', event]);
    };
    dragHandler = function (event) {
      trigger.apply(root, ['drag', event]);
    };
    dragEndHandler = function (event) {
      trigger.apply(root, ['dragend', event]);
    };
    dragEnterHandler = function (event) {
      trigger.apply(root, ['dragenter', event]);
    };
    dragOverHandler = function (event) {
      trigger.apply(root, ['dragover', event]);
    };
    dragLeaveHandler = function (event) {
      trigger.apply(root, ['dragleave', event]);
    };
    dropHandler = function (event) {
      trigger.apply(root, ['drop', event]);
    };
    scrollHandler = function (event) {
      trigger.apply(root, ['scroll', event]);
    };
    rotateStartHandler = function (event) {
      trigger.apply(root, ['rotatestart', event]);
    };
    rotateHandler = function (event) {
      trigger.apply(root, ['rotate', event]);
    };
    rotateEndHandler = function (event) {
      trigger.apply(root, ['rotateend', event]);
    };
    zoomHandler = function (event) {
      trigger.apply(root, ['zoom', event]);
    };
    on = function () {
      window.addEventListener('click', clickHandler, false);
      window.addEventListener('dblclick', doubleClickHandler, false);
      window.addEventListener('mousedown', mouseDownHandler, false);
      window.addEventListener('mousemove', mouseMoveHandler, false);
      window.addEventListener('mouseup', mouseUpHandler, false);
      window.addEventListener('touchstart', touchStartHandler, false);
      window.addEventListener('touchmove', touchMoveHandler, false);
      window.addEventListener('touchend', touchEndHandler, false);
      window.addEventListener('dragstart', dragStartHandler, false);
      window.addEventListener('drag', dragHandler, false);
      window.addEventListener('dragend', dragEndHandler, false);
      window.addEventListener('dragenter', dragEnterHandler, false);
      window.addEventListener('dragover', dragOverHandler, false);
      window.addEventListener('dragleave', dragLeaveHandler, false);
      window.addEventListener('drop', dropHandler, false);
      window.addEventListener('scroll', scrollHandler, false);
      window.addEventListener('rotatestart', rotateStartHandler, false);
      window.addEventListener('rotate', rotateHandler, false);
      window.addEventListener('rotateend', rotateEndHandler, false);
      window.addEventListener('zoom', zoomHandler, false);
    };
    off = function () {
      window.removeEventListener('click', clickHandler, false);
      window.removeEventListener('dblclick', doubleClickHandler, false);
      window.removeEventListener('mousedown', mouseDownHandler, false);
      window.removeEventListener('mousemove', mouseMoveHandler, false);
      window.removeEventListener('mouseup', mouseUpHandler, false);
      window.removeEventListener('touchstart', touchStartHandler, false);
      window.removeEventListener('touchmove', touchMoveHandler, false);
      window.removeEventListener('touchend', touchEndHandler, false);
      window.removeEventListener('dragstart', dragStartHandler, false);
      window.removeEventListener('drag', dragHandler, false);
      window.removeEventListener('dragend', dragEndHandler, false);
      window.removeEventListener('dragenter', dragEnterHandler, false);
      window.removeEventListener('dragover', dragOverHandler, false);
      window.removeEventListener('dragleave', dragLeaveHandler, false);
      window.removeEventListener('drop', dropHandler, false);
      window.removeEventListener('scroll', scrollHandler, false);
      window.removeEventListener('rotatestart', rotateStartHandler, false);
      window.removeEventListener('rotate', rotateHandler, false);
      window.removeEventListener('rotateend', rotateEndHandler, false);
      window.removeEventListener('zoom', zoomHandler, false);
    };
    return {
      'on': on,
      'off': off
    };
  })(this);

  window.addEventListener('load', function (event) {
    windowListener.on();
  });

  /**
   * Get listeners
   *
   * @return array
   */
  getListeners = function () {
    return listeners;
  };

  /**
   * Get events
   *
   * @return array
   */
  getEvents = function () {
    return events;
  };

  // Methods
  /**
   * Register a callback for an event
   */
  on = function (eventType, callback, scope) {
    var listenerType;
    scope = scope || window;

    // Check if the event-type is defined by this API
    if (!(eventType in events)) {
      throw 'Impossible to bind event : ' + eventType;
    }

    listenerType = events[eventType];

    // Push a new listener that will be executed when this event will occur
    listeners[listenerType].push({
      'scope': scope,
      'callback': callback
    });
  };

  /**
   * Alias for "on" method with click event-type
   */
  onClick = function (callback, scope) {
    this.on('click', callback, scope);
  };

  /**
   * Alias for "on" method with double-click event-type
   */
  onDoubleClick = function (callback, scope) {
    this.on('dblclick', callback, scope);
  };

  /**
   * Alias for "on" method with handle event-type
   */
  onHandle = function (callback, scope) {
    this.on('handle', callback, scope);
  };

  /**
   * Alias for "on" method with move event-type
   */
  onMove = function (callback, scope) {
    this.on('move', callback, scope);
  };

  /**
   * Alias for "on" method with release event-type
   */
  onRelease = function (callback, scope) {
    this.on('release', callback, scope);
  };

  /**
   * Alias for "on" method with dragstart event-type
   */
  onDragStart = function (callback, scope) {
    this.on('dragstart', callback, scope);
  };

  /**
   * Alias for "on" method with drag event-type
   */
  onDrag = function (callback, scope) {
    this.on('drag', callback, scope);
  };

  /**
   * Alias for "on" method with dragend event-type
   */
  onDragEnd = function (callback, scope) {
    this.on('dragend', callback, scope);
  };

  /**
   * Alias for "on" method with dragenter event-type
   */
  onDragEnter = function (callback, scope) {
    this.on('dragenter', callback, scope);
  };

  /**
   * Alias for "on" method with dragover event-type
   */
  onDragOver = function (callback, scope) {
    this.on('dragover', callback, scope);
  };

  /**
   * Alias for "on" method with dragleave event-type
   */
  onDragLeave = function (callback, scope) {
    this.on('dragleave', callback, scope);
  };

  /**
   * Alias for "on" method with drop event-type
   */
  onDrop = function (callback, scope) {
    this.on('drop', callback, scope);
  };

  /**
   * Alias for "on" method with scroll event-type
   */
  onScroll = function (callback, scope) {
    this.on('scroll', callback, scope);
  };

  /**
   * Alias for "on" method with rotatestart event-type
   */
  onRotateStart = function (callback, scope) {
    this.on('rotatestart', callback, scope);
  };

  /**
   * Alias for "on" method with rotate event-type
   */
  onRotate = function (callback, scope) {
    this.on('rotate', callback, scope);
  };

  /**
   * Alias for "on" method with rotateend event-type
   */
  onRotateEnd = function (callback, scope) {
    this.on('rotateend', callback, scope);
  };

  /**
   * Alias for "on" method with zoom event-type
   */
  onZoom = function (callback, scope) {
    this.on('zoom', callback, scope);
  };

  /**
   * Unregister a previously registred callback for (an optionnal) event
   * warning: This should not works for anonymous callbacks
   */
  off = function (eventType, callback, scope) {
    var listenerType, listenersList, indexOfCallbackInList, index;
    scope = scope || window;

    // Check if the event-type is defined by this API
    if (eventType && eventType in events) {
      listenerType = events[eventType];

      if (callback) {
        // Get the current listeners list for the given event
        listenersList = listeners[listenerType];
        // Get the callback index in the list
        indexOfCallbackInList = function (list, callback, scope) {
          var l = list.length - 1;
          while (l >= 0) {
            var item = list[l];
            // Compare both callback and scope
            if (item.scope === scope && item.callback === callback) {
              return l;
            }
            l = l-1;
          }

          return -1;
        };
        index = indexOfCallbackInList(listenersList, callback, scope);

        // If the callback is found, remove it from the list
        if (index > (-1)) {
          listenersList.splice(index, 1);
        }
      } else {
        // If the callback is not given, remove all callbacks of the event
        listeners[listenerType] = [];
      }
    } else {
      // If the event is not given, remove all callbacks of all events
      listeners = {
        'translation': [],
        'rotation': [],
        'zoom': []
      };
    }
  };

  /**
   * Alias for "off" method with click event-type
   */
  offClick = function (callback, scope) {
    this.off('click', callback, scope);
  };

  /**
   * Alias for "off" method with double-click event-type
   */
  offDoubleClick = function (callback, scope) {
    this.off('double-click', callback, scope);
  };

  /**
   * Alias for "off" method with handle event-type
   */
  offHandle = function (callback, scope) {
    this.off('handle', callback, scope);
  };

  /**
   * Alias for "off" method with move event-type
   */
  offMove = function (callback, scope) {
    this.off('move', callback, scope);
  };

  /**
   * Alias for "off" method with release event-type
   */
  offRelease = function (callback, scope) {
    this.off('release', callback, scope);
  };

  /**
   * Alias for "off" method with drag event-type
   */
  offDrag = function (callback, scope) {
    this.off('drag', callback, scope);
  };

  /**
   * Alias for "off" method with drop event-type
   */
  offDrop = function (callback, scope) {
    this.off('drop', callback, scope);
  };

  /**
   * Alias for "off" method with scroll event-type
   */
  offScroll = function (callback, scope) {
    this.off('scroll', callback, scope);
  };

  /**
   * Alias for "off" method with rotatestart event-type
   */
  offRotateStart = function (callback, scope) {
    this.off('rotatestart', callback, scope);
  };

  /**
   * Alias for "off" method with rotate event-type
   */
  offRotate = function (callback, scope) {
    this.off('rotate', callback, scope);
  };

  /**
   * Alias for "off" method with rotateend event-type
   */
  offRotateEnd = function (callback, scope) {
    this.off('rotateend', callback, scope);
  };

  /**
   * Alias for "off" method with zoom event-type
   */
  offZoom = function (callback, scope) {
    this.off('zoom', callback, scope);
  };

  /**
   * Unregister all previously registred callbacks for (an optionnal) event
   * warning: This should not works for anonymous callbacks
   */
  removeAllListeners = function (eventType) {
    this.off(eventType);
  };

  // Public scope : return all accessible methods
  return {
    'getEvents': getEvents,
    'getListeners': getListeners,
    'on': on,
    'onClick': onClick,
    'onHandle': onHandle,
    'onMove': onMove,
    'onRelease': onRelease,
    'onDragStart': onDragStart,
    'onDrag': onDrag,
    'onDragEnd': onDragEnd,
    'onDragEnter': onDragEnter,
    'onDragOver': onDragOver,
    'onDragLeave': onDragLeave,
    'onDrop': onDrop,
    'onScroll': onScroll,
    'onRotateStart': onRotateStart,
    'onRotate': onRotate,
    'onRotateEnd': onRotateEnd,
    'onZoom': onZoom,
    'off': off,
    'offClick': offClick,
    'offHandle': offHandle,
    'offMove': offMove,
    'offRelease': offRelease,
    'offDragStart': offDragStart,
    'offDrag': offDrag,
    'offDragEnd': offDragEnd,
    'offDragEnter': offDragEnter,
    'offDragOver': offDragOver,
    'offDragLeave': offDragLeave,
    'offDrop': offDrop,
    'offScroll': offScroll,
    'offRotateStart': offRotateStart,
    'offRotate': offRotate,
    'offRotateEnd': offRotateEnd,
    'offZoom': offZoom,
    'removeAllListeners': removeAllListeners
  };
})();

module.exports = CCNBridge;
<commit_msg>Comment CCNBridge library<commit_after>/**
 * CoCoNote Bridge
 * Listen for tactile events in JavaScript
 *
 * Version 0.0.1
 *
 * 15/07/2014
 *
 * @preserve Copyright @ VirtualSensitive 2014 <florent.schildknecht@gmail.com>
 */

// CCNBridge Revealing Module
var CCNBridge = (function () {
  'use strict';

  // Variables
  var events,
      getEvents,
      listeners,
      getListeners,
      on,
      onClick,
      onDoubleClick,
      onHandle,
      onMove,
      onRelease,
      onDragStart,
      onDrag,
      onDragEnd,
      onDragEnter,
      onDragOver,
      onDragLeave,
      onDrop,
      onScroll,
      onRotateStart,
      onRotate,
      onRotateEnd,
      onZoom,
      off,
      offClick,
      offDoubleClick,
      offHandle,
      offMove,
      offRelease,
      offDragStart,
      offDrag,
      offDragEnd,
      offDragEnter,
      offDragOver,
      offDragLeave,
      offDrop,
      offScroll,
      offRotateStart,
      offRotate,
      offRotateEnd,
      offZoom,
      removeAllListeners,
      windowListener,
      trigger;

  /**
   * List of events
   * [Item] --> Event name : listener-list name
   */
  events = {
    'click': 'click',
    'dblclick': 'double-click',
    'handle': 'handle',
    'move': 'move',
    'release': 'release',
    'dragstart': 'drag-start',
    'drag': 'drag',
    'dragend': 'drag-end',
    'dragenter': 'drag-enter',
    'dragover': 'drag-over',
    'dragleave': 'drag-leave',
    'drop': 'drop',
    'scroll': 'scroll',
    'rotatestart': 'rotate-start',
    'rotate': 'rotate',
    'rotateend': 'rotate-end',
    'zoom': 'zoom'
  };

  /**
   * List of callbacks / listeners to execute each time an event occur
   */
  listeners = {
    'click': [],
    'double-click': [],
    'handle': [],
    'move': [],
    'release': [],
    'drag-start': [],
    'drag': [],
    'drag-end': [],
    'drag-enter': [],
    'drag-over': [],
    'drag-leave': [],
    'drop': [],
    'scroll': [],
    'rotate-start': [],
    'rotate': [],
    'rotate-end': [],
    'zoom': []
  };

  /**
   * Trigger method for JavaScript and C++ events
   *
   * Execute every callbacks registred for the given event
   */
  trigger = function (eventType, event) {
    var listenerType, listenersList, l;

    // Check if the event-type is defined by this API
    if (!(eventType in events)) {
      throw 'Impossible to trigger event : ' + eventType;
    }

    listenerType = events[eventType];
    // Get the callbacks list
    listenersList = listeners[listenerType];
    l = listenersList.length - 1;

    while (l >= 0) {
      // For each callback, execute it with the given scope
      listenersList[l].callback.apply(listenersList[l].scope, [event]);
      l = l-1;
    }
  };

  /**
   * windowListener private reference :
   *
   * bind or unbind events on JavaScript window object
   */
  windowListener = (function (CCNBridge) {
    var on,
      clickHandler,
      doubleClickHandler,
      mouseDownHandler,
      mouseMoveHandler,
      mouseUpHandler,
      touchStartHandler,
      touchMoveHandler,
      touchEndHandler,
      dragStartHandler,
      dragHandler,
      dragEndHandler,
      dragEnterHandler,
      dragOverHandler,
      dragLeaveHandler,
      dropHandler,
      scrollHandler,
      rotateStartHandler,
      rotateHandler,
      rotateEndHandler,
      zoomHandler,
      off;
    clickHandler = function (event) {
      trigger.apply(CCNBridge, ['click', event]);
    };
    doubleClickHandler = function (event) {
      trigger.apply(CCNBridge, ['dblclick', event]);
    };
    mouseDownHandler = function (event) {
      trigger.apply(CCNBridge, ['handle', event]);
    };
    mouseMoveHandler = function (event) {
      trigger.apply(CCNBridge, ['move', event]);
    };
    mouseUpHandler = function (event) {
      trigger.apply(CCNBridge, ['release', event]);
    };
    touchStartHandler = function (event) {
      trigger.apply(CCNBridge, ['handle', event]);
    };
    touchMoveHandler = function (event) {
      trigger.apply(CCNBridge, ['move', event]);
    };
    touchEndHandler = function (event) {
      trigger.apply(CCNBridge, ['release', event]);
    };
    dragStartHandler = function (event) {
      trigger.apply(CCNBridge, ['dragstart', event]);
    };
    dragHandler = function (event) {
      trigger.apply(CCNBridge, ['drag', event]);
    };
    dragEndHandler = function (event) {
      trigger.apply(CCNBridge, ['dragend', event]);
    };
    dragEnterHandler = function (event) {
      trigger.apply(CCNBridge, ['dragenter', event]);
    };
    dragOverHandler = function (event) {
      trigger.apply(CCNBridge, ['dragover', event]);
    };
    dragLeaveHandler = function (event) {
      trigger.apply(CCNBridge, ['dragleave', event]);
    };
    dropHandler = function (event) {
      trigger.apply(CCNBridge, ['drop', event]);
    };
    scrollHandler = function (event) {
      trigger.apply(CCNBridge, ['scroll', event]);
    };
    rotateStartHandler = function (event) {
      trigger.apply(CCNBridge, ['rotatestart', event]);
    };
    rotateHandler = function (event) {
      trigger.apply(CCNBridge, ['rotate', event]);
    };
    rotateEndHandler = function (event) {
      trigger.apply(CCNBridge, ['rotateend', event]);
    };
    zoomHandler = function (event) {
      trigger.apply(CCNBridge, ['zoom', event]);
    };
    on = function () {
      window.addEventListener('click', clickHandler, false);
      window.addEventListener('dblclick', doubleClickHandler, false);
      window.addEventListener('mousedown', mouseDownHandler, false);
      window.addEventListener('mousemove', mouseMoveHandler, false);
      window.addEventListener('mouseup', mouseUpHandler, false);
      window.addEventListener('touchstart', touchStartHandler, false);
      window.addEventListener('touchmove', touchMoveHandler, false);
      window.addEventListener('touchend', touchEndHandler, false);
      window.addEventListener('dragstart', dragStartHandler, false);
      window.addEventListener('drag', dragHandler, false);
      window.addEventListener('dragend', dragEndHandler, false);
      window.addEventListener('dragenter', dragEnterHandler, false);
      window.addEventListener('dragover', dragOverHandler, false);
      window.addEventListener('dragleave', dragLeaveHandler, false);
      window.addEventListener('drop', dropHandler, false);
      window.addEventListener('scroll', scrollHandler, false);
      window.addEventListener('rotatestart', rotateStartHandler, false);
      window.addEventListener('rotate', rotateHandler, false);
      window.addEventListener('rotateend', rotateEndHandler, false);
      window.addEventListener('zoom', zoomHandler, false);
    };
    off = function () {
      window.removeEventListener('click', clickHandler, false);
      window.removeEventListener('dblclick', doubleClickHandler, false);
      window.removeEventListener('mousedown', mouseDownHandler, false);
      window.removeEventListener('mousemove', mouseMoveHandler, false);
      window.removeEventListener('mouseup', mouseUpHandler, false);
      window.removeEventListener('touchstart', touchStartHandler, false);
      window.removeEventListener('touchmove', touchMoveHandler, false);
      window.removeEventListener('touchend', touchEndHandler, false);
      window.removeEventListener('dragstart', dragStartHandler, false);
      window.removeEventListener('drag', dragHandler, false);
      window.removeEventListener('dragend', dragEndHandler, false);
      window.removeEventListener('dragenter', dragEnterHandler, false);
      window.removeEventListener('dragover', dragOverHandler, false);
      window.removeEventListener('dragleave', dragLeaveHandler, false);
      window.removeEventListener('drop', dropHandler, false);
      window.removeEventListener('scroll', scrollHandler, false);
      window.removeEventListener('rotatestart', rotateStartHandler, false);
      window.removeEventListener('rotate', rotateHandler, false);
      window.removeEventListener('rotateend', rotateEndHandler, false);
      window.removeEventListener('zoom', zoomHandler, false);
    };
    return {
      'on': on,
      'off': off
    };
  })(this);

  window.addEventListener('load', function (event) {
    // On page load : bind events on window object by default
    windowListener.on();
  });

  /**
   * Get listeners
   *
   * @return array
   */
  getListeners = function () {
    return listeners;
  };

  /**
   * Get events
   *
   * @return array
   */
  getEvents = function () {
    return events;
  };

  // Methods
  /**
   * Register a callback for an event
   */
  on = function (eventType, callback, scope) {
    var listenerType;
    scope = scope || window;

    // Check if the event-type is defined by this API
    if (!(eventType in events)) {
      throw 'Impossible to bind event : ' + eventType;
    }

    listenerType = events[eventType];

    // Push a new listener that will be executed when this event will occur
    listeners[listenerType].push({
      'scope': scope,
      'callback': callback
    });
  };

  /**
   * Alias for "on" method with click event-type
   */
  onClick = function (callback, scope) {
    this.on('click', callback, scope);
  };

  /**
   * Alias for "on" method with double-click event-type
   */
  onDoubleClick = function (callback, scope) {
    this.on('dblclick', callback, scope);
  };

  /**
   * Alias for "on" method with handle event-type
   */
  onHandle = function (callback, scope) {
    this.on('handle', callback, scope);
  };

  /**
   * Alias for "on" method with move event-type
   */
  onMove = function (callback, scope) {
    this.on('move', callback, scope);
  };

  /**
   * Alias for "on" method with release event-type
   */
  onRelease = function (callback, scope) {
    this.on('release', callback, scope);
  };

  /**
   * Alias for "on" method with dragstart event-type
   */
  onDragStart = function (callback, scope) {
    this.on('dragstart', callback, scope);
  };

  /**
   * Alias for "on" method with drag event-type
   */
  onDrag = function (callback, scope) {
    this.on('drag', callback, scope);
  };

  /**
   * Alias for "on" method with dragend event-type
   */
  onDragEnd = function (callback, scope) {
    this.on('dragend', callback, scope);
  };

  /**
   * Alias for "on" method with dragenter event-type
   */
  onDragEnter = function (callback, scope) {
    this.on('dragenter', callback, scope);
  };

  /**
   * Alias for "on" method with dragover event-type
   */
  onDragOver = function (callback, scope) {
    this.on('dragover', callback, scope);
  };

  /**
   * Alias for "on" method with dragleave event-type
   */
  onDragLeave = function (callback, scope) {
    this.on('dragleave', callback, scope);
  };

  /**
   * Alias for "on" method with drop event-type
   */
  onDrop = function (callback, scope) {
    this.on('drop', callback, scope);
  };

  /**
   * Alias for "on" method with scroll event-type
   */
  onScroll = function (callback, scope) {
    this.on('scroll', callback, scope);
  };

  /**
   * Alias for "on" method with rotatestart event-type
   */
  onRotateStart = function (callback, scope) {
    this.on('rotatestart', callback, scope);
  };

  /**
   * Alias for "on" method with rotate event-type
   */
  onRotate = function (callback, scope) {
    this.on('rotate', callback, scope);
  };

  /**
   * Alias for "on" method with rotateend event-type
   */
  onRotateEnd = function (callback, scope) {
    this.on('rotateend', callback, scope);
  };

  /**
   * Alias for "on" method with zoom event-type
   */
  onZoom = function (callback, scope) {
    this.on('zoom', callback, scope);
  };

  /**
   * Unregister one or several previously registred callbacks
   *
   * warning: This should not work for anonymous callbacks
   *
   * @param [optionnal] eventType : the event type to unregister
   * @param [optionnal] callback : the callback to unregister
   * @param [optionnal] scope : the callback's scope (default: window)
   *
   * Note : if no callback is provided, this method will unregister every callbacks for the given eventType
   * Note : if no eventType is provided, this method will unregister every callbacks for every events
   */
  off = function (eventType, callback, scope) {
    var listenerType, listenersList, indexOfCallbackInList, index;
    scope = scope || window;

    // Check if the event-type is defined by this API
    if (eventType && eventType in events) {
      listenerType = events[eventType];

      if (callback) {
        // Get the current listeners list for the given event
        listenersList = listeners[listenerType];
        // Get the callback index in the list
        indexOfCallbackInList = function (list, callback, scope) {
          var l = list.length - 1;
          while (l >= 0) {
            var item = list[l];
            // Compare both callback and scope
            if (item.scope === scope && item.callback === callback) {
              return l;
            }
            l = l-1;
          }

          return -1;
        };
        index = indexOfCallbackInList(listenersList, callback, scope);

        // If the callback is found, remove it from the list
        if (index > (-1)) {
          listenersList.splice(index, 1);
        }
      } else {
        // If the callback is not given, remove all callbacks of the event
        listeners[listenerType] = [];
      }
    } else {
      // If the event is not given, remove all callbacks of all events
      listeners = {
        'translation': [],
        'rotation': [],
        'zoom': []
      };
    }
  };

  /**
   * Alias for "off" method with click event-type
   */
  offClick = function (callback, scope) {
    this.off('click', callback, scope);
  };

  /**
   * Alias for "off" method with double-click event-type
   */
  offDoubleClick = function (callback, scope) {
    this.off('double-click', callback, scope);
  };

  /**
   * Alias for "off" method with handle event-type
   */
  offHandle = function (callback, scope) {
    this.off('handle', callback, scope);
  };

  /**
   * Alias for "off" method with move event-type
   */
  offMove = function (callback, scope) {
    this.off('move', callback, scope);
  };

  /**
   * Alias for "off" method with release event-type
   */
  offRelease = function (callback, scope) {
    this.off('release', callback, scope);
  };

  /**
   * Alias for "off" method with drag event-type
   */
  offDrag = function (callback, scope) {
    this.off('drag', callback, scope);
  };

  /**
   * Alias for "off" method with drop event-type
   */
  offDrop = function (callback, scope) {
    this.off('drop', callback, scope);
  };

  /**
   * Alias for "off" method with scroll event-type
   */
  offScroll = function (callback, scope) {
    this.off('scroll', callback, scope);
  };

  /**
   * Alias for "off" method with rotatestart event-type
   */
  offRotateStart = function (callback, scope) {
    this.off('rotatestart', callback, scope);
  };

  /**
   * Alias for "off" method with rotate event-type
   */
  offRotate = function (callback, scope) {
    this.off('rotate', callback, scope);
  };

  /**
   * Alias for "off" method with rotateend event-type
   */
  offRotateEnd = function (callback, scope) {
    this.off('rotateend', callback, scope);
  };

  /**
   * Alias for "off" method with zoom event-type
   */
  offZoom = function (callback, scope) {
    this.off('zoom', callback, scope);
  };

  /**
   * Alias for "off" method with optionnal eventType
   */
  removeAllListeners = function (eventType) {
    this.off(eventType);
  };

  // Public scope : return all accessible methods
  return {
    'getEvents': getEvents,
    'getListeners': getListeners,
    'on': on,
    'onClick': onClick,
    'onHandle': onHandle,
    'onMove': onMove,
    'onRelease': onRelease,
    'onDragStart': onDragStart,
    'onDrag': onDrag,
    'onDragEnd': onDragEnd,
    'onDragEnter': onDragEnter,
    'onDragOver': onDragOver,
    'onDragLeave': onDragLeave,
    'onDrop': onDrop,
    'onScroll': onScroll,
    'onRotateStart': onRotateStart,
    'onRotate': onRotate,
    'onRotateEnd': onRotateEnd,
    'onZoom': onZoom,
    'off': off,
    'offClick': offClick,
    'offHandle': offHandle,
    'offMove': offMove,
    'offRelease': offRelease,
    'offDragStart': offDragStart,
    'offDrag': offDrag,
    'offDragEnd': offDragEnd,
    'offDragEnter': offDragEnter,
    'offDragOver': offDragOver,
    'offDragLeave': offDragLeave,
    'offDrop': offDrop,
    'offScroll': offScroll,
    'offRotateStart': offRotateStart,
    'offRotate': offRotate,
    'offRotateEnd': offRotateEnd,
    'offZoom': offZoom,
    'removeAllListeners': removeAllListeners
  };
})();

module.exports = CCNBridge;
<|endoftext|>


<commit_before>import {Browser, Events, Log, Styler, UICorePlugin} from 'clappr'
import ChromecastPlayback from './chromecast_playback'
import chromecastStyle from './public/style.scss'
import assign from 'lodash.assign'
import castIconSvg from './public/ic_cast_24dp.svg'
import connecting1IconSvg from './public/ic_cast0_24dp.svg'
import connecting2IconSvg from './public/ic_cast1_24dp.svg'
import connecting3IconSvg from './public/ic_cast2_24dp.svg'
import connectedIconSvg from './public/ic_cast_connected_24dp.svg'

const DEVICE_STATE = {
  'IDLE' : 0,
  'ACTIVE' : 1,
  'WARNING' : 2,
  'ERROR' : 3
}

const DEFAULT_CLAPPR_APP_ID = '9DFB77C0'

const MIMETYPES = {
  'mp4': 'video/mp4',
  'ogg': 'video/ogg',
  '3gpp': 'video/3gpp',
  'webm': 'video/webm',
  'mkv': 'video/x-matroska',
  'm3u8': 'application/x-mpegurl',
  'mpd': 'application/dash+xml'
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

export default class ChromecastPlugin extends UICorePlugin {
  static get Movie() { return 'movie' }
  static get TvShow() { return 'tv_show' }
  static get Generic() { return 'none' }

  static get version() { return VERSION }
  get version() { return VERSION }

  get name() { return 'chromecast' }
  get tagName() { return 'button' }
  get attributes() {
    return {
      'class' : 'chromecast-button'
    }
  }
  get events() {
    return {
      'click': 'click'
    }
  }
  get options() { return this.core.options.chromecast || (this.core.options.chromecast = {}) }

  constructor(core) {
    super(core)
    if (Browser.isChrome) {
      this.appId = this.options.appId || DEFAULT_CLAPPR_APP_ID
      this.deviceState = DEVICE_STATE.IDLE
      this.embedScript()
    } else {
      this.disable()
    }
  }

  bindEvents() {
    this.container = this.container || this.core.getCurrentContainer()
    this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_RENDERED, this.render)
    this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged)
    if (this.container) {
      this.listenTo(this.container, Events.CONTAINER_TIMEUPDATE, this.containerTimeUpdate)
      this.listenTo(this.container, Events.CONTAINER_PLAY, this.containerPlay)
      this.listenTo(this.container, Events.CONTAINER_ENDED, this.sessionStopped)
    }
  }

  enable() {
    super.enable()
    this.render()
    this.embedScript()
  }

  embedScript() {
    if (!window.chrome.cast || !window.chrome.cast.isAvailable) {
      let script = document.createElement('script')
      script.setAttribute('type', 'text/javascript')
      script.setAttribute('async', 'async')
      script.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js')
      script.onload = () => this.bootstrapCastApi()
      document.body.appendChild(script)
    } else {
      this.bootstrapCastApi()
    }
  }

  bootstrapCastApi() {
    if (!window.chrome.cast || !window.chrome.cast.isAvailable) {
      window['__onGCastApiAvailable'] = (loaded, errorInfo) => {
        if (loaded) {
          this.appId = this.appId || DEFAULT_CLAPPR_APP_ID
          this.initializeCastApi()
        } else {
          Log.warn('GCastApi error', errorInfo)
          this.disable()
        }
      }
    } else {
      this.appId = this.appId || DEFAULT_CLAPPR_APP_ID
      this.initializeCastApi()
    }
  }

  initializeCastApi() {
    let autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
    let sessionRequest = new chrome.cast.SessionRequest(this.appId)
    let apiConfig = new chrome.cast.ApiConfig(sessionRequest,
      (session) => this.sessionListener(session), (e) => this.receiverListener(e), autoJoinPolicy)
    chrome.cast.initialize(apiConfig, () => Log.debug(this.name, 'init success'), () => Log.warn(this.name, 'init error'))
  }

  sessionListener(session) {
    Log.debug(this.name, 'new session id:' + session.sessionId)
    this.newSession(session)
  }

  sessionUpdateListener() {
    if (this.session) {
      Log.debug(this.name, this.session.status)
      if (this.session.status === chrome.cast.SessionStatus.STOPPED) {
        this.sessionStopped()
        this.session = null
      }
    }
  }

  receiverListener(e) {
    if ( e === chrome.cast.ReceiverAvailability.AVAILABLE ) {
      Log.debug(this.name, 'receiver found')
      this.show()
    } else {
      Log.debug(this.name, 'receiver list empty')
      this.hide()
    }
  }

  launchSuccess(session) {
    this.renderConnected()
    clearInterval(this.connectAnimInterval)
    this.core.mediaControl.resetKeepVisible()
    Log.debug(this.name, 'launch success - session: ' + session.sessionId)
    this.newSession(session)
  }

  launchError(e) {
    Log.debug(this.name, 'error on launch', e)
    this.renderDisconnected()
    clearInterval(this.connectAnimInterval)
    this.core.mediaControl.resetKeepVisible()
    this.container.play()
  }

  loadMediaSuccess(how, mediaSession) {
    Log.debug(this.name, 'new media session', mediaSession, '(', how , ')')

    this.originalPlayback = this.core.getCurrentPlayback()

    let options = assign({}, this.originalPlayback.options, {
      currentMedia: mediaSession,
      mediaControl: this.core.mediaControl,
      poster: this.core.options.poster,
      settings: this.originalPlayback.settings
    })
    this.src = this.originalPlayback.src
    this.playbackProxy = new ChromecastPlayback(options)
    this.playbackProxy.render()

    this.mediaSession = mediaSession

    this.originalPlayback.$el.remove()

    let container = this.core.getCurrentContainer()
    container.$el.append(this.playbackProxy.$el)
    container.stopListening()
    container.playback = this.playbackProxy
    container.bindEvents()
    container.settingsUpdate()
  }

  loadMediaError(e) {
    Log.warn(this.name, 'media error', e)
  }

  newSession(session) {
    this.session = session
    this.deviceState = DEVICE_STATE.ACTIVE
    this.renderConnected()

    session.addUpdateListener(() => this.sessionUpdateListener())

    this.containerPlay()
  }

  sessionStopped() {
    this.renderDisconnected()

    let time = this.currentTime

    let playerState = undefined
    if (this.mediaSession) {
      playerState = this.mediaSession.playerState
      this.mediaSession = null
    }

    this.core.load(this.src || this.core.options.sources)

    let container = this.core.getCurrentContainer()

    if (this.playbackProxy) {
      if (this.playbackProxy.isPlaying() || playerState === 'PAUSED') {
        container.once(Events.CONTAINER_READY, () => {
          container.play()
          container.playback.seek(100 * time / container.getDuration())
        })
      }
      this.playbackProxy.stop()
    }
  }

  loadMedia() {
    this.container.pause()
    let src = this.container.options.src
    Log.debug(this.name, 'loading... ' + src)
    let mediaInfo = this.createMediaInfo(src)
    let request = new chrome.cast.media.LoadRequest(mediaInfo)
    request.autoplay = true
    request.currentTime = this.currentTime || 0
    this.session.loadMedia(request, (mediaSession) => this.loadMediaSuccess('loadMedia', mediaSession), (e) => this.loadMediaError(e))
  }

  createMediaInfo(src) {
    let mimeType = ChromecastPlugin.mimeTypeFor(src)
    let mediaInfo = new chrome.cast.media.MediaInfo(src)
    mediaInfo.contentType = this.options.contentType || mimeType
    let metadata = this.createMediaMetadata()
    mediaInfo.metadata = metadata
    return mediaInfo
  }

  createMediaMetadata() {
    this.options.media || (this.options.media = {})
    let type = this.options.media.type

    let metadata = this.createCastMediaMetadata(type)
    metadata.title = this.options.media.title
    metadata.subtitle = this.options.media.subtitle
    metadata.releaseDate = this.options.media.releaseDate

    if (type === ChromecastPlugin.TvShow) {
      metadata.episode = this.options.media.episode
      metadata.originalAirdate = this.options.media.originalAirdate
      metadata.season = this.options.media.season
      metadata.seriesTitle = this.options.media.seriesTitle
    } else if (type === ChromecastPlugin.Movie) {
      metadata.studio = this.options.media.studio
    }

    if (this.options.media.images) {
      metadata.images = this.options.media.images.map((url) => new chrome.cast.Image(url))
    }
    if (!metadata.images && this.core.options.poster) {
      metadata.images = [new chrome.cast.Image(this.core.options.poster)]
    }
    return metadata
  }

  createCastMediaMetadata(type) {
    switch (type) {
    case ChromecastPlugin.Movie: return new chrome.cast.media.MovieMediaMetadata()
    case ChromecastPlugin.TvShow: return new chrome.cast.media.TvShowMediaMetadata()
    default: return new chrome.cast.media.GenericMediaMetadata()
    }
  }

  show() {
    this.$el.show()
  }

  hide() {
    this.$el.hide()
  }

  click() {
    this.container.pause()
    chrome.cast.requestSession((session) => this.launchSuccess(session), (e) => this.launchError(e))
    if (!this.session) {
      let position = 0
      let connectingIcons = [connecting1IconSvg, connecting2IconSvg, connecting3IconSvg]
      clearInterval(this.connectAnimInterval)
      this.connectAnimInterval = setInterval(() => {
        this.$el.html(connectingIcons[position])
        position = (position + 1) % 3
      }, 600)
      this.core.mediaControl.setKeepVisible()
    }
  }

  containerChanged() {
    this.container = this.core.getCurrentContainer()
    this.stopListening()
    this.bindEvents()
    this.currentTime = 0
  }

  containerTimeUpdate(timeProgress) {
    this.currentTime = timeProgress.current
  }

  containerPlay() {
    if (this.session && (!this.mediaSession || this.mediaSession.playerState === 'IDLE' || this.mediaSession.playerState === 'PAUSED')) {
      Log.debug(this.name, 'load media')
      this.currentTime = this.currentTime || 0
      this.loadMedia()
    }
  }

  renderConnected() {
    this.$el.html(connectedIconSvg)
  }

  renderDisconnected() {
    this.$el.html(castIconSvg)
  }

  render() {
    this.session ? this.renderConnected() : this.renderDisconnected()
    this.core.mediaControl.$el.find('.media-control-right-panel[data-media-control]').append(this.$el)
    this.$style && this.$style.remove()
    this.$style = Styler.getStyleFor(chromecastStyle, {baseUrl: this.core.options.baseUrl})
    this.core.$el.append(this.$style)
    return this
  }

  static mimeTypeFor(srcUrl) {
    let extension = (srcUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
    if (MIMETYPES[extension]) {
      return MIMETYPES[extension]
    } else if (srcUrl.indexOf('.ism') > -1) {
      return 'application/vnd.ms-sstr+xml'
    }
  }
}
<commit_msg>Fix Cast API initialization for iOS devices.<commit_after>import {Browser, Events, Log, Styler, UICorePlugin} from 'clappr'
import ChromecastPlayback from './chromecast_playback'
import chromecastStyle from './public/style.scss'
import assign from 'lodash.assign'
import castIconSvg from './public/ic_cast_24dp.svg'
import connecting1IconSvg from './public/ic_cast0_24dp.svg'
import connecting2IconSvg from './public/ic_cast1_24dp.svg'
import connecting3IconSvg from './public/ic_cast2_24dp.svg'
import connectedIconSvg from './public/ic_cast_connected_24dp.svg'

const DEVICE_STATE = {
  'IDLE' : 0,
  'ACTIVE' : 1,
  'WARNING' : 2,
  'ERROR' : 3
}

const DEFAULT_CLAPPR_APP_ID = '9DFB77C0'

const MIMETYPES = {
  'mp4': 'video/mp4',
  'ogg': 'video/ogg',
  '3gpp': 'video/3gpp',
  'webm': 'video/webm',
  'mkv': 'video/x-matroska',
  'm3u8': 'application/x-mpegurl',
  'mpd': 'application/dash+xml'
}
MIMETYPES['ogv'] = MIMETYPES['ogg']
MIMETYPES['3gp'] = MIMETYPES['3gpp']

export default class ChromecastPlugin extends UICorePlugin {
  static get Movie() { return 'movie' }
  static get TvShow() { return 'tv_show' }
  static get Generic() { return 'none' }

  static get version() { return VERSION }
  get version() { return VERSION }

  get name() { return 'chromecast' }
  get tagName() { return 'button' }
  get attributes() {
    return {
      'class' : 'chromecast-button'
    }
  }
  get events() {
    return {
      'click': 'click'
    }
  }
  get options() { return this.core.options.chromecast || (this.core.options.chromecast = {}) }

  constructor(core) {
    super(core)

    this.bootTryDelay = this.options.bootTryDelay || 500      // Default is 500 milliseconds between each attempt
    this.bootMaxTryCount = this.options.bootMaxTryCount || 6  // Default is 6 attempts (3 seconds)
    this.bootTryCount = 0

    if (Browser.isChrome) {
      this.appId = this.options.appId || DEFAULT_CLAPPR_APP_ID
      this.deviceState = DEVICE_STATE.IDLE
      this.embedScript()
    } else {
      this.disable()
    }
  }

  bindEvents() {
    this.container = this.container || this.core.getCurrentContainer()
    this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_RENDERED, this.render)
    this.listenTo(this.core.mediaControl, Events.MEDIACONTROL_CONTAINERCHANGED, this.containerChanged)
    if (this.container) {
      this.listenTo(this.container, Events.CONTAINER_TIMEUPDATE, this.containerTimeUpdate)
      this.listenTo(this.container, Events.CONTAINER_PLAY, this.containerPlay)
      this.listenTo(this.container, Events.CONTAINER_ENDED, this.sessionStopped)
    }
  }

  enable() {
    super.enable()
    this.render()
    this.embedScript()
  }

  embedScript() {
    if (!window.chrome || !window.chrome.cast || !window.chrome.cast.isAvailable) {
      let script = document.createElement('script')
      script.setAttribute('type', 'text/javascript')
      script.setAttribute('async', 'async')
      script.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js')
      script.onload = () => this.bootstrapCastApi()
      document.body.appendChild(script)
    } else {
      this.bootstrapCastApi()
    }
  }

  bootstrapCastApi() {
    this.bootTryCount++

    if (this.bootTryCount > this.bootMaxTryCount) {
      this.bootTryCount = 0
      Log.warn('GCastApi bootstrap timeout')
      this.disable()
      return
    }

    // The "chrome" property may not be available immediately on some iOS devices
    if (window.chrome) {
      this.bootTryCount = 0

      if (window.chrome.cast && window.chrome.cast.isAvailable) {
        this.appId = this.appId || DEFAULT_CLAPPR_APP_ID
        this.initializeCastApi()
      } else {
        window['__onGCastApiAvailable'] = (loaded, errorInfo) => {
          if (loaded) {
            this.appId = this.appId || DEFAULT_CLAPPR_APP_ID
            this.initializeCastApi()
          } else {
            Log.warn('GCastApi error', errorInfo)
            this.disable()
          }
        }
      }
    } else {
      setTimeout(() => { this.bootstrapCastApi() }, this.bootTryDelay)
    }
  }

  initializeCastApi() {
    let autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED
    let sessionRequest = new chrome.cast.SessionRequest(this.appId)
    let apiConfig = new chrome.cast.ApiConfig(sessionRequest,
      (session) => this.sessionListener(session), (e) => this.receiverListener(e), autoJoinPolicy)
    chrome.cast.initialize(apiConfig, () => Log.debug(this.name, 'init success'), () => Log.warn(this.name, 'init error'))
  }

  sessionListener(session) {
    Log.debug(this.name, 'new session id:' + session.sessionId)
    this.newSession(session)
  }

  sessionUpdateListener() {
    if (this.session) {
      Log.debug(this.name, this.session.status)
      if (this.session.status === chrome.cast.SessionStatus.STOPPED) {
        this.sessionStopped()
        this.session = null
      }
    }
  }

  receiverListener(e) {
    if ( e === chrome.cast.ReceiverAvailability.AVAILABLE ) {
      Log.debug(this.name, 'receiver found')
      this.show()
    } else {
      Log.debug(this.name, 'receiver list empty')
      this.hide()
    }
  }

  launchSuccess(session) {
    this.renderConnected()
    clearInterval(this.connectAnimInterval)
    this.core.mediaControl.resetKeepVisible()
    Log.debug(this.name, 'launch success - session: ' + session.sessionId)
    this.newSession(session)
  }

  launchError(e) {
    Log.debug(this.name, 'error on launch', e)
    this.renderDisconnected()
    clearInterval(this.connectAnimInterval)
    this.core.mediaControl.resetKeepVisible()
    this.container.play()
  }

  loadMediaSuccess(how, mediaSession) {
    Log.debug(this.name, 'new media session', mediaSession, '(', how , ')')

    this.originalPlayback = this.core.getCurrentPlayback()

    let options = assign({}, this.originalPlayback.options, {
      currentMedia: mediaSession,
      mediaControl: this.core.mediaControl,
      poster: this.core.options.poster,
      settings: this.originalPlayback.settings
    })
    this.src = this.originalPlayback.src
    this.playbackProxy = new ChromecastPlayback(options)
    this.playbackProxy.render()

    this.mediaSession = mediaSession

    this.originalPlayback.$el.remove()

    let container = this.core.getCurrentContainer()
    container.$el.append(this.playbackProxy.$el)
    container.stopListening()
    container.playback = this.playbackProxy
    container.bindEvents()
    container.settingsUpdate()
  }

  loadMediaError(e) {
    Log.warn(this.name, 'media error', e)
  }

  newSession(session) {
    this.session = session
    this.deviceState = DEVICE_STATE.ACTIVE
    this.renderConnected()

    session.addUpdateListener(() => this.sessionUpdateListener())

    this.containerPlay()
  }

  sessionStopped() {
    this.renderDisconnected()

    let time = this.currentTime

    let playerState = undefined
    if (this.mediaSession) {
      playerState = this.mediaSession.playerState
      this.mediaSession = null
    }

    this.core.load(this.src || this.core.options.sources)

    let container = this.core.getCurrentContainer()

    if (this.playbackProxy) {
      if (this.playbackProxy.isPlaying() || playerState === 'PAUSED') {
        container.once(Events.CONTAINER_READY, () => {
          container.play()
          container.playback.seek(100 * time / container.getDuration())
        })
      }
      this.playbackProxy.stop()
    }
  }

  loadMedia() {
    this.container.pause()
    let src = this.container.options.src
    Log.debug(this.name, 'loading... ' + src)
    let mediaInfo = this.createMediaInfo(src)
    let request = new chrome.cast.media.LoadRequest(mediaInfo)
    request.autoplay = true
    request.currentTime = this.currentTime || 0
    this.session.loadMedia(request, (mediaSession) => this.loadMediaSuccess('loadMedia', mediaSession), (e) => this.loadMediaError(e))
  }

  createMediaInfo(src) {
    let mimeType = ChromecastPlugin.mimeTypeFor(src)
    let mediaInfo = new chrome.cast.media.MediaInfo(src)
    mediaInfo.contentType = this.options.contentType || mimeType
    let metadata = this.createMediaMetadata()
    mediaInfo.metadata = metadata
    return mediaInfo
  }

  createMediaMetadata() {
    this.options.media || (this.options.media = {})
    let type = this.options.media.type

    let metadata = this.createCastMediaMetadata(type)
    metadata.title = this.options.media.title
    metadata.subtitle = this.options.media.subtitle
    metadata.releaseDate = this.options.media.releaseDate

    if (type === ChromecastPlugin.TvShow) {
      metadata.episode = this.options.media.episode
      metadata.originalAirdate = this.options.media.originalAirdate
      metadata.season = this.options.media.season
      metadata.seriesTitle = this.options.media.seriesTitle
    } else if (type === ChromecastPlugin.Movie) {
      metadata.studio = this.options.media.studio
    }

    if (this.options.media.images) {
      metadata.images = this.options.media.images.map((url) => new chrome.cast.Image(url))
    }
    if (!metadata.images && this.core.options.poster) {
      metadata.images = [new chrome.cast.Image(this.core.options.poster)]
    }
    return metadata
  }

  createCastMediaMetadata(type) {
    switch (type) {
    case ChromecastPlugin.Movie: return new chrome.cast.media.MovieMediaMetadata()
    case ChromecastPlugin.TvShow: return new chrome.cast.media.TvShowMediaMetadata()
    default: return new chrome.cast.media.GenericMediaMetadata()
    }
  }

  show() {
    this.$el.show()
  }

  hide() {
    this.$el.hide()
  }

  click() {
    this.container.pause()
    chrome.cast.requestSession((session) => this.launchSuccess(session), (e) => this.launchError(e))
    if (!this.session) {
      let position = 0
      let connectingIcons = [connecting1IconSvg, connecting2IconSvg, connecting3IconSvg]
      clearInterval(this.connectAnimInterval)
      this.connectAnimInterval = setInterval(() => {
        this.$el.html(connectingIcons[position])
        position = (position + 1) % 3
      }, 600)
      this.core.mediaControl.setKeepVisible()
    }
  }

  containerChanged() {
    this.container = this.core.getCurrentContainer()
    this.stopListening()
    this.bindEvents()
    this.currentTime = 0
  }

  containerTimeUpdate(timeProgress) {
    this.currentTime = timeProgress.current
  }

  containerPlay() {
    if (this.session && (!this.mediaSession || this.mediaSession.playerState === 'IDLE' || this.mediaSession.playerState === 'PAUSED')) {
      Log.debug(this.name, 'load media')
      this.currentTime = this.currentTime || 0
      this.loadMedia()
    }
  }

  renderConnected() {
    this.$el.html(connectedIconSvg)
  }

  renderDisconnected() {
    this.$el.html(castIconSvg)
  }

  render() {
    this.session ? this.renderConnected() : this.renderDisconnected()
    this.core.mediaControl.$el.find('.media-control-right-panel[data-media-control]').append(this.$el)
    this.$style && this.$style.remove()
    this.$style = Styler.getStyleFor(chromecastStyle, {baseUrl: this.core.options.baseUrl})
    this.core.$el.append(this.$style)
    return this
  }

  static mimeTypeFor(srcUrl) {
    let extension = (srcUrl.split('?')[0].match(/.*\.(.*)$/) || [])[1]
    if (MIMETYPES[extension]) {
      return MIMETYPES[extension]
    } else if (srcUrl.indexOf('.ism') > -1) {
      return 'application/vnd.ms-sstr+xml'
    }
  }
}
<|endoftext|>


<commit_before>// http://userscripts.org/scripts/show/26900

// **** ADAPTED FROM HTML DEMO AT.... *******
// DEMO = http://bz.var.ru/comp/web/resizable.html
// JS = http://bz.var.ru/comp/web/resizable-tables.js
//  ******* ORIGINAL SCRIPT HEADER *******
// Resizable Table Columns.
//  version: 1.0
//
// (c) 2006, bz
//
// 25.12.2006:  first working prototype
// 26.12.2006:  now works in IE as well but not in Opera (Opera is @#$%!)
// 27.12.2006:  changed initialization, now just make class='resizable' in table and load script
// ==========================================
// Greasemonkey Changelog
// 20080520 adapted by gollum for use in Greasemonkey scripts
// stripped out the cookie code
// removed references to "this" function calls
// added eventListeners/removeEventListeners
// wrapped all in anonymous function
// added script auto-updater

//(function() {

  function preventEvent(e) {
  	var ev = e || window.event;
  	if (ev.preventDefault) ev.preventDefault();
  	else ev.returnValue = false;
  	if (ev.stopPropagation)
  		ev.stopPropagation();
  	return false;
  }

  function getWidth(x) {
  	if (x.currentStyle)
  		// in IE
  		var y = x.clientWidth - parseInt(x.currentStyle["paddingLeft"]) - parseInt(x.currentStyle["paddingRight"]);
  		// for IE5: var y = x.offsetWidth;
  	else if (window.getComputedStyle)
  		// in Gecko
  		var y = document.defaultView.getComputedStyle(x,null).getPropertyValue("width");
  	return y || 0;
  }

  // main class prototype
  function ColumnResize(table) {
  	if (table.tagName != 'TABLE') return;

  	// this.id = table.id;

  	// ============================================================
  	// private data
  	// var self = this;

  	var dragColumns  = table.rows[0].cells; // first row columns, used for changing of width
  	if (!dragColumns) return; // return if no table exists or no one row exists

  	var dragColumnNo; // current dragging column
  	var dragX;        // last event X mouse coordinate

  	// var saveOnmouseup;   // save document onmouseup event handler
  	// var saveOnmousemove; // save document onmousemove event handler
  	var saveBodyCursor;  // save body cursor property

  	// ============================================================
  	// methods

  	// ============================================================
  	// do changes columns widths
  	// returns true if success and false otherwise
  	var changeColumnWidth = function(no, w) {
  		if (!dragColumns) return false;

  		if (no < 0) return false;
  		if (dragColumns.length < no) return false;

  		if (parseInt(dragColumns[no].style.width) <= -w) return false;
  		if (dragColumns[no+1] && parseInt(dragColumns[no+1].style.width) <= w) return false;

  		dragColumns[no].style.width = parseInt(dragColumns[no].style.width) + w +'px';
  		if (dragColumns[no+1])
  			dragColumns[no+1].style.width = parseInt(dragColumns[no+1].style.width) - w + 'px';

  		return true;
  	}

  	// ============================================================
  	// do drag column width
  	var columnDrag = function(e) {
  		var e = e || window.event;
  		var X = e.clientX || e.pageX;
  		if (!changeColumnWidth(dragColumnNo, X-dragX)) {
  			// stop drag!
  			stopColumnDrag(e);
  		}

  		dragX = X;
  		// prevent other event handling
  		preventEvent(e);
  		return false;
  	}

  	// ============================================================
  	// stops column dragging
  	var stopColumnDrag = function(e) {
  		var e = e || window.event;
  		if (!dragColumns) return;

  		// restore handlers & cursor
  		myRemoveEventListener(document, "mouseup", stopColumnDrag);
  		myRemoveEventListener(document, "mousemove", columnDrag);
  		document.body.style.cursor = saveBodyCursor;

  		preventEvent(e);
  	}

  	// ============================================================
  	// init data and start dragging
  	var startColumnDrag = function(e) {
  		var e = e || window.event;

  		// remember dragging object
  		dragColumnNo = (e.target || e.srcElement).parentNode.parentNode.cellIndex;
  		dragX = e.clientX || e.pageX;

  		// set up current columns widths in their particular attributes
  		// do it in two steps to avoid jumps on page!
  		var colWidth = new Array();
  		for (var i=0; i<dragColumns.length; i++)
  			colWidth[i] = parseInt( getWidth(dragColumns[i]) );
  		for (var i=0; i<dragColumns.length; i++) {
  			dragColumns[i].width = ""; // for sure
  			dragColumns[i].style.width = colWidth[i] + "px";
  		}

  		// saveOnmouseup       = document.onmouseup;
  		myAddEventListener(document, "mouseup", stopColumnDrag);

  		saveBodyCursor             = document.body.style.cursor;
  		document.body.style.cursor = 'w-resize';

  		// fire!
  		// saveOnmousemove      = document.onmousemove;
  		myAddEventListener(document, "mousemove", columnDrag);

  		preventEvent(e);
  	}

  	// prepare table header to be draggable
  	// it runs during class creation
  	for (var i=0; i<dragColumns.length; i++) {
  		dragColumns[i].innerHTML = "
"+
  			"
"+
  			"
"+
  			dragColumns[i].innerHTML+
  			"
";
  			// BUGBUG: calculate real border width instead of 5px!!!
  			tmp = dragColumns[i].firstChild.firstChild;
  			myAddEventListener(tmp, "mousedown", startColumnDrag);
  		}
  }

  function myAddEventListener(target, event, handler) {
		if (target.addEventListener) {
			target.addEventListener(event, handler, false);
		} else if (tmp.attachEvent) {
			// pour MSIE
			target.attachEvent("on" + event, handler);
		}
  }

  function myRemoveEventListener(target, event, handler) {
		if (target.removeEventListener) {
			target.removeEventListener(event, handler, false);
		} else if (tmp.attachEvent) {
			// pour MSIE
			target.detachEvent("on" + event, handler);
		}
}

  // select all tables and make resizable those that have 'sortable' class
  var resizableTables = new Array();
  function ResizableColumns() {
  	var tables = document.getElementsByTagName('table');
	for (var i=0; i<tables.length; i++) {
  		if (tables[i].className.search(/\bsortable\b/) != -1) {
  		 	// generate id
  			if (!tables[i].id) tables[i].id = 'table'+(i+1);
  			// make table resizable
  			resizableTables[resizableTables.length] = new ColumnResize(tables[i]);
  		}
  	}
  //	alert(resizableTables.length + ' tables was added.');
  }

//})();

//============================================================
//
// Usage. In your html code just include the follow:
//
//============================================================
//

// ...
//

//============================================================<commit_msg>resizable_tables.js: don't use innerHTML<commit_after>// http://userscripts.org/scripts/show/26900

// **** ADAPTED FROM HTML DEMO AT.... *******
// DEMO = http://bz.var.ru/comp/web/resizable.html
// JS = http://bz.var.ru/comp/web/resizable-tables.js
//  ******* ORIGINAL SCRIPT HEADER *******
// Resizable Table Columns.
//  version: 1.0
//
// (c) 2006, bz
//
// 25.12.2006:  first working prototype
// 26.12.2006:  now works in IE as well but not in Opera (Opera is @#$%!)
// 27.12.2006:  changed initialization, now just make class='resizable' in table and load script
// ==========================================
// Greasemonkey Changelog
// 20080520 adapted by gollum for use in Greasemonkey scripts
// stripped out the cookie code
// removed references to "this" function calls
// added eventListeners/removeEventListeners
// wrapped all in anonymous function
// added script auto-updater

//(function() {

  function preventEvent(e) {
  	var ev = e || window.event;
  	if (ev.preventDefault) ev.preventDefault();
  	else ev.returnValue = false;
  	if (ev.stopPropagation)
  		ev.stopPropagation();
  	return false;
  }

  function getWidth(x) {
  	if (x.currentStyle)
  		// in IE
  		var y = x.clientWidth - parseInt(x.currentStyle["paddingLeft"]) - parseInt(x.currentStyle["paddingRight"]);
  		// for IE5: var y = x.offsetWidth;
  	else if (window.getComputedStyle)
  		// in Gecko
  		var y = document.defaultView.getComputedStyle(x,null).getPropertyValue("width");
  	return y || 0;
  }

  // main class prototype
  function ColumnResize(table) {
  	if (table.tagName != 'TABLE') return;

  	// this.id = table.id;

  	// ============================================================
  	// private data
  	// var self = this;

  	var dragColumns  = table.rows[0].cells; // first row columns, used for changing of width
  	if (!dragColumns) return; // return if no table exists or no one row exists

  	var dragColumnNo; // current dragging column
  	var dragX;        // last event X mouse coordinate

  	// var saveOnmouseup;   // save document onmouseup event handler
  	// var saveOnmousemove; // save document onmousemove event handler
  	var saveBodyCursor;  // save body cursor property

  	// ============================================================
  	// methods

  	// ============================================================
  	// do changes columns widths
  	// returns true if success and false otherwise
  	var changeColumnWidth = function(no, w) {
  		if (!dragColumns) return false;

  		if (no < 0) return false;
  		if (dragColumns.length < no) return false;

  		if (parseInt(dragColumns[no].style.width) <= -w) return false;
  		if (dragColumns[no+1] && parseInt(dragColumns[no+1].style.width) <= w) return false;

  		dragColumns[no].style.width = parseInt(dragColumns[no].style.width) + w +'px';
  		if (dragColumns[no+1])
  			dragColumns[no+1].style.width = parseInt(dragColumns[no+1].style.width) - w + 'px';

  		return true;
  	}

  	// ============================================================
  	// do drag column width
  	var columnDrag = function(e) {
  		var e = e || window.event;
  		var X = e.clientX || e.pageX;
  		if (!changeColumnWidth(dragColumnNo, X-dragX)) {
  			// stop drag!
  			stopColumnDrag(e);
  		}

  		dragX = X;
  		// prevent other event handling
  		preventEvent(e);
  		return false;
  	}

  	// ============================================================
  	// stops column dragging
  	var stopColumnDrag = function(e) {
  		var e = e || window.event;
  		if (!dragColumns) return;

  		// restore handlers & cursor
  		myRemoveEventListener(document, "mouseup", stopColumnDrag);
  		myRemoveEventListener(document, "mousemove", columnDrag);
  		document.body.style.cursor = saveBodyCursor;

  		preventEvent(e);
  	}

  	// ============================================================
  	// init data and start dragging
  	var startColumnDrag = function(e) {
  		var e = e || window.event;

  		// remember dragging object
  		dragColumnNo = (e.target || e.srcElement).parentNode.parentNode.cellIndex;
  		dragX = e.clientX || e.pageX;

  		// set up current columns widths in their particular attributes
  		// do it in two steps to avoid jumps on page!
  		var colWidth = new Array();
  		for (var i=0; i<dragColumns.length; i++)
  			colWidth[i] = parseInt( getWidth(dragColumns[i]) );
  		for (var i=0; i<dragColumns.length; i++) {
  			dragColumns[i].width = ""; // for sure
  			dragColumns[i].style.width = colWidth[i] + "px";
  		}

  		// saveOnmouseup       = document.onmouseup;
  		myAddEventListener(document, "mouseup", stopColumnDrag);

  		saveBodyCursor             = document.body.style.cursor;
  		document.body.style.cursor = 'w-resize';

  		// fire!
  		// saveOnmousemove      = document.onmousemove;
  		myAddEventListener(document, "mousemove", columnDrag);

  		preventEvent(e);
  	}

  	// prepare table header to be draggable
  	// it runs during class creation
  	for (var i=0; i<dragColumns.length; i++) {
  		var div = document.createElement("div");
  		div.style.position = "relative";
  		div.style.height = "100%";
  		div.style.width = "100%";
  		var innerDiv = document.createElement("div");
  		innerDiv.style.position = "absolute";
  		innerDiv.style.height = "100%";
  		innerDiv.style.width = "5px";
  		innerDiv.style.marginRight = "-5px";
  		innerDiv.style.left = "100%";
  		innerDiv.style.top = "0px";
  		innerDiv.style.cursor = "w-resize";
  		innerDiv.style.zIndex = "10";
  		div.appendChild(innerDiv);
  		while (dragColumns[i].childNodes.length) { div.appendChild(dragColumns[i].firstChild); }
  		dragColumns[i].appendChild(div);
  			// BUGBUG: calculate real border width instead of 5px!!!
  			tmp = dragColumns[i].firstChild.firstChild;
  			myAddEventListener(tmp, "mousedown", startColumnDrag);
  		}
  }

  function myAddEventListener(target, event, handler) {
		if (target.addEventListener) {
			target.addEventListener(event, handler, false);
		} else if (tmp.attachEvent) {
			// pour MSIE
			target.attachEvent("on" + event, handler);
		}
  }

  function myRemoveEventListener(target, event, handler) {
		if (target.removeEventListener) {
			target.removeEventListener(event, handler, false);
		} else if (tmp.attachEvent) {
			// pour MSIE
			target.detachEvent("on" + event, handler);
		}
}

  // select all tables and make resizable those that have 'sortable' class
  var resizableTables = new Array();
  function ResizableColumns() {
  	var tables = document.getElementsByTagName('table');
	for (var i=0; i<tables.length; i++) {
  		if (tables[i].className.search(/\bsortable\b/) != -1) {
  		 	// generate id
  			if (!tables[i].id) tables[i].id = 'table'+(i+1);
  			// make table resizable
  			resizableTables[resizableTables.length] = new ColumnResize(tables[i]);
  		}
  	}
  //	alert(resizableTables.length + ' tables was added.');
  }

//})();

//============================================================
//
// Usage. In your html code just include the follow:
//
//============================================================
//

// ...
//

//============================================================<|endoftext|>


<commit_before>var NeedsChange = {
    LOSING_FAST: 'down_fast',
    LOSING: 'down_normal',
    GAINING: 'up_normal',
    GAINING_FAST: 'up_fast'
};

var NeedType = {
    HUNGER: 'hunger',
    SLEEP: 'sleep',
    COLD: 'cold'
};

var Need = Class.extend({
    id: null,
    name: null,
    currentValue: 0,
    maxValue: 100,
    currentSpeed: NeedsChange.LOSING,

    init: function (id, name, startValue) {
        this.id = id;
        this.name = name;
        this.currentValue = startValue;
        this.currentSpeed = NeedsChange.LOSING;
    },

    getPercentage: function () {
        return (this.currentValue / this.maxValue) * 100;
    }
});

var Needs = {
    needs: [],

    clear: function () {
        this.needs = [];

        this.needs.push(new Need(NeedType.HUNGER, 'Hunger', 40));
        this.needs.push(new Need(NeedType.COLD, 'Cold', 30));
        this.needs.push(new Need(NeedType.SLEEP, 'Sleep', 10));

        this.setupUi();
    },

    uiSyncTimer: 0,

    setupUi: function () {
        var $uiNeeds = $('#needs');
        $uiNeeds.html('');

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            var $div = $('<div />')
                .addClass('need')
                .addClass(need.id)
                .appendTo($uiNeeds);

            $div.append(need.name);

            var $statusImg = $('<img />')
                .addClass('progress_speed')
                .addClass(need.id)
                .appendTo($div);

            var $progressBar = $('<div />')
                .addClass('progress')
                .addClass(need.id)
                .appendTo($div);

            var $progressInner = $('<div />')
                .addClass('inner')
                .appendTo($progressBar);
        }

        this.syncUi();
    },

    syncUi: function () {
        var $uiNeeds = $('#needs');

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            var $div = $('.need.' + need.id);
            var $img = $div.find('.progress_speed');
            var $progressInner = $div.find('.progress .inner');

            $img.attr('src', 'assets/images/progress_' + need.currentSpeed + '.png');
            $progressInner.css('width', need.getPercentage() + '%');
        }
    },

    die: function () {
        alert('U DED');
        // TODO death
    },

    update: function () {
        if (this.uiSyncTimer > 0) {
            this.uiSyncTimer--;
        }

        if (this.uiSyncTimer <= 0) {
            this.syncUi();
            this.uiSyncTimer = 60;
        }

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            switch (need.currentSpeed) {
                case NeedsChange.GAINING:
                    need.currentValue -= 0.005;
                    break;
                case NeedsChange.GAINING_FAST:
                    need.currentValue -= 0.01;
                    break;
                case NeedsChange.LOSING_FAST:
                    need.currentValue += 0.01;
                    break;
                case NeedsChange.LOSING:
                    need.currentValue += 0.005;
                    break;
            }

            if (need.currentValue < 0) {
                need.currentValue = 0;
            }

            if (need.currentValue > need.maxValue) {
                this.die();
                return;
            }
        }
    }
};<commit_msg>[Needs] Coldness decreases if fireplace is lit, increases at double speed if it's outside between 6 and 6<commit_after>var NeedsChange = {
    LOSING_FAST: 'down_fast',
    LOSING: 'down_normal',
    GAINING: 'up_normal',
    GAINING_FAST: 'up_fast'
};

var NeedType = {
    HUNGER: 'hunger',
    SLEEP: 'sleep',
    COLD: 'cold'
};

var Need = Class.extend({
    id: null,
    name: null,
    currentValue: 0,
    maxValue: 100,
    currentSpeed: NeedsChange.LOSING,

    init: function (id, name, startValue) {
        this.id = id;
        this.name = name;
        this.currentValue = startValue;
        this.currentSpeed = NeedsChange.LOSING;
    },

    getPercentage: function () {
        return (this.currentValue / this.maxValue) * 100;
    },

    determineSpeed: function () {
        switch (this.id) {
            case NeedType.COLD:
                if (Game.map.fireplaceLit) {
                    this.currentSpeed = NeedsChange.GAINING;
                } else if (Game.map.isInterior()) {
                    this.currentSpeed = NeedsChange.LOSING;
                } else if (Time.getHour() <= 6 || Time.getHour() >= 18 && Game.map.isExterior()) {
                    this.currentSpeed = NeedsChange.LOSING_FAST;
                } else {
                    this.currentSpeed = NeedsChange.LOSING;
                }
                console.log(this.currentSpeed);

                break;
        }
    }
});

var Needs = {
    needs: [],

    clear: function () {
        this.needs = [];

        this.needs.push(new Need(NeedType.HUNGER, 'Hunger', 40));
        this.needs.push(new Need(NeedType.COLD, 'Cold', 30));
        this.needs.push(new Need(NeedType.SLEEP, 'Sleep', 10));

        this.setupUi();
    },

    uiSyncTimer: 0,

    setupUi: function () {
        var $uiNeeds = $('#needs');
        $uiNeeds.html('');

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            var $div = $('<div />')
                .addClass('need')
                .addClass(need.id)
                .appendTo($uiNeeds);

            $div.append(need.name);

            var $statusImg = $('<img />')
                .addClass('progress_speed')
                .addClass(need.id)
                .appendTo($div);

            var $progressBar = $('<div />')
                .addClass('progress')
                .addClass(need.id)
                .appendTo($div);

            var $progressInner = $('<div />')
                .addClass('inner')
                .appendTo($progressBar);
        }

        this.syncUi();
    },

    syncUi: function () {
        var $uiNeeds = $('#needs');

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            var $div = $('.need.' + need.id);
            var $img = $div.find('.progress_speed');
            var $progressInner = $div.find('.progress .inner');

            $img.attr('src', 'assets/images/progress_' + need.currentSpeed + '.png');
            $progressInner.css('width', need.getPercentage() + '%');
        }
    },

    die: function () {
        alert('U DED');
        // TODO death
    },

    update: function () {
        if (this.uiSyncTimer > 0) {
            this.uiSyncTimer--;
        }

        if (this.uiSyncTimer <= 0) {
            this.syncUi();
            this.uiSyncTimer = 60;
        }

        for (var i = 0; i < this.needs.length; i++) {
            var need = this.needs[i];

            need.determineSpeed();

            switch (need.currentSpeed) {
                case NeedsChange.GAINING:
                    need.currentValue -= 0.005;
                    break;
                case NeedsChange.GAINING_FAST:
                    need.currentValue -= 0.01;
                    break;
                case NeedsChange.LOSING_FAST:
                    need.currentValue += 0.01;
                    break;
                case NeedsChange.LOSING:
                    need.currentValue += 0.005;
                    break;
            }

            if (need.currentValue < 0) {
                need.currentValue = 0;
            }

            if (need.currentValue > need.maxValue) {
                this.die();
                return;
            }
        }
    }
};<|endoftext|>


<commit_before>function OcelotController() {
	var ws;
	this.init = function() {
		if(!ws || ws.status !== "OPEN") {
			if(document.location.href.toString().indexOf(document.location.protocol+"//"+document.location.hostname + ":" + document.location.port+"%CTXPATH%")===0) {
				ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + "%CTXPATH%/endpoint");
			} else {
				ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + "/endpoint");
			}
			ws.topicHandlers = {};
			ws.resultHandlers = {};
			ws.faultHandlers = {};
			ws.status = "OPEN";
			ws.onmessage =function (evt) {
				var msgToClient = JSON.parse(evt.data);
				if(msgToClient.result) {
					if(this.topicHandlers[msgToClient.id]) {
						this.topicHandlers[msgToClient.id](msgToClient.result);
					} else if(this.resultHandlers[msgToClient.id]) {
						this.resultHandlers[msgToClient.id](msgToClient.result);
					}
				} else if(msgToClient.fault) {
					this.faultHandlers[msgToClient.id](msgToClient.fault);
				}
			};
			ws.onopen = function (evt) {
				this.status = "OPEN";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
			ws.onerror = function (evt) {
				this.status = "ERROR";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
			ws.onclose = function (evt) {
				this.status = "CLOSED";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
		}
	};
	this.init();
	this.subscribe = function (token) {
		if(ws.status === "OPEN") {
			ws.topicHandlers[token.topic] = token.onMessage;
			if(token.topic === "ocelot-status") {
				token.onMessage(ws.status);
			} else if(token.topic === "ocelot-msg") {
			} else {
				var command = "{\"topic\":\"" + token.topic + "\",\"cmd\":\"subscribe\"}";
				ws.send(command);
			}
		} else this.showError();
	};
	this.unsubscribe = function (token) {
		if(ws.status === "OPEN") {
			ws.topicHandlers[token.topic] = null;
			if(token.topic !== "ocelot-status" && token.topic !== "ocelot-msg") {
				var command = "{\"topic\":\"" + token.topic + "\",\"cmd\":\"unsubscribe\"}";
				ws.send(command);
			}
		} else this.showError();
	};
	this.call = function (token) {
		if(ws.status === "OPEN") {
			var uuid = new UUID().random();
			ws.resultHandlers[uuid] = token.onResult;
			ws.faultHandlers[uuid] = token.onFault;
			var msg = "{\"id\":\"" + uuid + "\",\"ds\":\"" + token.dataservice + "\",\"op\":\"" + token.operation + "\", \"args\":"+JSON.stringify(token.args)+"}";
			var command = "{\"topic\":\"" + token.factory + "\",\"cmd\":\"call\",\"msg\":" + msg + "}";
			ws.send(command);
		} else this.showError();
	};
	this.showError= function () {
		alert("WebSocket is not open");
	};
}
function UUID() {
	this.random = function () {
		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
			var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	};
}
var ocelotController;
document.addEventListener("subscribe", function (event) {
	ocelotController.subscribe(event);
});
document.addEventListener("unsubscribe", function (event) {
	ocelotController.unsubscribe(event);
});
document.addEventListener("call", function (event) {
	ocelotController.call(event);
});
window.addEventListener("load", function (event) {
	ocelotController = new OcelotController();
});
function Mdb(topic) {
	var topic = topic;
	this.subscribe = function() {
		var subEvent = document.createEvent("Event");
		subEvent.initEvent("subscribe", true, false);
		subEvent.topic = topic;
		subEvent.onMessage = this.onMessage;
		document.dispatchEvent(subEvent);
	};
	this.unsubscribe = function() {
		var unsubEvent = document.createEvent("Event");
		unsubEvent.initEvent("unsubscribe", true, false);
		unsubEvent.topic = topic;
		document.dispatchEvent(unsubEvent);
	};
	this.onMessage = function(msg) {};
}
var getOcelotEvent = function getOcelotEvent(op, args) {
	var evt = document.createEvent("Event");
	evt.initEvent("call", true, false);
	evt.factory = this.fid;
	evt.dataservice = this.ds;
	evt.operation = op;
	evt.args = args;
	evt.onResult = function (msg) {};
	evt.onFault = function (fault) {};
	setTimeout(function () {document.dispatchEvent(evt);}, 1);
	return evt;
};
<commit_msg>rajout de notification ocelot-status<commit_after>function OcelotController() {
	var ws;
	this.init = function() {
		if(!ws || ws.status !== "OPEN") {
			if(document.location.href.toString().indexOf(document.location.protocol+"//"+document.location.hostname + ":" + document.location.port+"%CTXPATH%")===0) {
				ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + "%CTXPATH%/endpoint");
			} else {
				ws = new WebSocket("ws://" + document.location.hostname + ":" + document.location.port + "/endpoint");
			}
			ws.topicHandlers = {};
			ws.resultHandlers = {};
			ws.faultHandlers = {};
			ws.status = "OPEN";
			ws.onmessage =function (evt) {
				var msgToClient = JSON.parse(evt.data);
				if(msgToClient.result) {
					if(this.topicHandlers[msgToClient.id]) {
						this.topicHandlers[msgToClient.id](msgToClient.result);
					} else if(this.resultHandlers[msgToClient.id]) {
						this.resultHandlers[msgToClient.id](msgToClient.result);
					}
				} else if(msgToClient.fault) {
					this.faultHandlers[msgToClient.id](msgToClient.fault);
				}
			};
			ws.onopen = function (evt) {
				this.status = "OPEN";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
			ws.onerror = function (evt) {
				this.status = "ERROR";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
			ws.onclose = function (evt) {
				this.status = "CLOSED";
				if(this.topicHandlers["ocelot-status"]) this.topicHandlers["ocelot-status"](this.status);
			};
		}
	};
	this.init();
	this.subscribe = function (token) {
		if(ws.status === "OPEN") {
			ws.topicHandlers[token.topic] = token.onMessage;
			if(token.topic === "ocelot-msg") {
			} else {
				var command = "{\"topic\":\"" + token.topic + "\",\"cmd\":\"subscribe\"}";
				ws.send(command);
			}
		} else this.showError();
		if(ws.topicHandlers["ocelot-status"]) ws.topicHandlers["ocelot-status"](ws.status);
	};
	this.unsubscribe = function (token) {
		if(ws.topicHandlers["ocelot-status"]) ws.topicHandlers["ocelot-status"](ws.status);
		if(ws.status === "OPEN") {
			ws.topicHandlers[token.topic] = null;
			if(token.topic !== "ocelot-status" && token.topic !== "ocelot-msg") {
				var command = "{\"topic\":\"" + token.topic + "\",\"cmd\":\"unsubscribe\"}";
				ws.send(command);
			}
		} else this.showError();
	};
	this.call = function (token) {
		if(ws.topicHandlers["ocelot-status"]) ws.topicHandlers["ocelot-status"](ws.status);
		if(ws.status === "OPEN") {
			var uuid = new UUID().random();
			ws.resultHandlers[uuid] = token.onResult;
			ws.faultHandlers[uuid] = token.onFault;
			var msg = "{\"id\":\"" + uuid + "\",\"ds\":\"" + token.dataservice + "\",\"op\":\"" + token.operation + "\", \"args\":"+JSON.stringify(token.args)+"}";
			var command = "{\"topic\":\"" + token.factory + "\",\"cmd\":\"call\",\"msg\":" + msg + "}";
			ws.send(command);
		} else this.showError();
	};
	this.showError= function () {
		alert("WebSocket is not open");
	};
}
function UUID() {
	this.random = function () {
		return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
			var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	};
}
var ocelotController = new OcelotController();
document.addEventListener("subscribe", function (event) {
	ocelotController.subscribe(event);
});
document.addEventListener("unsubscribe", function (event) {
	ocelotController.unsubscribe(event);
});
document.addEventListener("call", function (event) {
	ocelotController.call(event);
});
window.addEventListener("load", function (event) {
//	ocelotController = new OcelotController();
});
function Mdb(topic) {
	var topic = topic;
	this.subscribe = function() {
		var subEvent = document.createEvent("Event");
		subEvent.initEvent("subscribe", true, false);
		subEvent.topic = topic;
		subEvent.onMessage = this.onMessage;
		document.dispatchEvent(subEvent);
	};
	this.unsubscribe = function() {
		var unsubEvent = document.createEvent("Event");
		unsubEvent.initEvent("unsubscribe", true, false);
		unsubEvent.topic = topic;
		document.dispatchEvent(unsubEvent);
	};
	this.onMessage = function(msg) {};
}
var getOcelotEvent = function getOcelotEvent(op, args) {
	var evt = document.createEvent("Event");
	evt.initEvent("call", true, false);
	evt.factory = this.fid;
	evt.dataservice = this.ds;
	evt.operation = op;
	evt.args = args;
	evt.onResult = function (msg) {};
	evt.onFault = function (fault) {};
	setTimeout(function () {document.dispatchEvent(evt);}, 1);
	return evt;
};
<|endoftext|>