<commit_before>/**
 * @file Crumbs component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Crumb from '../_Crumb';
import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';

export default class Crumbs extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.itemRender = ::this.itemRender;

    }

    itemRender(item, index) {

        if (item.renderer) {
            return item.renderer(item, index);
        }

        const {itemRenderer, onItemTouchTap} = this.props;
        if (itemRenderer) {
            return itemRenderer(item, index);
        }

        return <Crumb {...item}
                      onTouchTap={e => {
                          item.onTouchTap && item.onTouchTap(e);
                          onItemTouchTap && onItemTouchTap(e, item, index);
                      }}/>;

    }

    render() {

        const {className, style, data, separator, showLastSeparator} = this.props,

            crumbsClassName = (className ? ' ' + className : '');

        return (

                {
                    data && data.map((item, index) => (

                            {this.itemRender(item, index)}

                            {
                                !showLastSeparator && index === data.length - 1 ?
                                    null
                                    :

                                        {separator}

                            }

                    ))
                }

        );

    }
};

Crumbs.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The theme of the Crumbs.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Crumbs data config.
     */
    data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the list button.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the list button.
         */
        style: PropTypes.object,

        /**
         * The theme of the list button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The url of crumb.
         */
        href: PropTypes.string,

        /**
         * The text value of the list button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The list item's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the list button. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the list item will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * If true,the element's ripple effect will be disabled.
         */
        disableTouchRipple: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        tip: PropTypes.string,

        /**
         * The position of tip.
         */
        tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

        /**
         * If true,the item will have center displayed ripple effect.
         */
        rippleDisplayCenter: PropTypes.bool,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        renderer: PropTypes.func,

        /**
         * Callback function fired when a list item touch-tapped.
         */
        onTouchTap: PropTypes.func

    }), PropTypes.string, PropTypes.number])).isRequired,

    separator: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

    showLastSeparator: PropTypes.bool,

    /**
     * Crumbs data renderer callback.
     */
    itemRenderer: PropTypes.func,

    onItemTouchTap: PropTypes.func

};

Crumbs.defaultProps = {

    className: null,
    style: null,
    theme: Theme.DEFAULT,

    data: null,

    separator: '>',
    showLastSeparator: false

};<commit_msg>update Crumbs<commit_after>/**
 * @file Crumbs component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Crumb from '../_Crumb';
import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';

export default class Crumbs extends Component {

    static Theme = Theme;
    static propTypes = {

        /**
         * The CSS class name of the root element.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the root element.
         */
        style: PropTypes.object,

        /**
         * The theme of the Crumbs.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * Crumbs data config.
         */
        data: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

            /**
             * The CSS class name of the list button.
             */
            className: PropTypes.string,

            /**
             * Override the styles of the list button.
             */
            style: PropTypes.object,

            /**
             * The theme of the list button.
             */
            theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

            /**
             * The url of crumb.
             */
            href: PropTypes.string,

            /**
             * The text value of the list button.Type can be string or number.
             */
            value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The list item's display text. Type can be string, number or bool.
             */
            text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The desc value of the list button. Type can be string or number.
             */
            desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * If true,the list item will be disabled.
             */
            disabled: PropTypes.bool,

            /**
             * If true,the button will be have loading effect.
             */
            isLoading: PropTypes.bool,

            /**
             * If true,the element's ripple effect will be disabled.
             */
            disableTouchRipple: PropTypes.bool,

            /**
             * Use this property to display an icon. It will display on the left.
             */
            iconCls: PropTypes.string,

            /**
             * Use this property to display an icon. It will display on the right.
             */
            rightIconCls: PropTypes.string,

            /**
             * The message of tip.
             */
            tip: PropTypes.string,

            /**
             * The position of tip.
             */
            tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

            /**
             * If true,the item will have center displayed ripple effect.
             */
            rippleDisplayCenter: PropTypes.bool,

            /**
             * You can create a complicated renderer callback instead of value and desc prop.
             */
            renderer: PropTypes.func,

            /**
             * Callback function fired when a list item touch-tapped.
             */
            onTouchTap: PropTypes.func

        }), PropTypes.string, PropTypes.number])).isRequired,

        separator: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

        showLastSeparator: PropTypes.bool,

        /**
         * Crumbs data renderer callback.
         */
        itemRenderer: PropTypes.func,

        onItemTouchTap: PropTypes.func

    };
    static defaultProps = {

        className: null,
        style: null,
        theme: Theme.DEFAULT,

        data: null,

        separator: '>',
        showLastSeparator: false

    };

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.itemRender = ::this.itemRender;

    }

    itemRender(item, index) {

        if (item.renderer) {
            return item.renderer(item, index);
        }

        const {itemRenderer, onItemTouchTap} = this.props;
        if (itemRenderer) {
            return itemRenderer(item, index);
        }

        return <Crumb {...item}
                      onTouchTap={e => {
                          item.onTouchTap && item.onTouchTap(e);
                          onItemTouchTap && onItemTouchTap(e, item, index);
                      }}/>;

    }

    render() {

        const {className, style, data, separator, showLastSeparator} = this.props,

            crumbsClassName = (className ? ' ' + className : '');

        return (

                {
                    data && data.map((item, index) => (

                            {this.itemRender(item, index)}

                            {
                                !showLastSeparator && index === data.length - 1 ?
                                    null
                                    :

                                        {separator}

                            }

                    ))
                }

        );

    }
};<|endoftext|>


<commit_before>/**
 * @file Crumbs component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Crumb from '../_Crumb';
import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';

export default class Crumbs extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.itemRender = ::this.itemRender;

    }

    itemRender(item) {

        if (item.renderer) {
            return item.renderer(item);
        }

        const {itemRenderer} = this.props;
        if (itemRenderer) {
            return itemRenderer(item);
        }

        return <Crumb {...item}/>;

    }

    render() {

        const {className, style, items, separator} = this.props,

            crumbsClassName = (className ? ' ' + className : '');

        return (

                {
                    items.map((item, index) => {
                        return (

                                {this.itemRender(item)}

                                    {separator}

                        );
                    })
                }

        );

    }
};

Crumbs.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The theme of the Crumbs.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Crumbs items config.
     */
    items: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the list button.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the list button.
         */
        style: PropTypes.object,

        /**
         * The theme of the list button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The url of crumb.
         */
        href: PropTypes.string,

        /**
         * The text value of the list button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The list item's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the list button. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the list item will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * If true,the element's ripple effect will be disabled.
         */
        disableTouchRipple: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        tip: PropTypes.string,

        /**
         * The position of tip.
         */
        tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

        /**
         * If true,the item will have center displayed ripple effect.
         */
        rippleDisplayCenter: PropTypes.bool,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        renderer: PropTypes.func,

        /**
         * Callback function fired when a list item touch-tapped.
         */
        onTouchTap: PropTypes.func

    }), PropTypes.string, PropTypes.number])).isRequired,

    separator: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

    /**
     * Crumbs items renderer callback.
     */
    itemRenderer: PropTypes.func

};

Crumbs.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    items: [],

    separator: '>'

};<commit_msg>update Crumbs<commit_after>/**
 * @file Crumbs component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';

import Crumb from '../_Crumb';
import Tip from '../Tip';
import Theme from '../Theme';

import Util from '../_vendors/Util';

export default class Crumbs extends Component {

    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.itemRender = ::this.itemRender;

    }

    itemRender(item) {

        if (item.renderer) {
            return item.renderer(item);
        }

        const {itemRenderer} = this.props;
        if (itemRenderer) {
            return itemRenderer(item);
        }

        return <Crumb {...item}/>;

    }

    render() {

        const {className, style, items, separator} = this.props,

            crumbsClassName = (className ? ' ' + className : '');

        return (

                {
                    items && items.map((item, index) => {
                        return (

                                {this.itemRender(item)}

                                    {separator}

                        );
                    })
                }

        );

    }
};

Crumbs.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The theme of the Crumbs.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Crumbs items config.
     */
    items: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

        /**
         * The CSS class name of the list button.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the list button.
         */
        style: PropTypes.object,

        /**
         * The theme of the list button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The url of crumb.
         */
        href: PropTypes.string,

        /**
         * The text value of the list button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The list item's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the list button. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the list item will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * If true,the element's ripple effect will be disabled.
         */
        disableTouchRipple: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        tip: PropTypes.string,

        /**
         * The position of tip.
         */
        tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

        /**
         * If true,the item will have center displayed ripple effect.
         */
        rippleDisplayCenter: PropTypes.bool,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        renderer: PropTypes.func,

        /**
         * Callback function fired when a list item touch-tapped.
         */
        onTouchTap: PropTypes.func

    }), PropTypes.string, PropTypes.number])).isRequired,

    separator: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),

    /**
     * Crumbs items renderer callback.
     */
    itemRenderer: PropTypes.func

};

