<commit_before>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import _ from "lodash";
import React from "react";
import { Link, withRouter } from "react-router-dom";
import { Table, Tag, Spin, Button, Input, Modal, Icon, Card } from "antd";
import Utils from "libs/utils";
import Clipboard from "clipboard-js";
import Toast from "libs/toast";
import messages from "messages";
import TaskSearchForm from "admin/task/task_search_form";
import { deleteTask, getTasks } from "admin/admin_rest_api";
import TemplateHelpers from "libs/template_helpers";
import FormatUtils from "libs/format_utils";
import TaskAnnotationView from "admin/task/task_annotation_view";
import Persistence from "libs/persistence";
import { PropTypes } from "@scalableminds/prop-types";
import type { APITaskType, APITaskTypeType } from "admin/api_flow_types";
import type { QueryObjectType, TaskFormFieldValuesType } from "admin/task/task_search_form";
import type { RouterHistory } from "react-router-dom";

const { Column } = Table;
const { Search, TextArea } = Input;

type Props = {
  initialFieldValues?: TaskFormFieldValuesType,
  history: RouterHistory,
};

type State = {
  isLoading: boolean,
  tasks: Array<APITaskType>,
  searchQuery: string,
  isAnonymousTaskLinkModalVisible: boolean,
};

const persistence: Persistence<State> = new Persistence(
  { searchQuery: PropTypes.string },
  "taskList",
);

class TaskListView extends React.PureComponent<Props, State> {
  state = {
    isLoading: false,
    tasks: [],
    searchQuery: "",
    isAnonymousTaskLinkModalVisible: Utils.hasUrlParam("showAnonymousLinks"),
  };

  componentWillMount() {
    this.setState(persistence.load(this.props.history));
  }

  componentWillUpdate(nextProps, nextState) {
    persistence.persist(this.props.history, nextState);
  }

  async fetchData(queryObject: QueryObjectType) {
    if (!_.isEmpty(queryObject)) {
      this.setState({ isLoading: true });

      const tasks = await getTasks(queryObject);
      this.setState({
        tasks,
        isLoading: false,
      });
    } else {
      this.setState({ tasks: [] });
    }
  }

  handleSearch = (event: SyntheticInputEvent<>): void => {
    this.setState({ searchQuery: event.target.value });
  };

  deleteTask = (task: APITaskType) => {
    Modal.confirm({
      title: messages["task.delete"],
      onOk: async () => {
        this.setState({
          isLoading: true,
        });

        await deleteTask(task.id);
        this.setState({
          isLoading: false,
          tasks: this.state.tasks.filter(t => t.id !== task.id),
        });
      },
    });
  };

  getAnonymousTaskLinkModal() {
    const anonymousTaskId = Utils.getUrlParamValue("showAnonymousLinks");
    if (!this.state.isAnonymousTaskLinkModalVisible) {
      return null;
    }
    const tasksString = this.state.tasks
      .filter(t => t.id === anonymousTaskId)
      .map(t => t.directLinks)
      .join("\n");
    return (
      <Modal
        title={`Anonymous Task Links for Task ${anonymousTaskId}`}
        visible={this.state.isAnonymousTaskLinkModalVisible}
        onOk={() => {
          Clipboard.copy(tasksString).then(() => Toast.success("Links copied to clipboard"));
          this.setState({ isAnonymousTaskLinkModalVisible: false });
        }}
        onCancel={() => this.setState({ isAnonymousTaskLinkModalVisible: false })}
      >
        <TextArea autosize={{ minRows: 2, maxRows: 10 }} defaultValue={tasksString} />
      </Modal>
    );
  }

  render() {
    const marginRight = { marginRight: 20 };

    return (

          <Link to="/tasks/create">
            <Button icon="plus" style={marginRight} type="primary">
              Add Task
            </Button>
          </Link>
          <Search
            style={{ width: 200 }}
            onPressEnter={this.handleSearch}
            onChange={this.handleSearch}
            value={this.state.searchQuery}
          />

Tasks

        <Card title="Search for Tasks">
          <TaskSearchForm
            onChange={queryObject => this.fetchData(queryObject)}
            initialFieldValues={this.props.initialFieldValues}
            isLoading={this.state.isLoading}
          />
        </Card>

        <Spin spinning={this.state.isLoading} size="large">

 <TaskAnnotationView task={task} />}
          >
            <Column
              title="ID"
              dataIndex="id"
              key="id"
              sorter={Utils.localeCompareBy("id")}
              className="monospace-id"
            />
            <Column
              title="Project"
              dataIndex="projectName"
              key="projectName"
              width={130}
              sorter={Utils.localeCompareBy("projectName")}
              render={(projectName: string) => (
                <a href={`/projects#${projectName}`}>{projectName}
              )}
            />
            <Column
              title="Type"
              dataIndex="type"
              key="type"
              width={100}
              sorter={Utils.localeCompareBy((task: APITaskType) => task.type.summary)}
              render={(taskType: APITaskTypeType) => (
                <a href={`/taskTypes#${taskType.id}`}>{taskType.summary}
              )}
            />
            <Column
              title="Dataset"
              dataIndex="dataSet"
              key="dataSet"
              width={130}
              sorter={Utils.localeCompareBy("dataSet")}
            />
            <Column
              title="Edit Position / Bounding Box"
              dataIndex="editPosition"
              key="editPosition"
              width={130}
              render={(__, task: APITaskType) => (

                  {TemplateHelpers.formatTuple(task.editPosition)}

                  {TemplateHelpers.formatTuple(task.boundingBoxVec6)}

              )}
            />
            <Column
              title="Experience"
              dataIndex="neededExperience"
              key="neededExperience"
              sorter={Utils.localeCompareBy(neededExperience => neededExperience.domain)}
              width={200}
              render={neededExperience =>
                neededExperience.domain !== "" || neededExperience.value > 0 ? (
                  <Tag>
                    {neededExperience.domain} : {neededExperience.value}
                  </Tag>
                ) : null
              }
            />
            <Column
              title="Creation Date"
              dataIndex="created"
              key="created"
              width={150}
              sorter={Utils.localeCompareBy("created")}
            />
            <Column
              title="Stats"
              dataIndex="status"
              key="status"
              width={80}
              render={(status, task: APITaskType) => (

                    <Icon type="play-circle-o" />
                    {status.open}

                    <Icon type="fork" />
                    {status.active}

                    <Icon type="check-circle-o" />
                    {status.finished}

                    <Icon type="clock-circle-o" />
                    {FormatUtils.formatSeconds(task.tracingTime / 1000)}

              )}
            />
            <Column
              title="Action"
              key="actions"
              width={130}
              render={(__, task: APITaskType) => (

                  {task.status.finished > 0 ? (
                    <a
                      href={`/annotations/CompoundTask/${task.id}`}
                      title="View all Finished Tracings"
                    >
                      <Icon type="eye-o" />View

                  ) : null}

                  <a href={`/tasks/${task.id}/edit`} title="Edit Task">
                    <Icon type="edit" />Edit

                  {task.status.finished > 0 ? (
                    <a
                      href={`/api/annotations/CompoundTask/${task.id}/download`}
                      title="Download all Finished Tracings"
                    >
                      <Icon type="download" />Download

                  ) : null}

                    <Icon type="delete" />Delete

              )}
            />

          {this.getAnonymousTaskLinkModal()}
        </Spin>

    );
  }
}

export default withRouter(TaskListView);
<commit_msg>add tooltip to task status icons<commit_after>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import _ from "lodash";
import React from "react";
import { Link, withRouter } from "react-router-dom";
import { Table, Tag, Spin, Button, Input, Modal, Icon, Card } from "antd";
import Utils from "libs/utils";
import Clipboard from "clipboard-js";
import Toast from "libs/toast";
import messages from "messages";
import TaskSearchForm from "admin/task/task_search_form";
import { deleteTask, getTasks } from "admin/admin_rest_api";
import TemplateHelpers from "libs/template_helpers";
import FormatUtils from "libs/format_utils";
import TaskAnnotationView from "admin/task/task_annotation_view";
import Persistence from "libs/persistence";
import { PropTypes } from "@scalableminds/prop-types";
import type { APITaskType, APITaskTypeType } from "admin/api_flow_types";
import type { QueryObjectType, TaskFormFieldValuesType } from "admin/task/task_search_form";
import type { RouterHistory } from "react-router-dom";

const { Column } = Table;
const { Search, TextArea } = Input;

type Props = {
  initialFieldValues?: TaskFormFieldValuesType,
  history: RouterHistory,
};

type State = {
  isLoading: boolean,
  tasks: Array<APITaskType>,
  searchQuery: string,
  isAnonymousTaskLinkModalVisible: boolean,
};

const persistence: Persistence<State> = new Persistence(
  { searchQuery: PropTypes.string },
  "taskList",
);

class TaskListView extends React.PureComponent<Props, State> {
  state = {
    isLoading: false,
    tasks: [],
    searchQuery: "",
    isAnonymousTaskLinkModalVisible: Utils.hasUrlParam("showAnonymousLinks"),
  };

  componentWillMount() {
    this.setState(persistence.load(this.props.history));
  }

  componentWillUpdate(nextProps, nextState) {
    persistence.persist(this.props.history, nextState);
  }

  async fetchData(queryObject: QueryObjectType) {
    if (!_.isEmpty(queryObject)) {
      this.setState({ isLoading: true });

      const tasks = await getTasks(queryObject);
      this.setState({
        tasks,
        isLoading: false,
      });
    } else {
      this.setState({ tasks: [] });
    }
  }

  handleSearch = (event: SyntheticInputEvent<>): void => {
    this.setState({ searchQuery: event.target.value });
  };

  deleteTask = (task: APITaskType) => {
    Modal.confirm({
      title: messages["task.delete"],
      onOk: async () => {
        this.setState({
          isLoading: true,
        });

        await deleteTask(task.id);
        this.setState({
          isLoading: false,
          tasks: this.state.tasks.filter(t => t.id !== task.id),
        });
      },
    });
  };