Crumbs.defaultProps = {

    className: null,
    style: null,
    theme: Theme.DEFAULT,

    items: null,

    separator: '>'

};<|endoftext|>


<commit_before>/**
 * @author Brandon Alexander - baalexander@gmail.com
 */

/**
 * Manages connection to the server and all interactions with ROS.
 *
 * Emits the following events:
 *  * 'error' - there was an error with ROS
 *  * 'connection' - connected to the WebSocket server
 *  * 'close' - disconnected to the WebSocket server
 *  * <topicName> - a message came from rosbridge with the given topic name
 *  * <serviceID> - a service response came from rosbridge with the given ID
 *
 * @constructor
 * @param options - possible keys include:
 *   * url (optional) - the WebSocket URL for rosbridge (can be specified later with `connect`)
 */
ROSLIB.Ros = function(options) {
  options = options || {};
  var url = options.url;
  this.socket = null;
  this.idCounter = 0;

  // Sets unlimited event listeners.
  this.setMaxListeners(0);

  // begin by checking if a URL was given
  if (url) {
    this.connect(url);
  }
};
ROSLIB.Ros.prototype.__proto__ = EventEmitter2.prototype;

/**
 * Connect to the specified WebSocket.
 *
 * @param url - WebSocket URL for Rosbridge
 */
ROSLIB.Ros.prototype.connect = function(url) {
  var that = this;

  /**
   * Emits a 'connection' event on WebSocket connection.
   *
   * @param event - the argument to emit with the event.
   */
  function onOpen(event) {
    that.emit('connection', event);
  }

  /**
   * Emits a 'close' event on WebSocket disconnection.
   *
   * @param event - the argument to emit with the event.
   */
  function onClose(event) {
    that.emit('close', event);
  }

  /**
   * Emits an 'error' event whenever there was an error.
   *
   * @param event - the argument to emit with the event.
   */
  function onError(event) {
    that.emit('error', event);
  }

  /**
   * If a message was compressed as a PNG image (a compression hack since
   * gzipping over WebSockets * is not supported yet), this function places the
   * "image" in a canvas element then decodes the * "image" as a Base64 string.
   *
   * @param data - object containing the PNG data.
   * @param callback - function with params:
   *   * data - the uncompressed data
   */
  function decompressPng(data, callback) {
    // Uncompresses the data before sending it through (use image/canvas to do so).
    var image = new Image();
    // When the image loads, extracts the raw data (JSON message).
    image.onload = function() {
      // Creates a local canvas to draw on.
      var canvas = document.createElement('canvas');
      var context = canvas.getContext('2d');

      // Sets width and height.
      canvas.width = image.width;
      canvas.height = image.height;

      // Puts the data into the image.
      context.drawImage(image, 0, 0);
      // Grabs the raw, uncompressed data.
      var imageData = context.getImageData(0, 0, image.width, image.height).data;

      // Constructs the JSON.
      var jsonData = '';
      for ( var i = 0; i < imageData.length; i += 4) {
        // RGB
        jsonData += String.fromCharCode(imageData[i], imageData[i + 1], imageData[i + 2]);
      }
      var decompressedData = JSON.parse(jsonData);
      callback(decompressedData);
    };
    // Sends the image data to load.
    image.src = 'data:image/png;base64,' + data.data;
  }

  /**
   * Parses message responses from rosbridge and sends to the appropriate
   * topic, service, or param.
   *
   * @param message - the raw JSON message from rosbridge.
   */
  function onMessage(message) {
    function handleMessage(message) {
      if (message.op === 'publish') {
        that.emit(message.topic, message.msg);
      } else if (message.op === 'service_response') {
        that.emit(message.id, message);
      }
    }

    var data = JSON.parse(message.data);
    if (data.op === 'png') {
      decompressPng(data, function(decompressedData) {
        handleMessage(decompressedData);
      });
    } else {
      handleMessage(data);
    }
  }

  this.socket = new WebSocket(url);
  this.socket.onopen = onOpen;
  this.socket.onclose = onClose;
  this.socket.onerror = onError;
  this.socket.onmessage = onMessage;
};

/**
 * Disconnect from the WebSocket server.
 */
ROSLIB.Ros.prototype.close = function() {
  if (this.socket) {
    this.socket.close();
  }
};

/**
 * Sends an authorization request to the server.
 *
 * @param mac - MAC (hash) string given by the trusted source.
 * @param client - IP of the client.
 * @param dest - IP of the destination.
 * @param rand - Random string given by the trusted source.
 * @param t - Time of the authorization request.
 * @param level - User level as a string given by the client.
 * @param end - End time of the client's session.
 */
ROSLIB.Ros.prototype.authenticate = function(mac, client, dest, rand, t, level, end) {
  // create the request
  var auth = {
    op : 'auth',
    mac : mac,
    client : client,
    dest : dest,
    rand : rand,
    t : t,
    level : level,
    end : end
  };
  // send the request
  this.callOnConnection(auth);
};

/**
 * Sends the message over the WebSocket, but queues the message up if not yet
 * connected.
 */
ROSLIB.Ros.prototype.callOnConnection = function(message) {
  var that = this;
  var messageJson = JSON.stringify(message);

  if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
    that.once('connection', function() {
      that.socket.send(messageJson);
    });
  } else {
    that.socket.send(messageJson);
  }
};

/**
 * Retrieves list of topics in ROS as an array.
 *
 * @param callback function with params:
 *   * topics - Array of topic names
 */
ROSLIB.Ros.prototype.getTopics = function(callback) {
  var topicsClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/topics',
    serviceType : 'rosapi/Topics'
  });

  var request = new ROSLIB.ServiceRequest();

  topicsClient.callService(request, function(result) {
    callback(result.topics);
  });
};

/**
 * Retrieves list of active service names in ROS.
 *
 * @param callback - function with the following params:
 *   * services - array of service names
 */
ROSLIB.Ros.prototype.getServices = function(callback) {
  var servicesClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/services',
    serviceType : 'rosapi/Services'
  });

  var request = new ROSLIB.ServiceRequest();

  servicesClient.callService(request, function(result) {
    callback(result.services);
  });
};

/**
 * Retrieves list of active node names in ROS.
 *
 * @param callback - function with the following params:
 *   * nodes - array of node names
 */
ROSLIB.Ros.prototype.getNodes = function(callback) {
  var nodesClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/nodes',
    serviceType : 'rosapi/Nodes'
  });

  var request = new ROSLIB.ServiceRequest();

  nodesClient.callService(request, function(result) {
    callback(result.nodes);
  });
};

/**
 * Retrieves list of param names from the ROS Parameter Server.
 *
 * @param callback function with params:
 *  * params - array of param names.
 */
ROSLIB.Ros.prototype.getParams = function(callback) {
  var paramsClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/get_param_names',
    serviceType : 'rosapi/GetParamNames'
  });

  var request = new ROSLIB.ServiceRequest();
  paramsClient.callService(request, function(result) {
    callback(result.names);
  });
};

/**
 * Retrieves a type of ROS topic.
 *
 * @param callback - function with params:
 *   * type - String of the topic type
 */
ROSLIB.Ros.prototype.getTopicType = function(topic, callback) {
  var topicTypeClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/topic_type',
    serviceType : 'rosapi/TopicType'
  });
  var request = new ROSLIB.ServiceRequest({
    topic: topic
  });
  topicTypeClient.callService(request, function(result) {
    callback(result.type);
  });
};

/**
 * Retrieves a detail of ROS message.
 *
 * @param callback - function with params:
 *   * details - Array of the message detail
 * @param message - String of a topic type
 */