  getAnonymousTaskLinkModal() {
    const anonymousTaskId = Utils.getUrlParamValue("showAnonymousLinks");
    if (!this.state.isAnonymousTaskLinkModalVisible) {
      return null;
    }
    const tasksString = this.state.tasks
      .filter(t => t.id === anonymousTaskId)
      .map(t => t.directLinks)
      .join("\n");
    return (
      <Modal
        title={`Anonymous Task Links for Task ${anonymousTaskId}`}
        visible={this.state.isAnonymousTaskLinkModalVisible}
        onOk={() => {
          Clipboard.copy(tasksString).then(() => Toast.success("Links copied to clipboard"));
          this.setState({ isAnonymousTaskLinkModalVisible: false });
        }}
        onCancel={() => this.setState({ isAnonymousTaskLinkModalVisible: false })}
      >
        <TextArea autosize={{ minRows: 2, maxRows: 10 }} defaultValue={tasksString} />
      </Modal>
    );
  }

  render() {
    const marginRight = { marginRight: 20 };

    return (

          <Link to="/tasks/create">
            <Button icon="plus" style={marginRight} type="primary">
              Add Task
            </Button>
          </Link>
          <Search
            style={{ width: 200 }}
            onPressEnter={this.handleSearch}
            onChange={this.handleSearch}
            value={this.state.searchQuery}
          />

Tasks

        <Card title="Search for Tasks">
          <TaskSearchForm
            onChange={queryObject => this.fetchData(queryObject)}
            initialFieldValues={this.props.initialFieldValues}
            isLoading={this.state.isLoading}
          />
        </Card>

        <Spin spinning={this.state.isLoading} size="large">

 <TaskAnnotationView task={task} />}
          >
            <Column
              title="ID"
              dataIndex="id"
              key="id"
              sorter={Utils.localeCompareBy("id")}
              className="monospace-id"
            />
            <Column
              title="Project"
              dataIndex="projectName"
              key="projectName"
              width={130}
              sorter={Utils.localeCompareBy("projectName")}
              render={(projectName: string) => (
                <a href={`/projects#${projectName}`}>{projectName}
              )}
            />
            <Column
              title="Type"
              dataIndex="type"
              key="type"
              width={100}
              sorter={Utils.localeCompareBy((task: APITaskType) => task.type.summary)}
              render={(taskType: APITaskTypeType) => (
                <a href={`/taskTypes#${taskType.id}`}>{taskType.summary}
              )}
            />
            <Column
              title="Dataset"
              dataIndex="dataSet"
              key="dataSet"
              width={130}
              sorter={Utils.localeCompareBy("dataSet")}
            />
            <Column
              title="Edit Position / Bounding Box"
              dataIndex="editPosition"
              key="editPosition"
              width={130}
              render={(__, task: APITaskType) => (

                  {TemplateHelpers.formatTuple(task.editPosition)}

                  {TemplateHelpers.formatTuple(task.boundingBoxVec6)}

              )}
            />
            <Column
              title="Experience"
              dataIndex="neededExperience"
              key="neededExperience"
              sorter={Utils.localeCompareBy(neededExperience => neededExperience.domain)}
              width={200}
              render={neededExperience =>
                neededExperience.domain !== "" || neededExperience.value > 0 ? (
                  <Tag>
                    {neededExperience.domain} : {neededExperience.value}
                  </Tag>
                ) : null
              }
            />
            <Column
              title="Creation Date"
              dataIndex="created"
              key="created"
              width={150}
              sorter={Utils.localeCompareBy("created")}
            />
            <Column
              title="Stats"
              dataIndex="status"
              key="status"
              width={80}
              render={(status, task: APITaskType) => (

                    <Icon type="play-circle-o" />
                    {status.open}

                    <Icon type="fork" />
                    {status.active}

                    <Icon type="check-circle-o" />
                    {status.finished}

                    <Icon type="clock-circle-o" />
                    {FormatUtils.formatSeconds(task.tracingTime / 1000)}

              )}
            />
            <Column
              title="Action"
              key="actions"
              width={130}
              render={(__, task: APITaskType) => (

                  {task.status.finished > 0 ? (
                    <a
                      href={`/annotations/CompoundTask/${task.id}`}
                      title="View all Finished Tracings"
                    >
                      <Icon type="eye-o" />View

                  ) : null}

                  <a href={`/tasks/${task.id}/edit`} title="Edit Task">
                    <Icon type="edit" />Edit

                  {task.status.finished > 0 ? (
                    <a
                      href={`/api/annotations/CompoundTask/${task.id}/download`}
                      title="Download all Finished Tracings"
                    >
                      <Icon type="download" />Download

                  ) : null}

                    <Icon type="delete" />Delete

              )}
            />

          {this.getAnonymousTaskLinkModal()}
        </Spin>

    );
  }
}

export default withRouter(TaskListView);
<|endoftext|>


<commit_before>/* globals Awesomplete */
const React = require('react');
const ReactDOM = require('react-dom');
// Dependencies
const Focus = require('focus-core');
let {builder, types} = Focus.component;
let find = require('lodash/collection/find');
const InputText = require('../input/text').component;

/**
 * Autocomplete component.
 * Get a pickList as an input, then let the user type and suggests values from the picklist.
 * Can force values in the input field to be taken from the pick list only.
 * @type {Object}
 */
let Autocomplete = {
    /**
     * Component will mount.
     * Check if the Awesomplete library is in the Window object.
     */
    componentWillMount() {
        // Check if Awesomplete is set in Window
        if (!window.Awesomplete) {
            throw new Error('Please include Awesomplete to your application. See http://leaverou.github.io/awesomplete/ for more information');
        }
    },
    /**
     * Component did mount.
     * Initiates the Awesomplete object.
     */
    componentDidMount() {
        let {inputText: input} = this.refs.input.refs;
        let {code, codeResolver, pickList} = this.props;
        this._awesomeplete = new Awesomplete(ReactDOM.findDOMNode(input), {
            list: this._extractListFromData(pickList)
        });
        this._awesomeplete.input.addEventListener('awesomplete-select', event => this._selectionHandler(event.text));
        this._resolveValueFromPicklistOrCodeResolver(code, pickList);
    },
    /**
     * Default props.
     * @return {Object} default props
     */
    getDefaultProps() {
        return {
            code: '',
            pickList: [],
            timeoutDuration: 200,
            allowUnmatchedValue: true
        };
    },
    /**
     * Prop validation
     * @type {Object}
     */
    propTypes: {
        allowUnmatchedValue: types('bool'), // restrict user input to values of the list, or allow freestyle
        code: types('string'), // the field code value
        inputChangeHandler: types('func'), // callback when input changed
        pickList: types('array'), // list of values, looking like [{code: '', value: ''}, {code: '', value: ''}, ...]
        selectionHandler: types('func'), // selection callback
        timeoutDuration: types('number') // the throttle duration of the input rate
    },
    /**
     * Initial state.
     * Retrieve the value from the provided code and pick list.
     * @return {Object} initial state
     */
    getInitialState() {
        const {code, pickList} = this.props;
        return ({
            value: 0 < pickList.length ? this._getValueFromCode(code) : code
        });
    },
    /**
     * Component will receive props.
     * Update the pick list, and try to resolve the new value.
     * @param  {Object} nextProps new props
     */
    componentWillReceiveProps({pickList, code}) {
        if (code !== this.props.code) {
            this._resolveValueFromPicklistOrCodeResolver(code, pickList);
        }
        this._awesomeplete._list = this._extractListFromData(pickList);
    },
    _resolveValueFromPicklistOrCodeResolver(code, pickList) {
        const {codeResolver} = this.props;
        const value = this._getValueFromCode(code, pickList);
        if ('' !== value) {
            this.setState({value}); // eslint-disable-line
        } else if (codeResolver) {
            codeResolver(code).then(resolvedValue => {
                if ('' !== resolvedValue) {
                    this.setState({value: resolvedValue}, () => {
                        this.props.inputChangeHandler(resolvedValue);
                    }); // eslint-disable-line
                }
            });
        }
    },
    /**
     * Selection handler.
     * If a selection handler is set in the props, send it the selected pick.
     * Also, set a flag to tell the blur listener not to empty the value, because the selection, as it is a click outside the input, raises a blur event.
     * @param  {String} value selected value from the dropdown list
     */
    _selectionHandler(value) {
        const {selectionHandler} = this.props;
        if (selectionHandler) {
            const {pickList} = this.props;
            const selectedPick = find(pickList, {value});
            selectionHandler(selectedPick);
        }
        this._isSelecting = true; // Private flag to tell the blur listener not to replace the value
        this.setState({value});
    },
    /**
     * Extract list of suggestions from pick list
     * @param  {Object} data the pick list
     * @return {Array}      the suggestion array
     */
    _extractListFromData(data) {
        return data.map(datum => datum.value);
    },
    /**
     * Get code from value in the pick list
     * @param  {String} value the value
     * @return {String} the code
     */
    _getCodeFromValue(value) {
        const {pickList} = this.props;
        const pick = find(pickList, {value});
        return pick ? pick.code : pick;
    },
    /**
     * Get value from code in the pick list
     * @param  {String} code the code
     * @param  {Object} pickList=this.props.pickList  optional pick list to resolve the value from
     * @return {String} value
     */
    _getValueFromCode(code, pickList=this.props.pickList) {
        const pick = find(pickList, {code});
        return pick ? pick.value : '';
    },
    /**
     * Get the current code
     * @return {String} the code
     */
    getValue() {
        const {value} = this.state;
        const {allowUnmatchedValue} = this.props;
        const computedValue = this._getCodeFromValue(value);
        return computedValue ? computedValue : allowUnmatchedValue ? value : this.props.code;
    },
    /**
     * On input blur.
     * If allowUnmatchedValue is set in the props, validate the current value and erase it if not valid.
     */
    _onInputBlur() {
        const {value} = this.state;
        const {allowUnmatchedValue, pickList, selectionHandler} = this.props;
        const selectedPick = find(pickList, {value});
        const code = this._getCodeFromValue(value);
        if (selectedPick && !this._isSelecting && selectionHandler) {
            selectionHandler(selectedPick);
        }
        if (!code && !allowUnmatchedValue && !this._isSelecting) {
            this.setState({value: ''});
            selectionHandler({code: '', value: ''});
        }

        this._isSelecting = false;
    },
    /**
     * On input change
     * @param  {Object} event change event
     */
    _onInputChange(event) {
        const {value} = event.target;
        const {timeoutDuration} = this.props;
        this.setState({value});
        if (this._changeTimeout) {
            clearTimeout(this._changeTimeout);
        }
        this._changeTimeout = setTimeout(() => {
            let {inputChangeHandler} = this.props;
            if (inputChangeHandler) {
                inputChangeHandler(value);
            }
        }, timeoutDuration);
    },
    /**
     * Render
     * @return {HTML} rendered element
     */
    render() {
        const {value} = this.state;
        const {_onInputBlur, _onInputChange} = this;
        return (

                <InputText onBlur={_onInputBlur} onChange={_onInputChange} ref='input' value={value}/>

        );
    }
};