ROSLIB.Ros.prototype.getMessageDetails = function(message, callback) {
  var messageDetailClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/message_details',
    serviceType : 'rosapi/MessageDetails'
  });
  var request = new ROSLIB.ServiceRequest({
    type: message
  });
  messageDetailClient.callService(request, function(result) {
    callback(result.typedefs);
  });
};

/**
 * Encode a typedefs into a dictionary like `rosmsg show foo/bar`
 * @param type_defs - array of type_def dictionary
 */
ROSLIB.Ros.prototype.decodeTypeDefs = function(type_defs) {
  var typeDefDict = {};
  var theType = type_defs[0];

  // It calls itself recursively to resolve type definition
  // using hint_defs.
  var decodeTypeDefsRec = function(theType, hint_defs) {
    var typeDefDict = {};
    for (var i = 0; i < theType.fieldnames.length; i++) {
      var arrayLen = theType.fieldarraylen[i];
      var fieldName = theType.fieldnames[i];
      var fieldType = theType.fieldtypes[i];
      if (fieldType.indexOf('/') === -1) { // check the fieldType includes '/' or not
        if (arrayLen === -1) {
          typeDefDict[fieldName] = fieldType;
        }
        else {
          typeDefDict[fieldName] = [fieldType];
        }
      }
      else {
        // lookup the name
        var sub_type = false;
        for (var j = 0; j < hint_defs.length; j++) {
          if (hint_defs[j].type.toString() === fieldType.toString()) {
            sub_type = hint_defs[j];
            break;
          }
        }
        if (sub_type) {
          var sub_type_result = decodeTypeDefsRec(sub_type, hint_defs);
          if (arrayLen === -1) {
            typeDefDict[fieldName] = sub_type_result;
          }
          else {
            typeDefDict[fieldName] = [sub_type_result];
          }
        }
        else {
          throw 'cannot find ' + fieldType;
        }
      }
    }
    return typeDefDict;
  };                            // end of decodeTypeDefsRec

  return decodeTypeDefsRec(type_defs[0], type_defs);
};

<commit_msg>cleanup of decodeTypeDefs function<commit_after>/**
 * @author Brandon Alexander - baalexander@gmail.com
 */

/**
 * Manages connection to the server and all interactions with ROS.
 *
 * Emits the following events:
 *  * 'error' - there was an error with ROS
 *  * 'connection' - connected to the WebSocket server
 *  * 'close' - disconnected to the WebSocket server
 *  * <topicName> - a message came from rosbridge with the given topic name
 *  * <serviceID> - a service response came from rosbridge with the given ID
 *
 * @constructor
 * @param options - possible keys include:
 *   * url (optional) - the WebSocket URL for rosbridge (can be specified later with `connect`)
 */
ROSLIB.Ros = function(options) {
  options = options || {};
  var url = options.url;
  this.socket = null;
  this.idCounter = 0;

  // Sets unlimited event listeners.
  this.setMaxListeners(0);

  // begin by checking if a URL was given
  if (url) {
    this.connect(url);
  }
};
ROSLIB.Ros.prototype.__proto__ = EventEmitter2.prototype;

/**
 * Connect to the specified WebSocket.
 *
 * @param url - WebSocket URL for Rosbridge
 */
ROSLIB.Ros.prototype.connect = function(url) {
  var that = this;

  /**
   * Emits a 'connection' event on WebSocket connection.
   *
   * @param event - the argument to emit with the event.
   */
  function onOpen(event) {
    that.emit('connection', event);
  }

  /**
   * Emits a 'close' event on WebSocket disconnection.
   *
   * @param event - the argument to emit with the event.
   */
  function onClose(event) {
    that.emit('close', event);
  }

  /**
   * Emits an 'error' event whenever there was an error.
   *
   * @param event - the argument to emit with the event.
   */
  function onError(event) {
    that.emit('error', event);
  }

  /**
   * If a message was compressed as a PNG image (a compression hack since
   * gzipping over WebSockets * is not supported yet), this function places the
   * "image" in a canvas element then decodes the * "image" as a Base64 string.
   *
   * @param data - object containing the PNG data.
   * @param callback - function with params:
   *   * data - the uncompressed data
   */
  function decompressPng(data, callback) {
    // Uncompresses the data before sending it through (use image/canvas to do so).
    var image = new Image();
    // When the image loads, extracts the raw data (JSON message).
    image.onload = function() {
      // Creates a local canvas to draw on.
      var canvas = document.createElement('canvas');
      var context = canvas.getContext('2d');

      // Sets width and height.
      canvas.width = image.width;
      canvas.height = image.height;

      // Puts the data into the image.
      context.drawImage(image, 0, 0);
      // Grabs the raw, uncompressed data.
      var imageData = context.getImageData(0, 0, image.width, image.height).data;

      // Constructs the JSON.
      var jsonData = '';
      for ( var i = 0; i < imageData.length; i += 4) {
        // RGB
        jsonData += String.fromCharCode(imageData[i], imageData[i + 1], imageData[i + 2]);
      }
      var decompressedData = JSON.parse(jsonData);
      callback(decompressedData);
    };
    // Sends the image data to load.
    image.src = 'data:image/png;base64,' + data.data;
  }

  /**
   * Parses message responses from rosbridge and sends to the appropriate
   * topic, service, or param.
   *
   * @param message - the raw JSON message from rosbridge.
   */
  function onMessage(message) {
    function handleMessage(message) {
      if (message.op === 'publish') {
        that.emit(message.topic, message.msg);
      } else if (message.op === 'service_response') {
        that.emit(message.id, message);
      }
    }

    var data = JSON.parse(message.data);
    if (data.op === 'png') {
      decompressPng(data, function(decompressedData) {
        handleMessage(decompressedData);
      });
    } else {
      handleMessage(data);
    }
  }

  this.socket = new WebSocket(url);
  this.socket.onopen = onOpen;
  this.socket.onclose = onClose;
  this.socket.onerror = onError;
  this.socket.onmessage = onMessage;
};

/**
 * Disconnect from the WebSocket server.
 */
ROSLIB.Ros.prototype.close = function() {
  if (this.socket) {
    this.socket.close();
  }
};

/**
 * Sends an authorization request to the server.
 *
 * @param mac - MAC (hash) string given by the trusted source.
 * @param client - IP of the client.
 * @param dest - IP of the destination.
 * @param rand - Random string given by the trusted source.
 * @param t - Time of the authorization request.
 * @param level - User level as a string given by the client.
 * @param end - End time of the client's session.
 */
ROSLIB.Ros.prototype.authenticate = function(mac, client, dest, rand, t, level, end) {
  // create the request
  var auth = {
    op : 'auth',
    mac : mac,
    client : client,
    dest : dest,
    rand : rand,
    t : t,
    level : level,
    end : end
  };
  // send the request
  this.callOnConnection(auth);
};

/**
 * Sends the message over the WebSocket, but queues the message up if not yet
 * connected.
 */
ROSLIB.Ros.prototype.callOnConnection = function(message) {
  var that = this;
  var messageJson = JSON.stringify(message);

  if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
    that.once('connection', function() {
      that.socket.send(messageJson);
    });
  } else {
    that.socket.send(messageJson);
  }
};

/**
 * Retrieves list of topics in ROS as an array.
 *
 * @param callback function with params:
 *   * topics - Array of topic names
 */
ROSLIB.Ros.prototype.getTopics = function(callback) {
  var topicsClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/topics',
    serviceType : 'rosapi/Topics'
  });

  var request = new ROSLIB.ServiceRequest();

  topicsClient.callService(request, function(result) {
    callback(result.topics);
  });
};

/**
 * Retrieves list of active service names in ROS.
 *
 * @param callback - function with the following params:
 *   * services - array of service names
 */
ROSLIB.Ros.prototype.getServices = function(callback) {
  var servicesClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/services',
    serviceType : 'rosapi/Services'
  });

  var request = new ROSLIB.ServiceRequest();

  servicesClient.callService(request, function(result) {
    callback(result.services);
  });
};

/**
 * Retrieves list of active node names in ROS.
 *
 * @param callback - function with the following params:
 *   * nodes - array of node names
 */
ROSLIB.Ros.prototype.getNodes = function(callback) {
  var nodesClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/nodes',
    serviceType : 'rosapi/Nodes'
  });

  var request = new ROSLIB.ServiceRequest();

  nodesClient.callService(request, function(result) {
    callback(result.nodes);
  });
};

/**
 * Retrieves list of param names from the ROS Parameter Server.
 *
 * @param callback function with params:
 *  * params - array of param names.
 */
ROSLIB.Ros.prototype.getParams = function(callback) {
  var paramsClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/get_param_names',
    serviceType : 'rosapi/GetParamNames'
  });

  var request = new ROSLIB.ServiceRequest();
  paramsClient.callService(request, function(result) {
    callback(result.names);
  });
};

/**
 * Retrieves a type of ROS topic.
 *
 * @param callback - function with params:
 *   * type - String of the topic type
 */
ROSLIB.Ros.prototype.getTopicType = function(topic, callback) {
  var topicTypeClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/topic_type',
    serviceType : 'rosapi/TopicType'
  });
  var request = new ROSLIB.ServiceRequest({
    topic: topic
  });
  topicTypeClient.callService(request, function(result) {
    callback(result.type);
  });
};

/**
 * Retrieves a detail of ROS message.
 *
 * @param callback - function with params:
 *   * details - Array of the message detail
 * @param message - String of a topic type
 */
ROSLIB.Ros.prototype.getMessageDetails = function(message, callback) {
  var messageDetailClient = new ROSLIB.Service({
    ros : this,
    name : '/rosapi/message_details',
    serviceType : 'rosapi/MessageDetails'
  });
  var request = new ROSLIB.ServiceRequest({
    type: message
  });
  messageDetailClient.callService(request, function(result) {
    callback(result.typedefs);
  });
};

/**
 * Decode a typedefs into a dictionary like `rosmsg show foo/bar`
 *
 * @param defs - array of type_def dictionary
 */
ROSLIB.Ros.prototype.decodeTypeDefs = function(defs) {
  var that = this;

  // calls itself recursively to resolve type definition using hints.
  var decodeTypeDefsRec = function(theType, hints) {
    var typeDefDict = {};
    for (var i = 0; i < theType.fieldnames.length; i++) {
      var arrayLen = theType.fieldarraylen[i];
      var fieldName = theType.fieldnames[i];
      var fieldType = theType.fieldtypes[i];
      if (fieldType.indexOf('/') === -1) { // check the fieldType includes '/' or not
        if (arrayLen === -1) {
          typeDefDict[fieldName] = fieldType;
        }
        else {
          typeDefDict[fieldName] = [fieldType];
        }
      }
      else {
        // lookup the name
        var sub = false;
        for (var j = 0; j < hints.length; j++) {
          if (hints[j].type.toString() === fieldType.toString()) {
            sub = hints[j];
            break;
          }
        }
        if (sub) {
          var subResult = decodeTypeDefsRec(sub, hints);
          if (arrayLen === -1) {
            typeDefDict[fieldName] = subResult;
          }
          else {
            typeDefDict[fieldName] = [subResult];
          }
        }
        else {
          that.emit('error', 'Cannot find ' + fieldType + ' in decodeTypeDefs');
        }
      }
    }
    return typeDefDict;
  };

  return decodeTypeDefsRec(defs[0], defs);
};
<|endoftext|>


<commit_before>var fs   = require('fs');
var path = require('path');
var glob = require('glob');

var apis = {};

glob.sync('src/ext/*/client.js').forEach(function (file) {
    var parts = file.split(path.sep);
    var id    = parts[parts.length - 2];

    apis[id] = require(path.relative(__dirname, path.resolve(file)));
});

var clients = {};

module.exports = {
    add: function (client, id) {
        clients[id] = {
            client:        client,
            subscriptions: []
        };

        console.log('Client #%d connected', id);
    },

    remove: function (id) {
        console.log('Client #%d disconnected', id);
    },

    wire: function (clientId, request) {
        var parts = request.id.split('.');

        if (!apis[parts[0]]) {
            console.log('Unable to find API matching id "%s"', parts[0]);

            return;
        }

        var api = apis[parts[0]];
        if (!api[parts[1]]) {
            console.log('Unable to find API call matching "%s"', parts[1]);

            return;
        }

        api[parts[1]](request.params)
            .then(function (data) {
                var message = {
                    id:   request.id,
                    body: data
                };

                clients[clientId].client.send(JSON.stringify(message));
            })
        ;
    }
};<commit_msg>Add naive poll system<commit_after>var fs   = require('fs');
var path = require('path');
var glob = require('glob');
var _    = require('lodash');

var apis = {};

/**
 * Collects all available APIs
 */
glob.sync('src/ext/*/client.js').forEach(function (file) {
    var parts = file.split(path.sep);
    var id    = parts[parts.length - 2];

    apis[id] = require(path.relative(__dirname, path.resolve(file)));
});

var clients       = {};
var subscriptions = {};

function processApiCall(id, callFn, params) {
    console.log('calling %s', id);
    callFn(params)
        .then(function (data) {
            var message = {
                id:   id,
                body: data
            };

            subscriptions[id].cached = message;

            subscriptions[id].clients.forEach(function (clientId) {
                clients[clientId].send(JSON.stringify(message));
            });
        })
        .catch(function (err) {
            console.log('ERROR — %s — status code: %s', id, err.status || err.statusCode);
        })
    ;
}

module.exports = {

    /**
     * Register a new client.
     *
     * @param client
     * @param id
     */
    add: function (client, id) {
        clients[id] = client;

        console.log('Client #%d connected', id);
    },

    /**
     * Remove a client.
     *
     * @param id
     */
    remove: function (id) {
        _.forOwn(subscriptions, function (subscription, subscriptionId) {
            subscription.clients = _.without(subscription.clients, id);
            if (subscription.clients.length === 0 && subscription.timer) {

                console.log('removing interval for %s', subscriptionId);

                clearInterval(subscription.timer);
                delete subscription.timer;
            }
        });

        delete clients[id];

        console.log('Client #%d disconnected', id);
    },

    /**
     * Add a subscription for the given client (client <-> API call).
     *
     * @param clientId
     * @param request
     */
    wire: function (clientId, request) {
        var requestId = request.id;
        var parts     = requestId.split('.');

        if (!apis[parts[0]]) {
            console.log('Unable to find API matching id "%s"', parts[0]);

            return;
        }

        var api = apis[parts[0]];
        if (!api[parts[1]]) {
            console.log('Unable to find API call matching "%s"', parts[1]);

            return;
        }

        var callFn = api[parts[1]];

        if (!subscriptions[requestId]) {
            console.log('adding subscription %s', requestId);
            subscriptions[requestId] = {
                clients:         [],
                currentResponse: null
            };

            processApiCall(requestId, callFn, request.params);
        }

        if (!subscriptions[requestId].timer) {
            subscriptions[requestId].timer = setInterval(function () {
                processApiCall(requestId, callFn, request.params);
            }, 30000);
        }

        if (!_.contains(subscriptions[requestId].clients, clientId)) {
            subscriptions[requestId].clients.push(clientId);
            if (subscriptions[requestId].cached !== null) {
                clients[clientId].send(JSON.stringify(subscriptions[requestId].cached));
            }
        }
    }
};<|endoftext|>


<commit_before>import React, { Component, PropTypes } from "react";
import moment from "moment";
import { Glyphicon } from "react-bootstrap";
import DateTimePicker from "./DateTimePicker.js";
import Constants from "./Constants.js";

export default class DateTimeField extends Component {
  static defaultProps = {
    dateTime: moment().format("x"),
    format: "x",
    showToday: true,
    viewMode: "days",
    daysOfWeekDisabled: [],
    mode: Constants.MODE_DATETIME,
    onChange: (x) => {
      console.log(x);
    }
  }

  resolvePropsInputFormat = () => {
    if (this.props.inputFormat) { return this.props.inputFormat; }
    switch (this.props.mode) {
      case Constants.MODE_TIME:
        return "h:mm A";
      case Constants.MODE_DATE:
        return "MM/DD/YY";
      default:
        return "MM/DD/YY h:mm A";
    }
  }