module.exports = builder(Autocomplete);
<commit_msg>Revert onInputBlur prop removal<commit_after>/* globals Awesomplete */
const React = require('react');
const ReactDOM = require('react-dom');
// Dependencies
const Focus = require('focus-core');
let {builder, types} = Focus.component;
let find = require('lodash/collection/find');
const InputText = require('../input/text').component;

/**
 * Autocomplete component.
 * Get a pickList as an input, then let the user type and suggests values from the picklist.
 * Can force values in the input field to be taken from the pick list only.
 * @type {Object}
 */
let Autocomplete = {
    /**
     * Component will mount.
     * Check if the Awesomplete library is in the Window object.
     */
    componentWillMount() {
        // Check if Awesomplete is set in Window
        if (!window.Awesomplete) {
            throw new Error('Please include Awesomplete to your application. See http://leaverou.github.io/awesomplete/ for more information');
        }
    },
    /**
     * Component did mount.
     * Initiates the Awesomplete object.
     */
    componentDidMount() {
        let {inputText: input} = this.refs.input.refs;
        let {code, codeResolver, pickList} = this.props;
        this._awesomeplete = new Awesomplete(ReactDOM.findDOMNode(input), {
            list: this._extractListFromData(pickList)
        });
        this._awesomeplete.input.addEventListener('awesomplete-select', event => this._selectionHandler(event.text));
        this._resolveValueFromPicklistOrCodeResolver(code, pickList);
    },
    /**
     * Default props.
     * @return {Object} default props
     */
    getDefaultProps() {
        return {
            code: '',
            pickList: [],
            timeoutDuration: 200,
            allowUnmatchedValue: true
        };
    },
    /**
     * Prop validation
     * @type {Object}
     */
    propTypes: {
        allowUnmatchedValue: types('bool'), // restrict user input to values of the list, or allow freestyle
        code: types('string'), // the field code value
        inputChangeHandler: types('func'), // callback when input changed
        onInputBlur: types('func'),
        pickList: types('array'), // list of values, looking like [{code: '', value: ''}, {code: '', value: ''}, ...]
        selectionHandler: types('func'), // selection callback
        timeoutDuration: types('number') // the throttle duration of the input rate
    },
    /**
     * Initial state.
     * Retrieve the value from the provided code and pick list.
     * @return {Object} initial state
     */
    getInitialState() {
        const {code, pickList} = this.props;
        return ({
            value: 0 < pickList.length ? this._getValueFromCode(code) : code
        });
    },
    /**
     * Component will receive props.
     * Update the pick list, and try to resolve the new value.
     * @param  {Object} nextProps new props
     */
    componentWillReceiveProps({pickList, code}) {
        if (code !== this.props.code) {
            this._resolveValueFromPicklistOrCodeResolver(code, pickList);
        }
        this._awesomeplete._list = this._extractListFromData(pickList);
    },
    _resolveValueFromPicklistOrCodeResolver(code, pickList) {
        const {codeResolver} = this.props;
        const value = this._getValueFromCode(code, pickList);
        if ('' !== value) {
            this.setState({value}); // eslint-disable-line
        } else if (codeResolver) {
            codeResolver(code).then(resolvedValue => {
                if ('' !== resolvedValue) {
                    this.setState({value: resolvedValue}, () => {
                        this.props.inputChangeHandler(resolvedValue);
                    }); // eslint-disable-line
                }
            });
        }
    },
    /**
     * Selection handler.
     * If a selection handler is set in the props, send it the selected pick.
     * Also, set a flag to tell the blur listener not to empty the value, because the selection, as it is a click outside the input, raises a blur event.
     * @param  {String} value selected value from the dropdown list
     */
    _selectionHandler(value) {
        const {selectionHandler} = this.props;
        if (selectionHandler) {
            const {pickList} = this.props;
            const selectedPick = find(pickList, {value});
            selectionHandler(selectedPick);
        }
        this._isSelecting = true; // Private flag to tell the blur listener not to replace the value
        this.setState({value});
    },
    /**
     * Extract list of suggestions from pick list
     * @param  {Object} data the pick list
     * @return {Array}      the suggestion array
     */
    _extractListFromData(data) {
        return data.map(datum => datum.value);
    },
    /**
     * Get code from value in the pick list
     * @param  {String} value the value
     * @return {String} the code
     */
    _getCodeFromValue(value) {
        const {pickList} = this.props;
        const pick = find(pickList, {value});
        return pick ? pick.code : pick;
    },
    /**
     * Get value from code in the pick list
     * @param  {String} code the code
     * @param  {Object} pickList=this.props.pickList  optional pick list to resolve the value from
     * @return {String} value
     */
    _getValueFromCode(code, pickList=this.props.pickList) {
        const pick = find(pickList, {code});
        return pick ? pick.value : '';
    },
    /**
     * Get the current code
     * @return {String} the code
     */
    getValue() {
        const {value} = this.state;
        const {allowUnmatchedValue} = this.props;
        const computedValue = this._getCodeFromValue(value);
        return computedValue ? computedValue : allowUnmatchedValue ? value : this.props.code;
    },
    /**
     * On input blur.
     * If allowUnmatchedValue is set in the props, validate the current value and erase it if not valid.
     */
    _onInputBlur() {
        const {value} = this.state;
        const {allowUnmatchedValue, onInputBlur, pickList, selectionHandler} = this.props;
        const selectedPick = find(pickList, {value});
        const code = this._getCodeFromValue(value);
        if (selectedPick && !this._isSelecting && selectionHandler) {
            selectionHandler(selectedPick);
        }
        if (!code && !allowUnmatchedValue && !this._isSelecting) {
            this.setState({value: ''});
            selectionHandler({code: '', value: ''});
        }

        onInputBlur && onInputBlur();

        this._isSelecting = false;
    },
    /**
     * On input change
     * @param  {Object} event change event
     */
    _onInputChange(event) {
        const {value} = event.target;
        const {timeoutDuration} = this.props;
        this.setState({value});
        if (this._changeTimeout) {
            clearTimeout(this._changeTimeout);
        }
        this._changeTimeout = setTimeout(() => {
            let {inputChangeHandler} = this.props;
            if (inputChangeHandler) {
                inputChangeHandler(value);
            }
        }, timeoutDuration);
    },
    /**
     * Render
     * @return {HTML} rendered element
     */
    render() {
        const {value} = this.state;
        const {_onInputBlur, _onInputChange} = this;
        return (

                <InputText onBlur={_onInputBlur} onChange={_onInputChange} ref='input' value={value}/>

        );
    }
};

module.exports = builder(Autocomplete);
<|endoftext|>