  static propTypes = {
    dateTime: PropTypes.string,
    onChange: PropTypes.func,
    format: PropTypes.string,
    inputProps: PropTypes.object,
    inputFormat: PropTypes.string,
    defaultText: PropTypes.string,
    mode: PropTypes.oneOf([Constants.MODE_DATE, Constants.MODE_DATETIME, Constants.MODE_TIME]),
    minDate: PropTypes.object,
    maxDate: PropTypes.object,
    direction: PropTypes.string,
    showToday: PropTypes.bool,
    viewMode: PropTypes.string,
    daysOfWeekDisabled: PropTypes.arrayOf(PropTypes.integer)
  }

  state = {
      showDatePicker: this.props.mode !== Constants.MODE_TIME,
      showTimePicker: this.props.mode === Constants.MODE_TIME,
      inputFormat: this.resolvePropsInputFormat(),
      buttonIcon: this.props.mode === Constants.MODE_TIME ? "time" : "calendar",
      widgetStyle: {
        display: "block",
        position: "absolute",
        left: -9999,
        zIndex: "9999 !important"
      },
      viewDate: moment(this.props.dateTime, this.props.format, true).startOf("month"),
      selectedDate: moment(this.props.dateTime, this.props.format, true),
      inputValue: typeof this.props.defaultText !== "undefined" ? this.props.defaultText : moment(this.props.dateTime, this.props.format, true).format(this.resolvePropsInputFormat())
  }

  componentWillReceiveProps = (nextProps) => {
    let state = {};
    if (nextProps.inputFormat !== this.props.inputFormat) {
        state.inputFormat = nextProps.inputFormat;
        state.inputValue = moment(nextProps.dateTime, nextProps.format, true).format(nextProps.inputFormat);
    }

    if (nextProps.dateTime !== this.props.dateTime && moment(nextProps.dateTime, nextProps.format, true).isValid()) {
      state.viewDate = moment(nextProps.dateTime, nextProps.format, true).startOf("month");
      state.selectedDate = moment(nextProps.dateTime, nextProps.format, true);
      state.inputValue = moment(nextProps.dateTime, nextProps.format, true).format(nextProps.inputFormat ? nextProps.inputFormat : this.state.inputFormat);
    }
    return this.setState(state);
  }

  onChange = (event) => {
    const value = event.currentTarget == null ? event : event.currentTarget.value;
    if (moment(value, this.state.inputFormat, true).isValid()) {
      this.setState({
        selectedDate: moment(value, this.state.inputFormat, true),
        viewDate: moment(value, this.state.inputFormat, true).startOf("month")
      });
    }

    return this.setState({
      inputValue: value
    }, function() {
      return this.props.onChange(moment(this.state.inputValue, this.state.inputFormat, true).format(this.props.format), value);
    });

  }

  getValue = () => {
    return moment(this.state.inputValue, this.props.inputFormat, true).format(this.props.format);
  }

  setSelectedDate = (e) => {
    const { target } = e;
    if (target.className && !target.className.match(/disabled/g)) {
      let month;
      if (target.className.indexOf("new") >= 0) month = this.state.viewDate.month() + 1;
      else if (target.className.indexOf("old") >= 0) month = this.state.viewDate.month() - 1;
      else month = this.state.viewDate.month();
      return this.setState({
        selectedDate: this.state.viewDate.clone().month(month).date(parseInt(e.target.innerHTML)).hour(this.state.selectedDate.hours()).minute(this.state.selectedDate.minutes())
      }, function() {
        this.closePicker();
        this.props.onChange(this.state.selectedDate.format(this.props.format));
        return this.setState({
          inputValue: this.state.selectedDate.format(this.state.inputFormat)
        });
      });
    }
  }

  setSelectedHour = (e) => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().hour(parseInt(e.target.innerHTML)).minute(this.state.selectedDate.minutes())
    }, function() {
      this.closePicker();
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.state.inputFormat)
      });
    });
  }

  setSelectedMinute = (e) => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().hour(this.state.selectedDate.hours()).minute(parseInt(e.target.innerHTML))
    }, function() {
      this.closePicker();
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.state.inputFormat)
      });
    });
  }

  setViewMonth = (month) => {
    return this.setState({
      viewDate: this.state.viewDate.clone().month(month)
    });
  }

  setViewYear = (year) => {
    return this.setState({
      viewDate: this.state.viewDate.clone().year(year)
    });
  }

  addMinute = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().add(1, "minutes")
    }, function() {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  addHour = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().add(1, "hours")
    }, function() {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  addMonth = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(1, "months")
    });
  }

  addYear = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(1, "years")
    });
  }

  addDecade = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(10, "years")
    });
  }

  subtractMinute = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().subtract(1, "minutes")
    }, () => {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  subtractHour = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().subtract(1, "hours")
    }, () => {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  subtractMonth = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(1, "months")
    });
  }

  subtractYear = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(1, "years")
    });
  }

  subtractDecade = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(10, "years")
    });
  }

  togglePeriod = () => {
    if (this.state.selectedDate.hour() > 12) {
      return this.onChange(this.state.selectedDate.clone().subtract(12, "hours").format(this.state.inputFormat));
    } else {
      return this.onChange(this.state.selectedDate.clone().add(12, "hours").format(this.state.inputFormat));
    }
  }

  togglePicker = () => {
    return this.setState({
      showDatePicker: !this.state.showDatePicker,
      showTimePicker: !this.state.showTimePicker
    });
  }

  onClick = () => {
    let classes, gBCR, offset, placePosition, scrollTop, styles;
    if (this.state.showPicker) {
      return this.closePicker();
    } else {
      this.setState({
        showPicker: true
      });
      gBCR = this.refs.dtpbutton.getDOMNode().getBoundingClientRect();
      classes = {
        "bootstrap-datetimepicker-widget": true,
        "dropdown-menu": true
      };
      offset = {
        top: gBCR.top + window.pageYOffset - document.documentElement.clientTop,
        left: gBCR.left + window.pageXOffset - document.documentElement.clientLeft
      };
      offset.top = offset.top + this.refs.datetimepicker.getDOMNode().offsetHeight;
      scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
      placePosition = this.props.direction === "up" ? "top" : this.props.direction === "bottom" ? "bottom" : this.props.direction === "auto" ? offset.top + this.refs.widget.getDOMNode().offsetHeight > window.offsetHeight + scrollTop && this.refs.widget.offsetHeight + this.refs.datetimepicker.getDOMNode().offsetHeight > offset.top ? "top" : "bottom" : void 0;
      if (placePosition === "top") {
        offset.top = -this.refs.widget.getDOMNode().offsetHeight - this.getDOMNode().clientHeight - 2;
        classes.top = true;
        classes.bottom = false;
        classes["pull-right"] = true;
      } else {
        offset.top = 40;
        classes.top = false;
        classes.bottom = true;
        classes["pull-right"] = true;
      }
      styles = {
        display: "block",
        position: "absolute",
        top: offset.top,
        left: "auto",
        right: 40
      };
      return this.setState({
        widgetStyle: styles,
        widgetClasses: classes
      });
    }
  }

  closePicker = () => {
    let style = {
      display: "none"
    };
    return this.setState({
      showPicker: false,
      widgetStyle: style
    });
  }

  renderOverlay = () => {
    const styles = {
      position: "fixed",
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      zIndex: "999"
    };
    if (this.state.showPicker) {
      return (
);
    } else {
      return ;
    }
  }

  render() {
    return (

            {this.renderOverlay()}
            <DateTimePicker ref="widget"
                  addDecade={this.addDecade}
                  addHour={this.addHour}
                  addMinute={this.addMinute}
                  addMonth={this.addMonth}
                  addYear={this.addYear}
                  daysOfWeekDisabled={this.props.daysOfWeekDisabled}
                  maxDate={this.props.maxDate}
                  minDate={this.props.minDate}
                  mode={this.props.mode}
                  selectedDate={this.state.selectedDate}
                  setSelectedDate={this.setSelectedDate}
                  setSelectedHour={this.setSelectedHour}
                  setSelectedMinute={this.setSelectedMinute}
                  setViewMonth={this.setViewMonth}
                  setViewYear={this.setViewYear}
                  showDatePicker={this.state.showDatePicker}
                  showTimePicker={this.state.showTimePicker}
                  showToday={this.props.showToday}
                  subtractDecade={this.subtractDecade}
                  subtractHour={this.subtractHour}
                  subtractMinute={this.subtractMinute}
                  subtractMonth={this.subtractMonth}
                  subtractYear={this.subtractYear}
                  togglePeriod={this.togglePeriod}
                  togglePicker={this.togglePicker}
                  viewDate={this.state.viewDate}
                  viewMode={this.props.viewMode}
                  widgetClasses={this.state.widgetClasses}
                  widgetStyle={this.state.widgetStyle}
            />

              <Glyphicon glyph={this.state.buttonIcon} />
              <input type="text" className="form-control" onChange={this.onChange} value={this.state.inputValue} {...this.props.inputProps}/>

    );
  }
}

<commit_msg>Update DateTimeField.js<commit_after>import React, { Component, PropTypes } from "react";
import moment from "moment";
import { Glyphicon } from "react-bootstrap";
import DateTimePicker from "./DateTimePicker.js";
import Constants from "./Constants.js";

export default class DateTimeField extends Component {
  static defaultProps = {
    dateTime: moment().format("x"),
    format: "x",
    showToday: true,
    viewMode: "days",
    daysOfWeekDisabled: [],
    mode: Constants.MODE_DATETIME,
    onChange: (x) => {
      console.log(x);
    }
  }

  resolvePropsInputFormat = () => {
    if (this.props.inputFormat) { return this.props.inputFormat; }
    switch (this.props.mode) {
      case Constants.MODE_TIME:
        return "h:mm A";
      case Constants.MODE_DATE:
        return "MM/DD/YY";
      default:
        return "MM/DD/YY h:mm A";
    }
  }

  static propTypes = {
    dateTime: PropTypes.string,
    onChange: PropTypes.func,
    format: PropTypes.string,
    inputProps: PropTypes.object,
    inputFormat: PropTypes.string,
    defaultText: PropTypes.string,
    mode: PropTypes.oneOf([Constants.MODE_DATE, Constants.MODE_DATETIME, Constants.MODE_TIME]),
    minDate: PropTypes.object,
    maxDate: PropTypes.object,
    direction: PropTypes.string,
    showToday: PropTypes.bool,
    viewMode: PropTypes.string,
    daysOfWeekDisabled: PropTypes.arrayOf(PropTypes.integer)
  }

  state = {
      showDatePicker: this.props.mode !== Constants.MODE_TIME,
      showTimePicker: this.props.mode === Constants.MODE_TIME,
      inputFormat: this.resolvePropsInputFormat(),
      buttonIcon: this.props.mode === Constants.MODE_TIME ? "time" : "calendar",
      widgetStyle: {
        display: "block",
        position: "absolute",
        left: -9999,
        zIndex: "9999 !important"
      },
      viewDate: moment(this.props.dateTime, this.props.format, true).startOf("month"),
      selectedDate: moment(this.props.dateTime, this.props.format, true),
      inputValue: typeof this.props.defaultText !== "undefined" ? this.props.defaultText : moment(this.props.dateTime, this.props.format, true).format(this.resolvePropsInputFormat())
  }

  componentWillReceiveProps = (nextProps) => {
    let state = {};
    if (nextProps.inputFormat !== this.props.inputFormat) {
        state.inputFormat = nextProps.inputFormat;
        state.inputValue = moment(nextProps.dateTime, nextProps.format, true).format(nextProps.inputFormat);
    }

    if (nextProps.dateTime !== this.props.dateTime && moment(nextProps.dateTime, nextProps.format, true).isValid()) {
      state.viewDate = moment(nextProps.dateTime, nextProps.format, true).startOf("month");
      state.selectedDate = moment(nextProps.dateTime, nextProps.format, true);
      state.inputValue = moment(nextProps.dateTime, nextProps.format, true).format(nextProps.inputFormat ? nextProps.inputFormat : this.state.inputFormat);
    }
    return this.setState(state);
  }

  onChange = (event) => {
    const value = event.currentTarget == null ? event : event.currentTarget.value;
    if (moment(value, this.state.inputFormat, true).isValid()) {
      this.setState({
        selectedDate: moment(value, this.state.inputFormat, true),
        viewDate: moment(value, this.state.inputFormat, true).startOf("month")
      });
    }

    return this.setState({
      inputValue: value
    }, function() {
      return this.props.onChange(moment(this.state.inputValue, this.state.inputFormat, true).format(this.props.format), value);
    });

  }

  getValue = () => {
    return moment(this.state.inputValue, this.props.inputFormat, true).format(this.props.format);
  }

  setSelectedDate = (e) => {
    const { target } = e;
    if (target.className && !target.className.match(/disabled/g)) {
      let month;
      if (target.className.indexOf("new") >= 0) month = this.state.viewDate.month() + 1;
      else if (target.className.indexOf("old") >= 0) month = this.state.viewDate.month() - 1;
      else month = this.state.viewDate.month();
      return this.setState({
        selectedDate: this.state.viewDate.clone().month(month).date(parseInt(e.target.innerHTML)).hour(this.state.selectedDate.hours()).minute(this.state.selectedDate.minutes())
      }, function() {
        this.closePicker();
        this.props.onChange(this.state.selectedDate.format(this.props.format));
        return this.setState({
          inputValue: this.state.selectedDate.format(this.state.inputFormat)
        });
      });
    }
  }