<commit_before>define([
	'goo/fsmpack/statemachine/actions/Action',
	'goo/math/Quaternion',
	'goo/math/Matrix3',
	'goo/math/MathUtils',
	'goo/util/TWEEN'
], function (
	Action,
	Quaternion,
	Matrix3,
	MathUtils,
	TWEEN
) {
	'use strict';

	function TweenRotationAction(/*id, settings*/) {
		Action.apply(this, arguments);

		this.quatFrom = new Quaternion();
		this.quatTo = new Quaternion();
		this.quatFinal = new Quaternion();
		this.quatDelta = new Quaternion();
		this.quatOld = new Quaternion();
		this.quatCalc = new Quaternion();
		this.completed = false;
	}

	TweenRotationAction.prototype = Object.create(Action.prototype);
	TweenRotationAction.prototype.constructor = TweenRotationAction;

	TweenRotationAction.external = {
		key: 'Tween Rotation',
		name: 'Tween Rotate',
		type: 'animation',
		description: 'Transition to the set rotation, in angles.',
		canTransition: true,
		parameters: [{
			name: 'Rotation',
			key: 'to',
			type: 'rotation',
			description: 'Rotation.',
			'default': [0, 0, 0]
		}, {
			name: 'Relative',
			key: 'relative',
			type: 'boolean',
			description: 'If true add, otherwise set.',
			'default': true
		}, {
			name: 'Time (ms)',
			key: 'time',
			type: 'float',
			description: 'Time it takes for this movement to complete.',
			'default': 1000
		}, {
			name: 'Easing type',
			key: 'easing1',
			type: 'string',
			control: 'dropdown',
			description: 'Easing type.',
			'default': 'Linear',
			options: ['Linear', 'Quadratic', 'Exponential', 'Circular', 'Elastic', 'Back', 'Bounce']
		}, {
			name: 'Direction',
			key: 'easing2',
			type: 'string',
			control: 'dropdown',
			description: 'Easing direction.',
			'default': 'In',
			options: ['In', 'Out', 'InOut']
		}],
		transitions: [{
			key: 'complete',
			description: 'State to transition to when the rotation completes.'
		}]
	};

	TweenRotationAction.getTransitionLabel = function(transitionKey/*, actionConfig*/){
		return transitionKey === 'complete' ? 'On Tween Rotation Complete' : undefined;
	};

	TweenRotationAction.prototype.ready = function () {
		if (this.easing1 === 'Linear') {
			this.easing = TWEEN.Easing.Linear.None;
		} else {
			this.easing = TWEEN.Easing[this.easing1][this.easing2];
		}
	};

	TweenRotationAction.prototype.enter = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transformComponent = entity.transformComponent;

		this.startTime = fsm.getTime();

		this.quatFrom.fromRotationMatrix(transformComponent.transform.rotation);
		this.quatOld.set(this.quatFrom);
		this.quatFinal.set(this.quatFrom);
		this.quatTo.fromRotationMatrix(new Matrix3().fromAngles(this.to[0] * MathUtils.DEG_TO_RAD, this.to[1] * MathUtils.DEG_TO_RAD, this.to[2] * MathUtils.DEG_TO_RAD));
		if (this.relative) {
			this.quatTo.mul(this.quatFrom);
		}
		this.completed = false;
	};

	TweenRotationAction.prototype.update = function (fsm) {
		if (this.completed) {
			return;
		}
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;

		var t = Math.min((fsm.getTime() - this.startTime) * 1000 / this.time, 1);
		var fT = this.easing(t);

		if (this.relative) {
			this.quatCalc.set(this.quatOld).invert();
			Quaternion.slerp(this.quatFrom, this.quatTo, fT, this.quatDelta).mul(this.quatCalc);
			this.quatFinal.mul(this.quatDelta);
			this.quatOld.mul(this.quatDelta);
		} else {
			Quaternion.slerp(this.quatFrom, this.quatTo, fT, this.quatFinal);
		}

		this.quatFinal.toRotationMatrix(transform.rotation);
		entity.transformComponent.setUpdated();

		if (t >= 1) {
			fsm.send(this.transitions.complete);
			this.completed = true;
		}
	};

	return TweenRotationAction;
});<commit_msg>Skip converting tween rotate<commit_after>define([
	'goo/fsmpack/statemachine/actions/Action',
	'goo/math/Quaternion',
	'goo/math/Matrix3',
	'goo/math/MathUtils',
	'goo/util/TWEEN'
], function (
	Action,
	Quaternion,
	Matrix3,
	MathUtils,
	TWEEN
) {
	'use strict';

	function TweenRotationAction(/*id, settings*/) {
		Action.apply(this, arguments);

		this.quatFrom = new Quaternion();
		this.quatTo = new Quaternion();
		this.quatFinal = new Quaternion();
		this.completed = false;
	}

	TweenRotationAction.prototype = Object.create(Action.prototype);
	TweenRotationAction.prototype.constructor = TweenRotationAction;

	TweenRotationAction.external = {
		key: 'Tween Rotation',
		name: 'Tween Rotate',
		type: 'animation',
		description: 'Transition to the set rotation, in angles.',
		canTransition: true,
		parameters: [{
			name: 'Rotation',
			key: 'to',
			type: 'rotation',
			description: 'Rotation.',
			'default': [0, 0, 0]
		}, {
			name: 'Relative',
			key: 'relative',
			type: 'boolean',
			description: 'If true add, otherwise set.',
			'default': true
		}, {
			name: 'Time (ms)',
			key: 'time',
			type: 'float',
			description: 'Time it takes for this movement to complete.',
			'default': 1000
		}, {
			name: 'Easing type',
			key: 'easing1',
			type: 'string',
			control: 'dropdown',
			description: 'Easing type.',
			'default': 'Linear',
			options: ['Linear', 'Quadratic', 'Exponential', 'Circular', 'Elastic', 'Back', 'Bounce']
		}, {
			name: 'Direction',
			key: 'easing2',
			type: 'string',
			control: 'dropdown',
			description: 'Easing direction.',
			'default': 'In',
			options: ['In', 'Out', 'InOut']
		}],
		transitions: [{
			key: 'complete',
			description: 'State to transition to when the rotation completes.'
		}]
	};

	TweenRotationAction.getTransitionLabel = function(transitionKey/*, actionConfig*/){
		return transitionKey === 'complete' ? 'On Tween Rotation Complete' : undefined;
	};

	TweenRotationAction.prototype.ready = function () {
		if (this.easing1 === 'Linear') {
			this.easing = TWEEN.Easing.Linear.None;
		} else {
			this.easing = TWEEN.Easing[this.easing1][this.easing2];
		}
	};

	TweenRotationAction.prototype.enter = function (fsm) {
		var entity = fsm.getOwnerEntity();
		var transformComponent = entity.transformComponent;

		this.startTime = fsm.getTime();

		this.quatFrom.fromRotationMatrix(transformComponent.transform.rotation);
		this.quatTo.fromRotationMatrix(new Matrix3().fromAngles(this.to[0] * MathUtils.DEG_TO_RAD, this.to[1] * MathUtils.DEG_TO_RAD, this.to[2] * MathUtils.DEG_TO_RAD));
		if (this.relative) {
			this.quatTo.mul(this.quatFrom);
		}
		this.completed = false;
	};

	TweenRotationAction.prototype.update = function (fsm) {
		if (this.completed) {
			return;
		}
		var entity = fsm.getOwnerEntity();
		var transform = entity.transformComponent.transform;

		var t = Math.min((fsm.getTime() - this.startTime) * 1000 / this.time, 1);
		var fT = this.easing(t);
		Quaternion.slerp(this.quatFrom, this.quatTo, fT, this.quatFinal);

		this.quatFinal.toRotationMatrix(transform.rotation);
		entity.transformComponent.setUpdated();

		if (t >= 1) {
			fsm.send(this.transitions.complete);
			this.completed = true;
		}
	};

	return TweenRotationAction;
});<|endoftext|>


<commit_before>import {parse} from 'node-sqlparser'
import {Promise} from 'es6-promise'
import path from 'path'
import {
  config,
  Manager,
  FileParser,
  getAttr
} from '../../'

export default class Sql {

  constructor() {

  }

  static cleanRequest(str, jsonPage) {
    var matchFrom = /from .(.*?) /
    var matchVariable = /{{([a-zA-Z]*)}}/

    var matchFromExec = matchFrom.exec(str)
    if(typeof matchFromExec !== 'undefined' && matchFromExec !== null
      && typeof matchFromExec[1] !== 'undefined' && matchFromExec[1] !== null) {

      var fromMatch
      var toReplace = matchFromExec[1]
      while (fromMatch = matchVariable.exec(toReplace)) {
        try {
          var value = eval('jsonPage.' + fromMatch[1])
          if(typeof value !== 'undefined' && value !== null) {
            toReplace = toReplace.replace('{{' + fromMatch[1] + '}}', value)
          }else {
            toReplace = toReplace.replace('{{' + fromMatch[1] + '}}', '')
          }
        }catch(e) {
        }
      }

      str = str.replace(matchFromExec[1], toReplace)
    }

    var from = /from ([\S\s]+)/.exec(str)

    var matches = from
    if(matches[1]) {
      var res = matches[1]
      var splitAttr = [' where ', ' order by ', ' limit ', ' WHERE ', ' ORDER BY ', ' LIMIT ']
      for(var i = 0; i < splitAttr.length; i++) {
        if(res.indexOf(splitAttr[i]) > -1) {
          res = res.substring(0, res.indexOf(splitAttr[i]))
        }
      }
      var escapedFrom = res.replace(/\//g, '___abe___')
      escapedFrom = escapedFrom.replace(/\./g, '___abe_dot___')
      escapedFrom = escapedFrom.replace(/-/g, '___abe_dash___')
      str = str.replace(res, escapedFrom)
    }

    str = str.replace(/``/g, '\'\'')

    return str
  }

  static handleSqlRequest(str, jsonPage) {
    var cleanRequest = Sql.cleanRequest(str, jsonPage)
    var request = parse(cleanRequest)
    var reconstructSql = ''

    // SQL TYPE
    var type = ''
    if(typeof request.type !== 'undefined' && request.type !== null) {
      type = request.type
    }
    reconstructSql += `${type} `

    // SQL COLUMNS
    var columns = []
    if(typeof request.columns !== 'undefined' && request.columns !== null) {
      if(request.columns === '*') {
        columns.push('*')
      }else {
        Array.prototype.forEach.call(request.columns, (item) => {
          columns.push(item.expr.column)
        })
      }
    }
    reconstructSql += `${JSON.stringify(columns)} `

    // SQL FROM
    var from = []
    if(typeof request.from !== 'undefined' && request.from !== null) {

      Array.prototype.forEach.call(request.from, (item) => {
        from.push(item.table)
      })
    }else {
      from.push('*')
    }
    reconstructSql += `from ${JSON.stringify(from)} `

    var where
    if(typeof request.where !== 'undefined' && request.where !== null) {
      where = request.where
      // where = Sql.recurseWhere(request.where)
      // reconstructSql += 'where '
      // Array.prototype.forEach.call(where, (w) => {
      //   reconstructSql += `${w.operator} ${w.left} ${w.compare} ${w.right} `
      // })
    }

    var limit = -1
    if(typeof request.limit !== 'undefined' && request.limit !== null) {
      limit = request.limit[request.limit.length - 1].value
    }

    var orderby
    if(typeof request.orderby !== 'undefined' && request.orderby !== null && request.orderby.length > 0) {
      orderby = {
        column: request.orderby[0].expr.column,
        type: request.orderby[0].type
      }
      reconstructSql += `ORDER BY ${orderby.column} ${orderby.type} `
    }

    return {
      type: type,
      columns: columns,
      from: from,
      where: where,
      string: reconstructSql,
      limit: limit,
      orderby: orderby
    }
  }

  static sortByDateDesc(a, b) {
    var dateA = new Date(a.date)
    var dateB = new Date(b.date)
    if(dateA < dateB) {
      return 1
    }else if(dateA > dateB) {
      return -1
    }
    return 0
  }

  static shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex)
      currentIndex -= 1