  setSelectedHour = (e) => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().hour(parseInt(e.target.innerHTML)).minute(this.state.selectedDate.minutes())
    }, function() {
      this.closePicker();
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.state.inputFormat)
      });
    });
  }

  setSelectedMinute = (e) => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().hour(this.state.selectedDate.hours()).minute(parseInt(e.target.innerHTML))
    }, function() {
      this.closePicker();
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.state.inputFormat)
      });
    });
  }

  setViewMonth = (month) => {
    return this.setState({
      viewDate: this.state.viewDate.clone().month(month)
    });
  }

  setViewYear = (year) => {
    return this.setState({
      viewDate: this.state.viewDate.clone().year(year)
    });
  }

  addMinute = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().add(1, "minutes")
    }, function() {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  addHour = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().add(1, "hours")
    }, function() {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  addMonth = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(1, "months")
    });
  }

  addYear = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(1, "years")
    });
  }

  addDecade = () => {
    return this.setState({
      viewDate: this.state.viewDate.add(10, "years")
    });
  }

  subtractMinute = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().subtract(1, "minutes")
    }, () => {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  subtractHour = () => {
    return this.setState({
      selectedDate: this.state.selectedDate.clone().subtract(1, "hours")
    }, () => {
      this.props.onChange(this.state.selectedDate.format(this.props.format));
      return this.setState({
        inputValue: this.state.selectedDate.format(this.resolvePropsInputFormat())
      });
    });
  }

  subtractMonth = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(1, "months")
    });
  }

  subtractYear = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(1, "years")
    });
  }

  subtractDecade = () => {
    return this.setState({
      viewDate: this.state.viewDate.subtract(10, "years")
    });
  }

  togglePeriod = () => {
    if (this.state.selectedDate.hour() > 12) {
      return this.onChange(this.state.selectedDate.clone().subtract(12, "hours").format(this.state.inputFormat));
    } else {
      return this.onChange(this.state.selectedDate.clone().add(12, "hours").format(this.state.inputFormat));
    }
  }

  togglePicker = () => {
    return this.setState({
      showDatePicker: !this.state.showDatePicker,
      showTimePicker: !this.state.showTimePicker
    });
  }

  onClick = () => {
    let classes, gBCR, offset, placePosition, scrollTop, styles;
    if (this.state.showPicker) {
      return this.closePicker();
    } else {
      this.setState({
        showPicker: true
      });
      gBCR = this.refs.dtpbutton.getBoundingClientRect();
      classes = {
        "bootstrap-datetimepicker-widget": true,
        "dropdown-menu": true
      };
      offset = {
        top: gBCR.top + window.pageYOffset - document.documentElement.clientTop,
        left: gBCR.left + window.pageXOffset - document.documentElement.clientLeft
      };
      offset.top = offset.top + this.refs.datetimepicker.offsetHeight;
      scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;
      placePosition = this.props.direction === "up" ? "top" : this.props.direction === "bottom" ? "bottom" : this.props.direction === "auto" ? offset.top + this.refs.widget.offsetHeight > window.offsetHeight + scrollTop && this.refs.widget.offsetHeight + this.refs.datetimepicker.offsetHeight > offset.top ? "top" : "bottom" : void 0;
      if (placePosition === "top") {
        offset.top = -this.refs.widget.offsetHeight - this.clientHeight - 2;
        classes.top = true;
        classes.bottom = false;
        classes["pull-right"] = true;
      } else {
        offset.top = 40;
        classes.top = false;
        classes.bottom = true;
        classes["pull-right"] = true;
      }
      styles = {
        display: "block",
        position: "absolute",
        top: offset.top,
        left: "auto",
        right: 40
      };
      return this.setState({
        widgetStyle: styles,
        widgetClasses: classes
      });
    }
  }

  closePicker = () => {
    let style = {
      display: "none"
    };
    return this.setState({
      showPicker: false,
      widgetStyle: style
    });
  }

  renderOverlay = () => {
    const styles = {
      position: "fixed",
      top: 0,
      bottom: 0,
      left: 0,
      right: 0,
      zIndex: "999"
    };
    if (this.state.showPicker) {
      return (
);
    } else {
      return ;
    }
  }

  render() {
    return (

            {this.renderOverlay()}
            <DateTimePicker ref="widget"
                  addDecade={this.addDecade}
                  addHour={this.addHour}
                  addMinute={this.addMinute}
                  addMonth={this.addMonth}
                  addYear={this.addYear}
                  daysOfWeekDisabled={this.props.daysOfWeekDisabled}
                  maxDate={this.props.maxDate}
                  minDate={this.props.minDate}
                  mode={this.props.mode}
                  selectedDate={this.state.selectedDate}
                  setSelectedDate={this.setSelectedDate}
                  setSelectedHour={this.setSelectedHour}
                  setSelectedMinute={this.setSelectedMinute}
                  setViewMonth={this.setViewMonth}
                  setViewYear={this.setViewYear}
                  showDatePicker={this.state.showDatePicker}
                  showTimePicker={this.state.showTimePicker}
                  showToday={this.props.showToday}
                  subtractDecade={this.subtractDecade}
                  subtractHour={this.subtractHour}
                  subtractMinute={this.subtractMinute}
                  subtractMonth={this.subtractMonth}
                  subtractYear={this.subtractYear}
                  togglePeriod={this.togglePeriod}
                  togglePicker={this.togglePicker}
                  viewDate={this.state.viewDate}
                  viewMode={this.props.viewMode}
                  widgetClasses={this.state.widgetClasses}
                  widgetStyle={this.state.widgetStyle}
            />

              <Glyphicon glyph={this.state.buttonIcon} />
              <input type="text" className="form-control" onChange={this.onChange} value={this.state.inputValue} {...this.props.inputProps}/>

    );
  }
}

<|endoftext|>


<commit_before>/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

/* eslint-disable prefer-arrow-callback,no-var */

exports.loadToPrototype = loadToPrototype;
exports.loadToConstructor = loadToConstructor;

require('core-js/modules/web.immediate');

loadToConstructor([
	[
		Object,
		['toQueryString', require('sugar/object/toQueryString')],
		['fromQueryString', require('sugar/object/fromQueryString')],
		['isEqual', require('sugar/object/isEqual')],
		['isObject', require('sugar/object/isObject')],
		['reject', require('sugar/object/reject')],
		['select', require('sugar/object/select')]
	],

	[
		RegExp,
		['escape', require('sugar/regexp/escape')]
	],

	[
		Number,
		['range', require('sugar/number/range')]
	],

	[
		Date,
		['create', require('sugar/date/create')],
		['range', require('sugar/date/range')]
	],

	[
		Range,
		require('sugar/range').Range
	]
]);

loadToPrototype([
	[
		String,
		['dasherize', require('sugar/string/dasherize')],
		['camelize', require('sugar/string/camelize')]
	],

	[
		Number,
		['second', require('sugar/number/second')],
		['seconds', require('sugar/number/seconds')]
	],

	[
		Function,
		['once', require('sugar/function/once')],
		['debounce', require('sugar/function/debounce')],
		['throttle', require('sugar/function/throttle')]
	],

	[
		Array,
		['union', require('sugar/array/union')]
	],

	[
		Date,
		require('sugar/date').Date
	]
]);

function loadToConstructor(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0][fn[0]] = fn[1];

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						obj[0][key] = fn[key];
					}
				}
			}
		});
	});
}

function loadToPrototype(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0].prototype[fn[0]] = function () {
					return fn[1](this, ...arguments);
				};

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						obj[0].prototype[key] = function () {
							return fn[key](this, ...arguments);
						};
					}
				}
			}
		});
	});
}
<commit_msg>Added Sugar locales<commit_after>/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

/* eslint-disable prefer-arrow-callback,no-var */

exports.loadToPrototype = loadToPrototype;
exports.loadToConstructor = loadToConstructor;

require('core-js/modules/web.immediate');
require('sugar/locales/ru');

loadToConstructor([
	[
		Object,
		['toQueryString', require('sugar/object/toQueryString')],
		['fromQueryString', require('sugar/object/fromQueryString')],
		['isEqual', require('sugar/object/isEqual')],
		['isObject', require('sugar/object/isObject')],
		['reject', require('sugar/object/reject')],
		['select', require('sugar/object/select')]
	],

	[
		RegExp,
		['escape', require('sugar/regexp/escape')]
	],

	[
		Number,
		['range', require('sugar/number/range')]
	],

	[
		Date,
		['create', require('sugar/date/create')],
		['range', require('sugar/date/range')]
	],

	[
		Range,
		require('sugar/range').Range
	]
]);

loadToPrototype([
	[
		String,
		['dasherize', require('sugar/string/dasherize')],
		['camelize', require('sugar/string/camelize')]
	],

	[
		Number,
		['second', require('sugar/number/second')],
		['seconds', require('sugar/number/seconds')]
	],

	[
		Function,
		['once', require('sugar/function/once')],
		['debounce', require('sugar/function/debounce')],
		['throttle', require('sugar/function/throttle')]
	],

	[
		Array,
		['union', require('sugar/array/union')]
	],

	[
		Date,
		require('sugar/date').Date
	]
]);

function loadToConstructor(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0][fn[0]] = fn[1];

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						obj[0][key] = fn[key];
					}
				}
			}
		});
	});
}

function loadToPrototype(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0].prototype[fn[0]] = function () {
					return fn[1](this, ...arguments);
				};

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						obj[0].prototype[key] = function () {
							return fn[key](this, ...arguments);
						};
					}
				}
			}
		});
	});
}
<|endoftext|>


<commit_before>/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

/* eslint-disable prefer-arrow-callback,no-var */

exports.loadToPrototype = loadToPrototype;
exports.loadToConstructor = loadToConstructor;

require('core-js/modules/web.immediate');
require('sugar/locales/ru');

loadToConstructor([
	[
		Object,
		['toQueryString', require('sugar/object/toQueryString')],
		['fromQueryString', require('sugar/object/fromQueryString')],
		['isEqual', require('sugar/object/isEqual')],
		['isObject', require('sugar/object/isObject')],
		['reject', require('sugar/object/reject')],
		['select', require('sugar/object/select')]
	],

	[
		RegExp,
		['escape', require('sugar/regexp/escape')]
	],

	[
		Number,
		['range', require('sugar/number/range')]
	],

	[
		Date,
		['create', require('sugar/date/create')],
		['range', require('sugar/date/range')]
	],

	[
		Range,
		require('sugar/range').Range
	]
]);

loadToPrototype([
	[
		String,
		['dasherize', require('sugar/string/dasherize')],
		['camelize', require('sugar/string/camelize')]
	],

	[
		Number,
		['second', require('sugar/number/second')],
		['seconds', require('sugar/number/seconds')],
		['minute', require('sugar/number/minute')],
		['minutes', require('sugar/number/minutes')],
		['hour', require('sugar/number/hour')],
		['hours', require('sugar/number/hours')],
		['floor', require('sugar/number/floor')],
		['format', require('sugar/number/format')]
	],

	[
		Function,
		['once', require('sugar/function/once')],
		['memoize', require('sugar/function/memoize')],
		['debounce', require('sugar/function/debounce')],
		['throttle', require('sugar/function/throttle')]
	],

	[
		Array,
		['union', require('sugar/array/union')]
	],

	[
		Date,
		require('sugar/date').Date
	]
]);

function loadToConstructor(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0][fn[0]] = fn[1];

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						(function (key) {
							obj[0][key] = fn[key];
						})(key);
					}
				}
			}
		});
	});
}

function loadToPrototype(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0].prototype[fn[0]] = function () {
					return fn[1].apply(fn[1], [this].concat([].slice.call(arguments)));
				};

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						(function (key) {
							obj[0].prototype[key] = function () {
								return fn[key].apply(fn[key], [this].concat([].slice.call(arguments)));
							};
						})(key);
					}
				}
			}
		});
	});
}
<commit_msg>Refactoring<commit_after>/*!
 * V4Fire Client Core
 * https://github.com/V4Fire/Client
 *
 * Released under the MIT license
 * https://github.com/V4Fire/Client/blob/master/LICENSE
 */

/* eslint-disable prefer-arrow-callback,no-var */

exports.loadToPrototype = loadToPrototype;
exports.loadToConstructor = loadToConstructor;

require('core-js/modules/web.immediate');
require('sugar/locales/ru');

loadToConstructor([
	[
		Object,
		['toQueryString', require('sugar/object/toQueryString')],
		['fromQueryString', require('sugar/object/fromQueryString')],
		['isEqual', require('sugar/object/isEqual')],
		['isObject', require('sugar/object/isObject')],
		['reject', require('sugar/object/reject')],
		['select', require('sugar/object/select')]
	],

	[
		RegExp,
		['escape', require('sugar/regexp/escape')]
	],

	[
		Number,
		['range', require('sugar/number/range')]
	],

	[
		Date,
		['create', require('sugar/date/create')],
		['range', require('sugar/date/range')]
	],

	[
		Range,
		require('sugar/range').Range
	]
]);

loadToPrototype([
	[
		String,
		['dasherize', require('sugar/string/dasherize')],
		['camelize', require('sugar/string/camelize')]
	],

	[
		Number,
		['second', require('sugar/number/second')],
		['seconds', require('sugar/number/seconds')],
		['minute', require('sugar/number/minute')],
		['minutes', require('sugar/number/minutes')],
		['hour', require('sugar/number/hour')],
		['hours', require('sugar/number/hours')],
		['floor', require('sugar/number/floor')],
		['format', require('sugar/number/format')]
	],

	[
		Function,
		['once', require('sugar/function/once')],
		['memoize', require('sugar/function/memoize')],
		['debounce', require('sugar/function/debounce')],
		['throttle', require('sugar/function/throttle')]
	],

	[
		Array,
		['union', require('sugar/array/union')]
	],

	[
		Date,
		require('sugar/date').Date
	]
]);

function loadToConstructor(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0][fn[0]] = fn[1];

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						(function (key) {
							obj[0][key] = fn[key];
						})(key);
					}
				}
			}
		});
	});
}

function loadToPrototype(list) {
	list.forEach(function (obj) {
		obj.slice(1).forEach(function (fn) {
			if (Array.isArray(fn)) {
				obj[0].prototype[fn[0]] = function () {
					return fn[1].apply(fn[1], [this].concat(Array.from(arguments)));
				};

			} else {
				for (var key in fn) {
					if (fn.hasOwnProperty(key)) {
						(function (key) {
							obj[0].prototype[key] = function () {
								return fn[key].apply(fn[key], [this].concat(Array.from(arguments)));
							};
						})(key);
					}
				}
			}
		});
	});
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
 * Holds the current Platform object used by the code to do anything
 * specific to the platform we're running on (eg. web, electron)
 * Platforms are provided by the app layer.
 * This allows the app layer to set a Platform without necessarily
 * having to have a MatrixChat object
 */

import PlatformPeg from "./PlatformPeg";
import EventIndex from "./EventIndexing";

class EventIndexPeg {
    constructor() {
        this.index = null;
    }

    /**
     * Create a new EventIndex and initialize it if the platform supports it.
     *
     * @return {Promise<bool>} A promise that will resolve to true if an
     * EventIndex was successfully initialized, false otherwise.
     */
    async init() {
        const indexManager = PlatformPeg.get().getEventIndexingManager();
        if (!indexManager || await indexManager.supportsEventIndexing() !== true) {
            console.log("EventIndex: Platform doesn't support event indexing,",
                        "not initializing.");
            return false;
        }

        const index = new EventIndex();

        try {
            await index.init();
        } catch (e) {
            console.log("EventIndex: Error initializing the event index", e);
            return false;
        }

        console.log("EventIndex: Successfully initialized the event index");

        this.index = index;

        return true;
    }

    /**
     * Get the current event index.
     *
     * @return {EventIndex} The current event index.
     */
    get() {
        return this.index;
    }

    stop() {
        if (this.index === null) return;
        this.index.stopCrawler();
    }

    /**
     * Unset our event store
     *
     * After a call to this the init() method will need to be called again.
     *
     * @return {Promise} A promise that will resolve once the event index is
     * closed.
     */
    async unset() {
        if (this.index === null) return;
        this.index.close();
        this.index = null;
    }

    /**
     * Delete our event indexer.
     *
     * After a call to this the init() method will need to be called again.
     *
     * @return {Promise} A promise that will resolve once the event index is
     * deleted.
     */
    async deleteEventIndex() {
        const indexManager = PlatformPeg.get().getEventIndexingManager();

        if (indexManager !== null) {
            this.stop();
            console.log("EventIndex: Deleting event index.");
            await indexManager.deleteEventIndex();
            this.index = null;
        }
    }
}

if (!global.mxEventIndexPeg) {
    global.mxEventIndexPeg = new EventIndexPeg();
}
module.exports = global.mxEventIndexPeg;
<commit_msg>EventIndexPeg: Rewrite the module documentation.<commit_after>/*
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/*
 * Object holding the global EventIndex object. Can only be initialized if the
 * platform supports event indexing.
 */

import PlatformPeg from "./PlatformPeg";
import EventIndex from "./EventIndexing";

class EventIndexPeg {
    constructor() {
        this.index = null;
    }

    /**
     * Create a new EventIndex and initialize it if the platform supports it.
     *
     * @return {Promise<bool>} A promise that will resolve to true if an
     * EventIndex was successfully initialized, false otherwise.
     */
    async init() {
        const indexManager = PlatformPeg.get().getEventIndexingManager();
        if (!indexManager || await indexManager.supportsEventIndexing() !== true) {
            console.log("EventIndex: Platform doesn't support event indexing,",
                        "not initializing.");
            return false;
        }

        const index = new EventIndex();

        try {
            await index.init();
        } catch (e) {
            console.log("EventIndex: Error initializing the event index", e);
            return false;
        }

        console.log("EventIndex: Successfully initialized the event index");

        this.index = index;

        return true;
    }

    /**
     * Get the current event index.
     *
     * @return {EventIndex} The current event index.
     */
    get() {
        return this.index;
    }

    stop() {
        if (this.index === null) return;
        this.index.stopCrawler();
    }

    /**
     * Unset our event store
     *
     * After a call to this the init() method will need to be called again.
     *
     * @return {Promise} A promise that will resolve once the event index is
     * closed.
     */
    async unset() {
        if (this.index === null) return;
        this.index.close();
        this.index = null;
    }

    /**
     * Delete our event indexer.
     *
     * After a call to this the init() method will need to be called again.
     *
     * @return {Promise} A promise that will resolve once the event index is
     * deleted.
     */
    async deleteEventIndex() {
        const indexManager = PlatformPeg.get().getEventIndexingManager();

        if (indexManager !== null) {
            this.stop();
            console.log("EventIndex: Deleting event index.");
            await indexManager.deleteEventIndex();
            this.index = null;
        }
    }
}

if (!global.mxEventIndexPeg) {
    global.mxEventIndexPeg = new EventIndexPeg();
}
module.exports = global.mxEventIndexPeg;
<|endoftext|>