      // And swap it with the current element.
      temporaryValue = array[currentIndex]
      array[currentIndex] = array[randomIndex]
      array[randomIndex] = temporaryValue
    }

    return array
  }

  static sortByDateAsc(a, b) {
    var dateA = new Date(a.date)
    var dateB = new Date(b.date)
    if(dateA > dateB) {
      return 1
    }else if(dateA < dateB) {
      return -1
    }
    return 0
  }

  static getDataSource(str) {
    var res = str.substring(str.indexOf('source=') + 8, str.length)

    var reg = /([^'"]*=[\s\S]*?}})/g
    var matches = res.match(reg)
    if(typeof matches !== 'undefined' && matches !== null) {
      Array.prototype.forEach.call(matches, (match) => {
        res = res.replace(match, '')
      })
    }else {
      res = res.replace('}}', '')
    }

    return res.substring(0, res.length-1)
  }

  /**
   * replaces escaped characters with the right ones
   * @param  {String} statement the from clause
   * @return {String}           the from sanitized
   */
  static sanitizeFromStatement(statement){
    var from = ''

    if(typeof statement !== 'undefined' && statement !== null) {
      from = statement[0].replace(/___abe_dot___/g, '.')
      from = from.replace(/___abe___/g, '/')
      from = from.replace(/___abe_dash___/g, '-')
    }

    return from
  }

  /**
   * calculate the directory to analyze from the from clause
   * @param  {String} statement the from clause
   * @param  {String} tplPath   the path from the template originator
   * @return {string}           the directory to analyze
   */
  static getFromDirectory(statement, tplPath){
    var pathFromDir = ''
    if(typeof tplPath === 'undefined' || tplPath === null || tplPath === ''){
      tplPath = '/'
    }

    if(statement === '' || statement === '*' || statement === '/') {
      pathFromDir = path.join(config.root, config.data.url)
    }else if(statement === './') {
      pathFromDir = path.join(config.root, config.data.url, tplPath)
    }else if(statement.indexOf('/') === 0) {
      pathFromDir = path.join(config.root, config.data.url, statement)
    }else if(statement.indexOf('/') !== 0) {
      pathFromDir = path.join(config.root, config.data.url, tplPath, statement)
    }

    return pathFromDir
  }

  static executeOrderByClause(files, orderby){
    if(typeof orderby !== 'undefined' && orderby !== null) {
      if(orderby.column.toLowerCase() === 'random') {
        Sql.shuffle(files)
      }else if(orderby.column.toLowerCase() === 'date') {
        if(orderby.type === 'ASC') {
          files.sort(Sql.sortByDateAsc)
        }else if(orderby.type === 'DESC') {
          files.sort(Sql.sortByDateDesc)
        }
      }
    }

    return files
  }

  static executeFromClause(statement, pathFromClause){
    var from = Sql.sanitizeFromStatement(statement)

    // if the from clause ends with a dot, we won't recurse the directory analyze
    if(from.slice(-1) === '.'){
      from = from.slice(0, -1)
    }

    var fromDirectory = Sql.getFromDirectory(from, pathFromClause)

    var list = Manager.instance.getList()
    var files_array = list.filter((element, index) => {
      if(element.publish) {
        if (element.path.indexOf(fromDirectory) > -1) {
          return true
        }
      }
      return false
    })
    return files_array
  }

  static execQuery(pathQuery, match, jsonPage) {
    var res
    var files
    var request = Sql.handleSqlRequest(getAttr(match, 'source'), jsonPage)

    files = Sql.executeFromClause(request.from, pathQuery)
    files = Sql.executeOrderByClause(files, request.orderby)
    res = Sql.executeWhereClause(files, request.where, request.limit, request.columns, jsonPage)

    return res
  }

  static executeQuerySync(pathQuerySync, match, jsonPage) {
    return Sql.execQuery(pathQuerySync, match, jsonPage)
  }

  static executeQuery(pathexecuteQuery, match, jsonPage) {
    var p = new Promise((resolve) => {
      var res = Sql.execQuery(pathexecuteQuery, match, jsonPage)
      resolve(res)
    }).catch(function(e) {
      console.error(e)
    })

    return p
  }

  /**
   * check if a given string an url, string json, file url, abe sql request
   *
   * Sql.get('http://google.com')
   * Sql.get('{"test":"test"}')
   * Sql.get('select * from ../')
   * Sql.get('test')
   *
   * @param  {String} str
   * @return {String} url | request | value | file | other
   */
  static getSourceType(str) {
    if(/http:\/\/|https:\/\//.test(str)) {
      return 'url'
    }

    if(/select[\S\s]*?from/.test(str)) {
      return 'request'
    }

    try {
      JSON.parse(str)
      return 'value'
    }catch(e) {

    }

    if(/\.json/.test(str)) {
      return 'file'
    }

    return 'other'
  }

  static executeWhereClause(files, wheres, maxLimit, columns, jsonPage){
    var res = []
    var limit = 0

    for(let file of files) {
      if(limit < maxLimit || maxLimit === -1) {
        if(typeof wheres !== 'undefined' && wheres !== null) {

          if(Sql.recurseWhere(wheres, file.publish, jsonPage)) {
            var json = JSON.parse(JSON.stringify(file.publish))
            var jsonValues = {}

            if(typeof columns !== 'undefined' && columns !== null && columns.length > 0 && columns[0] !== '*') {

              Array.prototype.forEach.call(columns, (column) => {
                if(typeof json[column] !== 'undefined' && json[column] !== null) {
                  jsonValues[column] = json[column]
                }
              })
              jsonValues['abe_meta'] = json['abe_meta']
            }else {
              jsonValues = json
            }

            res.push(jsonValues)
            limit++
          }
        }
      } else {
        break
      }
    }

    return res
  }

  static getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc) {
    var value
    var compare

    if((where.left.column === 'template' || where.left.column === 'abe_meta.template')
      && typeof jsonDoc['abe_meta'] !== 'undefined' && jsonDoc['abe_meta'] !== null) {
      value = FileParser.getTemplate(jsonDoc['abe_meta'].template)
    }else {
      try {
        value = eval('jsonDoc.' + where.left.column)
      }catch(e) {
        // console.log('e', e)
      }
    }
    compare = where.right.column

    var matchVariable = /^{{(.*)}}$/.exec(compare)
    if(typeof matchVariable !== 'undefined' && matchVariable !== null && matchVariable.length > 0) {
      try {
        var shouldCompare = eval('jsonOriginalDoc.' + matchVariable[1])
        if(typeof shouldCompare !== 'undefined' && shouldCompare !== null) {
          compare = shouldCompare
        }else {
          compare = null
        }
      }catch(e) {
        compare = null
        // console.log('e', e)
      }
    }

    return {
      left: value,
      right: compare
    }
  }

  static recurseWhere(where, jsonDoc, jsonOriginalDoc) {
    var shouldAdd = true
    var isLeftCorrect = false
    var isRightCorrect = false
    var isCorrect = false

    switch(where.operator) {
    case '=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left !== values.right) {
        isCorrect = true
      }
      break
    case '!=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left === values.right) {
        isCorrect = true
      }
      break
    case '>':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isCorrect = (values.left > values.right)
      break
    case '>=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isCorrect = (values.left >= values.right)
      break
    case '<':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isCorrect = (values.left < values.right)
      break
    case '<=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isCorrect = (values.left <= values.right)
      break
    case 'LIKE':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left && values.left.indexOf(values.right) === -1) {
        isCorrect = true
      }
      break
    case 'NOT LIKE':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left && values.left.indexOf(values.right) > -1) {
        isCorrect = true
      }
      break
    case 'AND':
      isLeftCorrect = Sql.recurseWhere(where.left, jsonDoc, jsonOriginalDoc)
      isRightCorrect = Sql.recurseWhere(where.right, jsonDoc, jsonOriginalDoc)
      isCorrect = !isLeftCorrect && !isRightCorrect
      break
    case 'OR':
      isLeftCorrect = Sql.recurseWhere(where.left, jsonDoc, jsonOriginalDoc)
      isRightCorrect = Sql.recurseWhere(where.right, jsonDoc, jsonOriginalDoc)
      isCorrect = !isLeftCorrect || !isRightCorrect
      break
    case 'IN':
      var valuesLeft = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      Array.prototype.forEach.call(where.right.value, (right) => {
        if(valuesLeft.left === right.column) {
          isCorrect = true
        }
      })
      break
    case 'NOT IN':
      var valuesLeft = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isCorrect = true
      Array.prototype.forEach.call(where.right.value, (right) => {
        if(valuesLeft.left === right.column) {
          isCorrect = false
        }
      })
      break
    }
    return isCorrect
  }
}<commit_msg>bug abe-sql<commit_after>import {parse} from 'node-sqlparser'
import {Promise} from 'es6-promise'
import path from 'path'
import {
  config,
  Manager,
  FileParser,
  getAttr
} from '../../'

export default class Sql {

  constructor() {

  }

  static cleanRequest(str, jsonPage) {
    var matchFrom = /from .(.*?) /
    var matchVariable = /{{([a-zA-Z]*)}}/

    var matchFromExec = matchFrom.exec(str)
    if(typeof matchFromExec !== 'undefined' && matchFromExec !== null
      && typeof matchFromExec[1] !== 'undefined' && matchFromExec[1] !== null) {

      var fromMatch
      var toReplace = matchFromExec[1]
      while (fromMatch = matchVariable.exec(toReplace)) {
        try {
          var value = eval('jsonPage.' + fromMatch[1])
          if(typeof value !== 'undefined' && value !== null) {
            toReplace = toReplace.replace('{{' + fromMatch[1] + '}}', value)
          }else {
            toReplace = toReplace.replace('{{' + fromMatch[1] + '}}', '')
          }
        }catch(e) {
        }
      }

      str = str.replace(matchFromExec[1], toReplace)
    }

    var from = /from ([\S\s]+)/.exec(str)

    var matches = from
    if(matches[1]) {
      var res = matches[1]
      var splitAttr = [' where ', ' order by ', ' limit ', ' WHERE ', ' ORDER BY ', ' LIMIT ']
      for(var i = 0; i < splitAttr.length; i++) {
        if(res.indexOf(splitAttr[i]) > -1) {
          res = res.substring(0, res.indexOf(splitAttr[i]))
        }
      }
      var escapedFrom = res.replace(/\//g, '___abe___')
      escapedFrom = escapedFrom.replace(/\./g, '___abe_dot___')
      escapedFrom = escapedFrom.replace(/-/g, '___abe_dash___')
      str = str.replace(res, escapedFrom)
    }

    str = str.replace(/``/g, '\'\'')

    return str
  }

  static handleSqlRequest(str, jsonPage) {
    var cleanRequest = Sql.cleanRequest(str, jsonPage)
    var request = parse(cleanRequest)
    var reconstructSql = ''

    // SQL TYPE
    var type = ''
    if(typeof request.type !== 'undefined' && request.type !== null) {
      type = request.type
    }
    reconstructSql += `${type} `

    // SQL COLUMNS
    var columns = []
    if(typeof request.columns !== 'undefined' && request.columns !== null) {
      if(request.columns === '*') {
        columns.push('*')
      }else {
        Array.prototype.forEach.call(request.columns, (item) => {
          columns.push(item.expr.column)
        })
      }
    }
    reconstructSql += `${JSON.stringify(columns)} `

    // SQL FROM
    var from = []
    if(typeof request.from !== 'undefined' && request.from !== null) {

      Array.prototype.forEach.call(request.from, (item) => {
        from.push(item.table)
      })
    }else {
      from.push('*')
    }
    reconstructSql += `from ${JSON.stringify(from)} `

    var where
    if(typeof request.where !== 'undefined' && request.where !== null) {
      where = request.where
      // where = Sql.recurseWhere(request.where)
      // reconstructSql += 'where '
      // Array.prototype.forEach.call(where, (w) => {
      //   reconstructSql += `${w.operator} ${w.left} ${w.compare} ${w.right} `
      // })
    }

    var limit = -1
    if(typeof request.limit !== 'undefined' && request.limit !== null) {
      limit = request.limit[request.limit.length - 1].value
    }

    var orderby
    if(typeof request.orderby !== 'undefined' && request.orderby !== null && request.orderby.length > 0) {
      orderby = {
        column: request.orderby[0].expr.column,
        type: request.orderby[0].type
      }
      reconstructSql += `ORDER BY ${orderby.column} ${orderby.type} `
    }

    return {
      type: type,
      columns: columns,
      from: from,
      where: where,
      string: reconstructSql,
      limit: limit,
      orderby: orderby
    }
  }

  static sortByDateDesc(a, b) {
    var dateA = new Date(a.date)
    var dateB = new Date(b.date)
    if(dateA < dateB) {
      return 1
    }else if(dateA > dateB) {
      return -1
    }
    return 0
  }

  static shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {

      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex)
      currentIndex -= 1

      // And swap it with the current element.
      temporaryValue = array[currentIndex]
      array[currentIndex] = array[randomIndex]
      array[randomIndex] = temporaryValue
    }

    return array
  }

  static sortByDateAsc(a, b) {
    var dateA = new Date(a.date)
    var dateB = new Date(b.date)
    if(dateA > dateB) {
      return 1
    }else if(dateA < dateB) {
      return -1
    }
    return 0
  }

  static getDataSource(str) {
    var res = str.substring(str.indexOf('source=') + 8, str.length)

    var reg = /([^'"]*=[\s\S]*?}})/g
    var matches = res.match(reg)
    if(typeof matches !== 'undefined' && matches !== null) {
      Array.prototype.forEach.call(matches, (match) => {
        res = res.replace(match, '')
      })
    }else {
      res = res.replace('}}', '')
    }

    return res.substring(0, res.length-1)
  }

  /**
   * replaces escaped characters with the right ones
   * @param  {String} statement the from clause
   * @return {String}           the from sanitized
   */
  static sanitizeFromStatement(statement){
    var from = ''

    if(typeof statement !== 'undefined' && statement !== null) {
      from = statement[0].replace(/___abe_dot___/g, '.')
      from = from.replace(/___abe___/g, '/')
      from = from.replace(/___abe_dash___/g, '-')
    }

    return from
  }

  /**
   * calculate the directory to analyze from the from clause
   * @param  {String} statement the from clause
   * @param  {String} tplPath   the path from the template originator
   * @return {string}           the directory to analyze
   */
  static getFromDirectory(statement, tplPath){
    var pathFromDir = ''
    if(typeof tplPath === 'undefined' || tplPath === null || tplPath === ''){
      tplPath = '/'
    }

    if(statement === '' || statement === '*' || statement === '/') {
      pathFromDir = path.join(config.root, config.data.url)
    }else if(statement === './') {
      pathFromDir = path.join(config.root, config.data.url, tplPath)
    }else if(statement.indexOf('/') === 0) {
      pathFromDir = path.join(config.root, config.data.url, statement)
    }else if(statement.indexOf('/') !== 0) {
      pathFromDir = path.join(config.root, config.data.url, tplPath, statement)
    }

    return pathFromDir
  }

  static executeOrderByClause(files, orderby){
    if(typeof orderby !== 'undefined' && orderby !== null) {
      if(orderby.column.toLowerCase() === 'random') {
        Sql.shuffle(files)
      }else if(orderby.column.toLowerCase() === 'date') {
        if(orderby.type === 'ASC') {
          files.sort(Sql.sortByDateAsc)
        }else if(orderby.type === 'DESC') {
          files.sort(Sql.sortByDateDesc)
        }
      }
    }

    return files
  }

  static executeFromClause(statement, pathFromClause){
    var from = Sql.sanitizeFromStatement(statement)

    // if the from clause ends with a dot, we won't recurse the directory analyze
    if(from.slice(-1) === '.'){
      from = from.slice(0, -1)
    }

    var fromDirectory = Sql.getFromDirectory(from, pathFromClause)

    var list = Manager.instance.getList()
    var files_array = list.filter((element, index) => {
      if(element.publish) {
        if (element.path.indexOf(fromDirectory) > -1) {
          return true
        }
      }
      return false
    })
    return files_array
  }

  static execQuery(pathQuery, match, jsonPage) {
    var res
    var files
    var request = Sql.handleSqlRequest(getAttr(match, 'source'), jsonPage)

    files = Sql.executeFromClause(request.from, pathQuery)
    files = Sql.executeOrderByClause(files, request.orderby)
    res = Sql.executeWhereClause(files, request.where, request.limit, request.columns, jsonPage)

    return res
  }

  static executeQuerySync(pathQuerySync, match, jsonPage) {
    return Sql.execQuery(pathQuerySync, match, jsonPage)
  }

  static executeQuery(pathexecuteQuery, match, jsonPage) {
    var p = new Promise((resolve) => {
      var res = Sql.execQuery(pathexecuteQuery, match, jsonPage)
      resolve(res)
    }).catch(function(e) {
      console.error(e)
    })

    return p
  }

  /**
   * check if a given string an url, string json, file url, abe sql request
   *
   * Sql.get('http://google.com')
   * Sql.get('{"test":"test"}')
   * Sql.get('select * from ../')
   * Sql.get('test')
   *
   * @param  {String} str
   * @return {String} url | request | value | file | other
   */
  static getSourceType(str) {
    if(/http:\/\/|https:\/\//.test(str)) {
      return 'url'
    }

    if(/select[\S\s]*?from/.test(str)) {
      return 'request'
    }

    try {
      JSON.parse(str)
      return 'value'
    }catch(e) {

    }

    if(/\.json/.test(str)) {
      return 'file'
    }

    return 'other'
  }

  static executeWhereClause(files, wheres, maxLimit, columns, jsonPage){
    var res = []
    var limit = 0

    for(let file of files) {
      if(limit < maxLimit || maxLimit === -1) {
        if(typeof wheres !== 'undefined' && wheres !== null) {

          if(Sql.recurseWhere(wheres, file.publish, jsonPage)) {
            var json = JSON.parse(JSON.stringify(file.publish))
            var jsonValues = {}

            if(typeof columns !== 'undefined' && columns !== null && columns.length > 0 && columns[0] !== '*') {

              Array.prototype.forEach.call(columns, (column) => {
                if(typeof json[column] !== 'undefined' && json[column] !== null) {
                  jsonValues[column] = json[column]
                }
              })
              jsonValues['abe_meta'] = json['abe_meta']
            }else {
              jsonValues = json
            }

            res.push(jsonValues)
            limit++
          }
        }
      } else {
        break
      }
    }

    return res
  }

  static getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc) {
    var value
    var compare

    if((where.left.column === 'template' || where.left.column === 'abe_meta.template')
      && typeof jsonDoc['abe_meta'] !== 'undefined' && jsonDoc['abe_meta'] !== null) {
      value = FileParser.getTemplate(jsonDoc['abe_meta'].template)
    }else {
      try {
        value = eval('jsonDoc.' + where.left.column)
      }catch(e) {
        // console.log('e', e)
      }
    }
    compare = where.right.column

    var matchVariable = /^{{(.*)}}$/.exec(compare)
    if(typeof matchVariable !== 'undefined' && matchVariable !== null && matchVariable.length > 0) {
      try {
        var shouldCompare = eval('jsonOriginalDoc.' + matchVariable[1])
        if(typeof shouldCompare !== 'undefined' && shouldCompare !== null) {
          compare = shouldCompare
        }else {
          compare = null
        }
      }catch(e) {
        compare = null
        // console.log('e', e)
      }
    }

    return {
      left: value,
      right: compare
    }
  }

  static recurseWhere(where, jsonDoc, jsonOriginalDoc) {
    var shouldAdd = true
    var isNotLeftCorrect = false
    var isNotRightCorrect = false
    var isNotCorrect = false

    switch(where.operator) {
    case '=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left !== values.right) {
        isNotCorrect = true
      }
      break
    case '!=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left === values.right) {
        isNotCorrect = true
      }
      break
    case '>':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isNotCorrect = (values.left > values.right)
      break
    case '>=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isNotCorrect = (values.left >= values.right)
      break
    case '<':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isNotCorrect = (values.left < values.right)
      break
    case '<=':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isNotCorrect = (values.left <= values.right)
      break
    case 'LIKE':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left && values.left.indexOf(values.right) === -1) {
        isNotCorrect = true
      }
      break
    case 'NOT LIKE':
      var values = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      if(values.left && values.left.indexOf(values.right) > -1) {
        isNotCorrect = true
      }
      break
    case 'AND':
      isNotLeftCorrect = Sql.recurseWhere(where.left, jsonDoc, jsonOriginalDoc)
      isNotRightCorrect = Sql.recurseWhere(where.right, jsonDoc, jsonOriginalDoc)
      isNotCorrect = isNotLeftCorrect && isNotRightCorrect
      break
    case 'OR':
      isNotLeftCorrect = Sql.recurseWhere(where.left, jsonDoc, jsonOriginalDoc)
      isNotRightCorrect = Sql.recurseWhere(where.right, jsonDoc, jsonOriginalDoc)
      isNotCorrect = isNotLeftCorrect || isNotRightCorrect
      break
    case 'IN':
      var valuesLeft = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      Array.prototype.forEach.call(where.right.value, (right) => {
        if(valuesLeft.left === right.column) {
          isNotCorrect = true
        }
      })
      break
    case 'NOT IN':
      var valuesLeft = Sql.getWhereValuesToCompare(where, jsonDoc, jsonOriginalDoc)
      isNotCorrect = true
      Array.prototype.forEach.call(where.right.value, (right) => {
        if(valuesLeft.left === right.column) {
          isNotCorrect = false
        }
      })
      break
    }
    return isNotCorrect
  }
}<|endoftext|>


<commit_before>/* global attachEvent */

const XMLHttpRequest = require("xmlhttprequest-ssl");
const Polling = require("./polling");
const Emitter = require("component-emitter");
const { pick } = require("../util");
const globalThis = require("../globalThis");

const debug = require("debug")("engine.io-client:polling-xhr");

/**
 * Empty function
 */

function empty() {}

const hasXHR2 = (function() {
  const XMLHttpRequest = require("xmlhttprequest-ssl");
  const xhr = new XMLHttpRequest({ xdomain: false });
  return null != xhr.responseType;
})();

class XHR extends Polling {
  /**
   * XHR Polling constructor.
   *
   * @param {Object} opts
   * @api public
   */
  constructor(opts) {
    super(opts);

    if (typeof location !== "undefined") {
      const isSSL = "https:" === location.protocol;
      let port = location.port;

      // some user agents have empty `location.port`
      if (!port) {
        port = isSSL ? 443 : 80;
      }

      this.xd =
        (typeof location !== "undefined" &&
          opts.hostname !== location.hostname) ||
        port !== opts.port;
      this.xs = opts.secure !== isSSL;
    }
    /**
     * XHR supports binary
     */
    const forceBase64 = opts && opts.forceBase64;
    this.supportsBinary = hasXHR2 && !forceBase64;
  }

  /**
   * Creates a request.
   *
   * @param {String} method
   * @api private
   */
  request(opts = {}) {
    Object.assign(
      opts,
      { supportsBinary: this.supportsBinary, xd: this.xd, xs: this.xs },
      this.opts
    );
    return new Request(this.uri(), opts);
  }

  /**
   * Sends data.
   *
   * @param {String} data to send.
   * @param {Function} called upon flush.
   * @api private
   */
  doWrite(data, fn) {
    const isBinary = typeof data !== "string" && data !== undefined;
    const req = this.request({
      method: "POST",
      data: data,
      isBinary: isBinary
    });
    const self = this;
    req.on("success", fn);
    req.on("error", function(err) {
      self.onError("xhr post error", err);
    });
  }

  /**
   * Starts a poll cycle.
   *
   * @api private
   */
  doPoll() {
    debug("xhr poll");
    const req = this.request();
    const self = this;
    req.on("data", function(data) {
      self.onData(data);
    });
    req.on("error", function(err) {
      self.onError("xhr poll error", err);
    });
    this.pollXhr = req;
  }
}

class Request extends Emitter {
  /**
   * Request constructor
   *
   * @param {Object} options
   * @api public
   */
  constructor(uri, opts) {
    super();
    this.opts = opts;

    this.method = opts.method || "GET";
    this.uri = uri;
    this.async = false !== opts.async;
    this.data = undefined !== opts.data ? opts.data : null;
    this.isBinary = opts.isBinary;
    this.supportsBinary = opts.supportsBinary;

    this.create();
  }

  /**
   * Creates the XHR object and sends the request.
   *
   * @api private
   */
  create() {
    const opts = pick(
      this.opts,
      "agent",
      "enablesXDR",
      "pfx",
      "key",
      "passphrase",
      "cert",
      "ca",
      "ciphers",
      "rejectUnauthorized"
    );
    opts.xdomain = !!this.opts.xd;
    opts.xscheme = !!this.opts.xs;

    const xhr = (this.xhr = new XMLHttpRequest(opts));
    const self = this;

    try {
      debug("xhr open %s: %s", this.method, this.uri);
      xhr.open(this.method, this.uri, this.async);
      try {
        if (this.opts.extraHeaders) {
          xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);
          for (let i in this.opts.extraHeaders) {
            if (this.opts.extraHeaders.hasOwnProperty(i)) {
              xhr.setRequestHeader(i, this.opts.extraHeaders[i]);
            }
          }
        }
      } catch (e) {
        console.log(e);
      }

      if ("POST" === this.method) {
        try {
          if (this.isBinary) {
            xhr.setRequestHeader("Content-type", "application/octet-stream");
          } else {
            xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
          }
        } catch (e) {}
      }

      try {
        xhr.setRequestHeader("Accept", "*/*");
      } catch (e) {}

      // ie6 check
      if ("withCredentials" in xhr) {
        xhr.withCredentials = this.opts.withCredentials;
      }

      if (this.opts.requestTimeout) {
        xhr.timeout = this.opts.requestTimeout;
      }

      if (this.hasXDR()) {
        xhr.onload = function() {
          self.onLoad();
        };
        xhr.onerror = function() {
          self.onError(xhr.responseText);
        };
      } else {
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {
            try {
              const contentType = xhr.getResponseHeader("Content-Type");
              if (
                (self.supportsBinary &&
                  contentType === "application/octet-stream") ||
                contentType === "application/octet-stream; charset=UTF-8"
              ) {
                xhr.responseType = "arraybuffer";
              }
            } catch (e) {}
          }
          if (4 !== xhr.readyState) return;
          if (200 === xhr.status || 1223 === xhr.status) {
            self.onLoad();
          } else {
            // make sure the `error` event handler that's user-set
            // does not throw in the same tick and gets caught here
            setTimeout(function() {
              self.onError(typeof xhr.status === "number" ? xhr.status : 0);
            }, 0);
          }
        };
      }

      debug("xhr data %s", this.data);
      xhr.send(this.data);
    } catch (e) {
      // Need to defer since .create() is called directly from the constructor
      // and thus the 'error' event can only be only bound *after* this exception
      // occurs.  Therefore, also, we cannot throw here at all.
      setTimeout(function() {
        self.onError(e);
      }, 0);
      return;
    }

    if (typeof document !== "undefined") {
      this.index = Request.requestsCount++;
      Request.requests[this.index] = this;
    }
  }

  /**
   * Called upon successful response.
   *
   * @api private
   */
  onSuccess() {
    this.emit("success");
    this.cleanup();
  }

  /**
   * Called if we have data.
   *
   * @api private
   */
  onData(data) {
    this.emit("data", data);
    this.onSuccess();
  }

  /**
   * Called upon error.
   *
   * @api private
   */
  onError(err) {
    this.emit("error", err);
    this.cleanup(true);
  }

  /**
   * Cleans up house.
   *
   * @api private
   */
  cleanup(fromError) {
    if ("undefined" === typeof this.xhr || null === this.xhr) {
      return;
    }
    // xmlhttprequest
    if (this.hasXDR()) {
      this.xhr.onload = this.xhr.onerror = empty;
    } else {
      this.xhr.onreadystatechange = empty;
    }

    if (fromError) {
      try {
        this.xhr.abort();
      } catch (e) {}
    }

    if (typeof document !== "undefined") {
      delete Request.requests[this.index];
    }

    this.xhr = null;
  }

  /**
   * Called upon load.
   *
   * @api private
   */
  onLoad() {
    let data;
    try {
      let contentType;
      try {
        contentType = this.xhr.getResponseHeader("Content-Type");
      } catch (e) {}
      if (
        contentType === "application/octet-stream" ||
        contentType === "application/octet-stream; charset=UTF-8"
      ) {
        data = this.xhr.response || this.xhr.responseText;
      } else {
        data = this.xhr.responseText;
      }
    } catch (e) {
      this.onError(e);
    }
    if (null != data) {
      this.onData(data);
    }
  }

  /**
   * Check if it has XDomainRequest.
   *
   * @api private
   */
  hasXDR() {
    return typeof XDomainRequest !== "undefined" && !this.xs && this.enablesXDR;
  }

  /**
   * Aborts the request.
   *
   * @api public
   */
  abort() {
    this.cleanup();
  }
}

/**
 * Aborts pending requests when unloading the window. This is needed to prevent
 * memory leaks (e.g. when using IE) and to ensure that no spurious error is
 * emitted.
 */

Request.requestsCount = 0;
Request.requests = {};

if (typeof document !== "undefined") {
  if (typeof attachEvent === "function") {
    attachEvent("onunload", unloadHandler);
  } else if (typeof addEventListener === "function") {
    const terminationEvent = "onpagehide" in globalThis ? "pagehide" : "unload";
    addEventListener(terminationEvent, unloadHandler, false);
  }
}

function unloadHandler() {
  for (let i in Request.requests) {
    if (Request.requests.hasOwnProperty(i)) {
      Request.requests[i].abort();
    }
  }
}

module.exports = XHR;
module.exports.Request = Request;
<commit_msg>refactor: remove binary handling for the polling transport<commit_after>/* global attachEvent */

const XMLHttpRequest = require("xmlhttprequest-ssl");
const Polling = require("./polling");
const Emitter = require("component-emitter");
const { pick } = require("../util");
const globalThis = require("../globalThis");

const debug = require("debug")("engine.io-client:polling-xhr");

/**
 * Empty function
 */

function empty() {}

const hasXHR2 = (function() {
  const XMLHttpRequest = require("xmlhttprequest-ssl");
  const xhr = new XMLHttpRequest({ xdomain: false });
  return null != xhr.responseType;
})();

class XHR extends Polling {
  /**
   * XHR Polling constructor.
   *
   * @param {Object} opts
   * @api public
   */
  constructor(opts) {
    super(opts);

    if (typeof location !== "undefined") {
      const isSSL = "https:" === location.protocol;
      let port = location.port;

      // some user agents have empty `location.port`
      if (!port) {
        port = isSSL ? 443 : 80;
      }

      this.xd =
        (typeof location !== "undefined" &&
          opts.hostname !== location.hostname) ||
        port !== opts.port;
      this.xs = opts.secure !== isSSL;
    }
    /**
     * XHR supports binary
     */
    const forceBase64 = opts && opts.forceBase64;
    this.supportsBinary = hasXHR2 && !forceBase64;
  }

  /**
   * Creates a request.
   *
   * @param {String} method
   * @api private
   */
  request(opts = {}) {
    Object.assign(
      opts,
      { supportsBinary: this.supportsBinary, xd: this.xd, xs: this.xs },
      this.opts
    );
    return new Request(this.uri(), opts);
  }

  /**
   * Sends data.
   *
   * @param {String} data to send.
   * @param {Function} called upon flush.
   * @api private
   */
  doWrite(data, fn) {
    const isBinary = typeof data !== "string" && data !== undefined;
    const req = this.request({
      method: "POST",
      data: data,
      isBinary: isBinary
    });
    const self = this;
    req.on("success", fn);
    req.on("error", function(err) {
      self.onError("xhr post error", err);
    });
  }

  /**
   * Starts a poll cycle.
   *
   * @api private
   */
  doPoll() {
    debug("xhr poll");
    const req = this.request();
    const self = this;
    req.on("data", function(data) {
      self.onData(data);
    });
    req.on("error", function(err) {
      self.onError("xhr poll error", err);
    });
    this.pollXhr = req;
  }
}

class Request extends Emitter {
  /**
   * Request constructor
   *
   * @param {Object} options
   * @api public
   */
  constructor(uri, opts) {
    super();
    this.opts = opts;

    this.method = opts.method || "GET";
    this.uri = uri;
    this.async = false !== opts.async;
    this.data = undefined !== opts.data ? opts.data : null;
    this.isBinary = opts.isBinary;
    this.supportsBinary = opts.supportsBinary;

    this.create();
  }

  /**
   * Creates the XHR object and sends the request.
   *
   * @api private
   */
  create() {
    const opts = pick(
      this.opts,
      "agent",
      "enablesXDR",
      "pfx",
      "key",
      "passphrase",
      "cert",
      "ca",
      "ciphers",
      "rejectUnauthorized"
    );
    opts.xdomain = !!this.opts.xd;
    opts.xscheme = !!this.opts.xs;

    const xhr = (this.xhr = new XMLHttpRequest(opts));
    const self = this;

    try {
      debug("xhr open %s: %s", this.method, this.uri);
      xhr.open(this.method, this.uri, this.async);
      try {
        if (this.opts.extraHeaders) {
          xhr.setDisableHeaderCheck && xhr.setDisableHeaderCheck(true);
          for (let i in this.opts.extraHeaders) {
            if (this.opts.extraHeaders.hasOwnProperty(i)) {
              xhr.setRequestHeader(i, this.opts.extraHeaders[i]);
            }
          }
        }
      } catch (e) {
        console.log(e);
      }

      if ("POST" === this.method) {
        try {
          if (this.isBinary) {
            xhr.setRequestHeader("Content-type", "application/octet-stream");
          } else {
            xhr.setRequestHeader("Content-type", "text/plain;charset=UTF-8");
          }
        } catch (e) {}
      }

      try {
        xhr.setRequestHeader("Accept", "*/*");
      } catch (e) {}

      // ie6 check
      if ("withCredentials" in xhr) {
        xhr.withCredentials = this.opts.withCredentials;
      }

      if (this.opts.requestTimeout) {
        xhr.timeout = this.opts.requestTimeout;
      }

      if (this.hasXDR()) {
        xhr.onload = function() {
          self.onLoad();
        };
        xhr.onerror = function() {
          self.onError(xhr.responseText);
        };
      } else {
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {
            try {
              const contentType = xhr.getResponseHeader("Content-Type");
              if (
                (self.supportsBinary &&
                  contentType === "application/octet-stream") ||
                contentType === "application/octet-stream; charset=UTF-8"
              ) {
                xhr.responseType = "arraybuffer";
              }
            } catch (e) {}
          }
          if (4 !== xhr.readyState) return;
          if (200 === xhr.status || 1223 === xhr.status) {
            self.onLoad();
          } else {
            // make sure the `error` event handler that's user-set
            // does not throw in the same tick and gets caught here
            setTimeout(function() {
              self.onError(typeof xhr.status === "number" ? xhr.status : 0);
            }, 0);
          }
        };
      }

      debug("xhr data %s", this.data);
      xhr.send(this.data);
    } catch (e) {
      // Need to defer since .create() is called directly from the constructor
      // and thus the 'error' event can only be only bound *after* this exception
      // occurs.  Therefore, also, we cannot throw here at all.
      setTimeout(function() {
        self.onError(e);
      }, 0);
      return;
    }

    if (typeof document !== "undefined") {
      this.index = Request.requestsCount++;
      Request.requests[this.index] = this;
    }
  }

  /**
   * Called upon successful response.
   *
   * @api private
   */
  onSuccess() {
    this.emit("success");
    this.cleanup();
  }

  /**
   * Called if we have data.
   *
   * @api private
   */
  onData(data) {
    this.emit("data", data);
    this.onSuccess();
  }

  /**
   * Called upon error.
   *
   * @api private
   */
  onError(err) {
    this.emit("error", err);
    this.cleanup(true);
  }

  /**
   * Cleans up house.
   *
   * @api private
   */
  cleanup(fromError) {
    if ("undefined" === typeof this.xhr || null === this.xhr) {
      return;
    }
    // xmlhttprequest
    if (this.hasXDR()) {
      this.xhr.onload = this.xhr.onerror = empty;
    } else {
      this.xhr.onreadystatechange = empty;
    }

    if (fromError) {
      try {
        this.xhr.abort();
      } catch (e) {}
    }

    if (typeof document !== "undefined") {
      delete Request.requests[this.index];
    }

    this.xhr = null;
  }

  /**
   * Called upon load.
   *
   * @api private
   */
  onLoad() {
    const data = this.xhr.responseText;
    if (data !== null) {
      this.onData(data);
    }
  }

  /**
   * Check if it has XDomainRequest.
   *
   * @api private
   */
  hasXDR() {
    return typeof XDomainRequest !== "undefined" && !this.xs && this.enablesXDR;
  }

  /**
   * Aborts the request.
   *
   * @api public
   */
  abort() {
    this.cleanup();
  }
}

/**
 * Aborts pending requests when unloading the window. This is needed to prevent
 * memory leaks (e.g. when using IE) and to ensure that no spurious error is
 * emitted.
 */

Request.requestsCount = 0;
Request.requests = {};

if (typeof document !== "undefined") {
  if (typeof attachEvent === "function") {
    attachEvent("onunload", unloadHandler);
  } else if (typeof addEventListener === "function") {
    const terminationEvent = "onpagehide" in globalThis ? "pagehide" : "unload";
    addEventListener(terminationEvent, unloadHandler, false);
  }
}

function unloadHandler() {
  for (let i in Request.requests) {
    if (Request.requests.hasOwnProperty(i)) {
      Request.requests[i].abort();
    }
  }
}

module.exports = XHR;
module.exports.Request = Request;
<|endoftext|>


<commit_before>import React from 'react';
import './Header.scss';

export const Header = () => (

    Tiedonohjausjärjestelmä Alpha v0.1.3

);

export default Header;
<commit_msg>Bump version number<commit_after>import React from 'react';
import './Header.scss';

export const Header = () => (

    Tiedonohjausjärjestelmä Alpha v0.1.4

);

export default Header;
<|endoftext|>


<commit_before>// @flow

import capsidDebugMessage from '../debug-plugin'
import td from 'testdouble'

describe('debug-plugin', () => {
  afterEach(() => {
    td.reset()
  })

  describe('with event type message', () => {
    it('logs event and component names', () => {
      const e = { type: 'click' }
      const coelem = { constructor: { name: 'foo' } }

      td.replace(console, 'groupCollapsed')
      td.replace(console, 'log')
      td.replace(console, 'groupEnd')

      capsidDebugMessage({ type: 'event', e, coelem, module: 'module' })

      td.verify(console.groupCollapsed('[module] %cclick %con %cfoo', 'color: #f012be; font-weight: bold;', '', 'color: #2ecc40; font-weight: bold;'))
      td.verify(console.log(e))
      td.verify(console.groupEnd())
    })
  })

  describe('with unknown typee message', () => {
    it('logs error message', () => {
      td.replace(console, 'log')

      capsidDebugMessage({ type: 'unknown' })

      td.verify(console.log(`Unknown message: ${JSON.stringify({ type: 'unknown' })}`))
    })
  })
})
<commit_msg>test(debug-plugin): fix test cases<commit_after>// @flow

import capsidDebugMessage from '../debug-plugin'
import td from 'testdouble'

describe('debug-plugin', () => {
  afterEach(() => {
    td.reset()
  })

  describe('with event type message', () => {
    it('logs event and component names', () => {
      const e = { type: 'click' }
      const coelem = { constructor: { name: 'foo' } }

      td.replace(console, 'groupCollapsed')
      td.replace(console, 'log')
      td.replace(console, 'groupEnd')

      capsidDebugMessage({ type: 'event', e, coelem, module: 'module' })

      td.verify(console.groupCollapsed('module> %cclick%c on %cfoo', 'color: #f012be; font-weight: bold;', '', 'color: #1a80cc; font-weight: bold;'))
      td.verify(console.log(e))
      td.verify(console.groupEnd())
    })
  })

  describe('with unknown typee message', () => {
    it('logs error message', () => {
      td.replace(console, 'log')

      capsidDebugMessage({ type: 'unknown' })

      td.verify(console.log(`Unknown message: ${JSON.stringify({ type: 'unknown' })}`))
    })
  })
})
<|endoftext|>